All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shapeless.ops.nat.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-16 Miles Sabin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package shapeless
package ops

import scala.annotation.tailrec
import scala.reflect.macros.whitebox
import scala.language.experimental.macros

object nat {

  /**
   * Type class witnessing that `B` is the predecessor of `A`.
   * 
   * @author Miles Sabin
   */
  trait Pred[A <: Nat] extends Serializable { type Out <: Nat }

  object Pred {
    def apply[A <: Nat](implicit pred: Pred[A]): Aux[A, pred.Out] = pred

    type Aux[A <: Nat, B <: Nat] = Pred[A] { type Out = B }

    implicit def pred[B <: Nat]: Aux[Succ[B], B] = new Pred[Succ[B]] { type Out = B }
  }

  /**
   * Type class witnessing that `C` is the sum of `A` and `B`.
   * 
   * @author Miles Sabin
   */
  trait Sum[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Sum {
    def apply[A <: Nat, B <: Nat](implicit sum: Sum[A, B]): Aux[A, B, sum.Out] = sum

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Sum[A, B] { type Out = C }

    implicit def sum1[B <: Nat]: Aux[_0, B, B] = new Sum[_0, B] { type Out = B }
    implicit def sum2[A <: Nat, B <: Nat, C <: Nat]
      (implicit sum : Sum.Aux[A, Succ[B], C]): Aux[Succ[A], B, C] = new Sum[Succ[A], B] { type Out = C }
  }

  /**
   * Type class witnessing that `C` is the difference of `A` and `B`.
   * 
   * @author Miles Sabin
   */
  trait Diff[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Diff {
    def apply[A <: Nat, B <: Nat](implicit diff: Diff[A, B]): Aux[A, B, diff.Out] = diff

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Diff[A, B] { type Out = C }

    implicit def diff1[A <: Nat]: Aux[A, _0, A] = new Diff[A, _0] { type Out = A }
    implicit def diff2[A <: Nat, B <: Nat, C <: Nat]
      (implicit diff : Diff.Aux[A, B, C]): Aux[Succ[A], Succ[B], C] = new Diff[Succ[A], Succ[B]] { type Out = C }
  }

  /**
   * Type class witnessing that `C` is the product of `A` and `B`.
   * 
   * @author Miles Sabin
   */
  trait Prod[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Prod {
    def apply[A <: Nat, B <: Nat](implicit prod: Prod[A, B]): Aux[A, B, prod.Out] = prod

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Prod[A, B] { type Out = C }

    implicit def prod1[B <: Nat]: Aux[_0, B, _0] = new Prod[_0, B] { type Out = _0 }
    implicit def prod2[A <: Nat, B <: Nat, C <: Nat, D <: Nat]
      (implicit prod: Prod.Aux[A, B, C], sum: Sum.Aux[B, C, D]): Aux[Succ[A], B, D] = new Prod[Succ[A], B] { type Out = D }
  }

  /**
   * Type class witnessing that `Out` is the quotient of `A` and `B`.
   *
   * @author Tom Switzer
   */
  trait Div[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Div {
    def apply[A <: Nat, B <: Nat](implicit div: Div[A, B]): Aux[A, B, div.Out] = div

    import LT._

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Div[A, B] { type Out = C }

    implicit def div1[A <: Nat]: Aux[_0, A, _0] = new Div[_0, A] { type Out = _0 }

    implicit def div2[A <: Nat, B <: Nat](implicit lt: A < B): Aux[A, B, _0] =
      new Div[A, B] { type Out = _0 }

    implicit def div3[A <: Nat, B <: Nat, C <: Nat, D <: Nat]
      (implicit diff: Diff.Aux[Succ[A], B, C], div: Div.Aux[C, B, D]): Aux[Succ[A], B, Succ[D]] =
        new Div[Succ[A], B] { type Out = Succ[D] }
  }

  /**
   * Typeclass witnessing that `Out` is `A` mod `B`.
   *
   * @author Tom Switzer
   */
  trait Mod[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Mod {
    def apply[A <: Nat, B <: Nat](implicit mod: Mod[A, B]): Aux[A, B, mod.Out] = mod

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Mod[A, B] { type Out = C }

    implicit def modAux[A <: Nat, B <: Nat, C <: Nat, D <: Nat, E <: Nat]
      (implicit div: Div.Aux[A, B, C], prod: Prod.Aux[C, B, D], diff: Diff.Aux[A, D, E]): Aux[A, B, E] =
        new Mod[A, B] { type Out = E }
  }

  /**
   * Type class witnessing that `A` is less than `B`.
   * 
   * @author Miles Sabin
   */
  trait LT[A <: Nat, B <: Nat] extends Serializable

  object LT extends LT0 {
    def apply[A <: Nat, B <: Nat](implicit lt: A < B): LT[A, B] = lt

    implicit def lt1[B <: Nat] = new <[_0, Succ[B]] {}
    implicit def lt2[A <: Nat, B <: Nat](implicit lt : A < B) = new <[Succ[A], Succ[B]] {}
  }

  trait LT0 {
    type <[A <: Nat, B <: Nat] = LT[A, B]

    implicit def lt3[A <: Nat] = new <[A, Succ[A]] {}
  }

  /**
   * Type class witnessing that `A` is less than or equal to `B`.
   * 
   * @author Miles Sabin
   */
  trait LTEq[A <: Nat, B <: Nat] extends Serializable

  object LTEq extends LTEq0 {
    def apply[A <: Nat, B <: Nat](implicit lteq: A <= B): LTEq[A, B] = lteq

    implicit def ltEq1[A <: Nat] = new <=[A, A] {}
    implicit def ltEq2[A <: Nat] = new <=[A, Succ[A]] {}
  }

  trait LTEq0 {
    type <=[A <: Nat, B <: Nat] = LTEq[A, B]

    implicit def ltEq3[B <: Nat] = new <=[_0, B] {}
    implicit def ltEq4[A <: Nat, B <: Nat](implicit lteq : A <= B) = new <=[Succ[A], Succ[B]] {}
  }

  /**
   * Type class witnessing that `A` is greater than `B`.
   *
   * @author ryoppy
   */
  type GT[A <: Nat, B <: Nat] = LT[B, A]
  object GT {
    def apply[A <: Nat, B <: Nat](implicit gt: GT[A, B]): GT[A, B] = gt
    type >[A <: Nat, B <: Nat] = GT[A, B]
  }

  /**
   * Type class witnessing that `A` is greater than or equal to `B`.
   *
   * @author ryoppy
   */
  type GTEq[A <: Nat, B <: Nat] = LTEq[B, A]
  object GTEq {
    def apply[A <: Nat, B <: Nat](implicit gteq: GTEq[A, B]): GTEq[A, B] = gteq
    type >=[A <: Nat, B <: Nat] = GTEq[A, B]
  }

  /**
   * Type class witnessing that `Out` is `A` min `B`.
   *
   * @author George Leontiev
   */
  trait Min[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Min {
    def apply[A <: Nat, B <: Nat](implicit min: Min[A, B]): Aux[A, B, min.Out] = min

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Min[A, B] { type Out = C }

    implicit def minAux0[A <: Nat, B <: Nat, C <: Nat]
      (implicit lteq: LTEq[A, B]): Aux[A, B, A] = new Min[A, B] { type Out = A }
    implicit def minAux1[A <: Nat, B <: Nat, C <: Nat]
      (implicit lteq: LT[B, A]): Aux[A, B, B] = new Min[A, B] { type Out = B }
  }

  /**
   * Type class witnessing that `Out` is `A` max `B`.
   *
   * @author Alexander Konovalov
   */
  trait Max[A <: Nat, B <: Nat] extends Serializable { type Out <: Nat }

  object Max {
    def apply[A <: Nat, B <: Nat](implicit max: Max[A, B]): Aux[A, B, max.Out] = max

    type Aux[A <: Nat, B <: Nat, C <: Nat] = Max[A, B] { type Out = C }

    implicit def maxAux0[A <: Nat, B <: Nat, C <: Nat]
      (implicit lteq: LTEq[A, B]): Aux[A, B, B] = new Max[A, B] { type Out = B }
    implicit def maxAux1[A <: Nat, B <: Nat, C <: Nat]
      (implicit lteq: LT[B, A]): Aux[A, B, A] = new Max[A, B] { type Out = A }
  }

  /**
   * Type class witnessing that `Out` is `X` raised to the power `N`.
   *
   * @author George Leontiev
   */
  trait Pow[N <: Nat, X <: Nat] extends Serializable { type Out <: Nat }

  object Pow {
    def apply[A <: Nat, B <: Nat](implicit pow: Pow[A, B]): Aux[A, B, pow.Out] = pow

    import shapeless.nat._1

    type Aux[N <: Nat, X <: Nat, Z <: Nat] = Pow[N, X] { type Out = Z }

    implicit def pow1[A <: Nat]: Aux[Succ[A], _0, _0] = new Pow[Succ[A], _0] { type Out = _0 }
    implicit def pow2[A <: Nat]: Aux[_0, Succ[A], _1] = new Pow[_0, Succ[A]] { type Out = _1 }
    implicit def pow3[N <: Nat, X <: Nat, Z <: Nat, Y <: Nat]
      (implicit ev : Pow.Aux[N, X, Z], ev2 : Prod.Aux[Z, X, Y]): Aux[Succ[N], X, Y] = new Pow[Succ[N], X] { type Out = Y }
  }

  /**
   * Type class witnessing that `Out` is range `A` to `B`, inclusive of `A` and exclusive of `B`.
   *
   * @author Andreas Koestler
   */
  trait Range[A <: Nat, B <: Nat] extends DepFn0 with Serializable {
    type Out <: HList
  }

  object Range {
    def apply[A <: Nat, B <: Nat](implicit range: Range[A, B]): Aux[A, B, range.Out] = range

    type Aux[A <: Nat, B <: Nat, Out0 <: HList] = Range[A, B] {type Out = Out0}


    import shapeless.ops.hlist._

    implicit def range1[A <: Nat]: Aux[A, A, HNil] = new Range[A, A] {
      type Out = HNil

      def apply(): Out = HNil
    }

    implicit def range2[A <: Nat, B <: Nat, L <: HList, LO <: HList](implicit
                                                                     w: Witness.Aux[B],
                                                                     r: Range.Aux[A, B, L],
                                                                     prep: Prepend.Aux[L, B :: HNil, LO]
                                                                      ): Aux[A, Succ[B], LO] =
      new Range[A, Succ[B]] {
        type Out = LO

        def apply(): Out = r() :+ w.value
      }
  }

  /**
   * Type class implementing Euclidean algorithm for calculating the GCD
   *
   * @author Andreas Koestler
   */
  trait LowPriorityGCD {
    implicit def defaultCase[A <: Nat, B <: Nat, T <: Nat](implicit
                                                           mod: Mod.Aux[A, B, T],
                                                           gcd: GCD[B, T]): GCD.Aux[A, B, gcd.Out] = new GCD[A, B] {
      type Out = gcd.Out
    }
  }
  trait GCD[A <: Nat, B <: Nat] extends Serializable {
    type Out <: Nat
  }

  object GCD extends LowPriorityGCD {
    def apply[A <: Nat, B <: Nat](implicit gcd: GCD[A, B]): Aux[A, B, gcd.Out] = gcd

    type Aux[A <: Nat, B <: Nat, Out0 <: Nat] = GCD[A, B] {type Out = Out0}

    implicit def terminationCase[A <: Nat]: Aux[A, _0, A] = new GCD[A, _0] {
      type Out = A
    }
  }

  /**
   * Type class for calculating the Least Common Multiple
   *
   * @author Andreas Koestler
   */
  trait LCM[A <: Nat, B <: Nat] extends Serializable {
    type Out <: Nat
  }

  object LCM {
    def apply[A <: Nat, B <: Nat](implicit lcm: LCM[A, B]): Aux[A, B, lcm.Out] = lcm

    type Aux[A <: Nat, B <: Nat, Out0 <: Nat] = LCM[A, B] {type Out = Out0}

    implicit def lcm[A <: Nat, B <: Nat, M <: Nat, N <: Nat, Res <: Nat]
    (implicit
     prod: Prod.Aux[A, B, M],
     gcd: GCD.Aux[A, B, N],
     div: Div[M, N]
      ): Aux[A, B, div.Out] = new LCM[A, B] {
      type Out = div.Out
    }
  }

  /**
    * Type class witnessing that `Out` is an HList of `Nat` numbers ranging from
    * `A` to `B`.
    *
    * This differs from the `Range` type class in that it accepts another
    * type class, `Bound`, at both the start and end of the range (instead of
    * bare `Nat` types). This allows the flexibility to specify inclusive or
    * exclusive range boundaries for either end of the range.
    *
    * Reversed ranges are also possible (i.e. starting the range with a larger
    * number than it ends with), and results in an HList that counts from the
    * beginning of the range _down to_ the end of the range.
    *
    * @author Jeff Wilde
    */
  trait BoundedRange[A <: BoundedRange.Bound, B <: BoundedRange.Bound] extends DepFn0 with Serializable {
    type Out <: HList
  }

  object BoundedRange {

    def apply[A <: BoundedRange.Bound, B <: BoundedRange.Bound](implicit range: BoundedRange[A,B])
    : AuxF[A, B, range.Out]  = range

    trait Bound extends DepFn0 with Serializable {
      type Out <: Nat
    }

    /**
      * Type class witnessing that the `Nat` `A` is the inclusive bound of
      * a range, i.e. the beginning or end of a range that includes `A`.
      *
      * @author Jeff Wilde
      */
    trait Inclusive[A] extends Bound

    trait SoftInclusive[A] extends Bound

    /**
      * Type class witnessing that the `Nat` `A` is the exclusive bound of
      * a range, i.e. the beginning or end of a range that does not include `A`.
      *
      * @author Jeff Wilde
      */
    trait Exclusive[A] extends Bound


    import shapeless.ops.hlist._

    type AuxF[A <: BoundedRange.Bound, B <: BoundedRange.Bound, Out0 <: HList] =
      BoundedRange[A, B] {type Out = Out0}

    //
    // nil ranges (both nil starting and recursive terminators)

    implicit def nilClosed[A <: Nat]
    (implicit w: Witness.Aux[A])
    : AuxF[Inclusive[A], Inclusive[A], A :: HNil] =
      new BoundedRange[Inclusive[A], Inclusive[A]] {
        type Out = A :: HNil

        def apply(): Out = w.value :: HNil
      }

    implicit def nilOpen[A <: Nat]
    (implicit w: Witness.Aux[A])
    : AuxF[Exclusive[A], Exclusive[A], HNil] =
      new BoundedRange[Exclusive[A], Exclusive[A]] {
        type Out = HNil

        def apply(): Out = HNil
      }

    implicit def nilLeftOpenRightClosed[A <: Nat]
    (implicit w: Witness.Aux[A])
    : AuxF[Exclusive[A], Inclusive[A], A :: HNil] =
      new BoundedRange[Exclusive[A], Inclusive[A]] {
        type Out = A :: HNil

        def apply(): Out = w.value :: HNil
      }

    implicit def nilLeftClosedRightOpen[A <: Nat]
    (implicit w: Witness.Aux[A])
    : AuxF[Inclusive[A], Exclusive[A], A :: HNil] =
      new BoundedRange[Inclusive[A], Exclusive[A]] {
        type Out = A :: HNil

        def apply(): Out = w.value :: HNil
      }

    //
    // nil ranges (recursive terminators only)

    implicit def nilLeftOpenRightSoft[A <: Nat]
    : AuxF[Exclusive[A], SoftInclusive[A], HNil] =
      new BoundedRange[Exclusive[A], SoftInclusive[A]] {
        type Out = HNil

        def apply(): Out = HNil
      }

    implicit def nilLeftClosedRightSoft[A <: Nat]
    (implicit w: Witness.Aux[A])
    : AuxF[Inclusive[A], SoftInclusive[A], A :: HNil] =
      new BoundedRange[Inclusive[A], SoftInclusive[A]] {
        type Out = A :: HNil

        def apply(): Out = w.value :: HNil
      }

    //
    // intermediate recursive ranges

    implicit def leftOpenRightSoft[A <: Nat, B <: Nat, Sub <: HList]
    (implicit
      w: Witness.Aux[Succ[B]],
      subRange: AuxF[Exclusive[A], SoftInclusive[B], Sub])
    : AuxF[Exclusive[A], SoftInclusive[Succ[B]], Succ[B] :: Sub] =
      new BoundedRange[Exclusive[A], SoftInclusive[Succ[B]]] {
        type Out = Succ[B] :: Sub

        def apply(): Out = w.value :: subRange()
      }

    implicit def leftClosedRightSoft[A <: Nat, B <: Nat, Sub <: HList]
    (implicit
      w: Witness.Aux[Succ[B]],
      subRange: AuxF[Inclusive[A], SoftInclusive[B], Sub])
    : AuxF[Inclusive[A], SoftInclusive[Succ[B]], Succ[B] :: Sub] =
      new BoundedRange[Inclusive[A], SoftInclusive[Succ[B]]] {
        type Out =  Succ[B] :: Sub

        def apply(): Out = w.value :: subRange()
      }

    //
    // public starting ranges

    implicit def closed[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList]
    (implicit
      w: Witness.Aux[Succ[B]],
      subRange: AuxF[Inclusive[A], SoftInclusive[B], Sub],
      reverse: ReversePrepend.Aux[Sub, Succ[B] :: HNil, Rev])
    : AuxF[Inclusive[A], Inclusive[Succ[B]], Rev] =
      new BoundedRange[Inclusive[A], Inclusive[Succ[B]]] {
        type Out = Rev

        def apply(): Out = reverse(subRange(), w.value :: HNil)
      }

    implicit def open[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList]
    (implicit
      subRange: AuxF[Exclusive[A], SoftInclusive[B], Sub],
      reverse: Reverse.Aux[Sub, Rev])
    : AuxF[Exclusive[A], Exclusive[Succ[B]], Rev] =
      new BoundedRange[Exclusive[A], Exclusive[Succ[B]]] {
        type Out = Rev

        def apply(): Out = reverse(subRange())
      }

    implicit def leftOpenRightClosed[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList]
    (implicit
      w: Witness.Aux[Succ[B]],
      subRange: AuxF[Exclusive[A], SoftInclusive[B], Sub],
      reverse: ReversePrepend.Aux[Sub, Succ[B] :: HNil, Rev])
    : AuxF[Exclusive[A], Inclusive[Succ[B]], Rev] =
      new BoundedRange[Exclusive[A], Inclusive[Succ[B]]] {
        type Out = Rev

        def apply(): Out = reverse(subRange(), w.value :: HNil)
      }

    implicit def leftClosedRightOpen[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList]
    (implicit
      subRange: AuxF[Inclusive[A], SoftInclusive[B], Sub],
      reverse: Reverse.Aux[Sub, Rev])
    : AuxF[Inclusive[A], Exclusive[Succ[B]], Rev] =
      new BoundedRange[Inclusive[A], Exclusive[Succ[B]]] {
        type Out =  Rev

        def apply(): Out = reverse(subRange())
      }

    //
    // reversed starting ranges

    implicit def openReverse[A <: Nat, B <: Nat, Sub <: HList]
    (implicit subRange: AuxF[Exclusive[B], SoftInclusive[A], Sub])
    : AuxF[Exclusive[Succ[A]], Exclusive[B], Sub] =
      new BoundedRange[Exclusive[Succ[A]], Exclusive[B]] {
        type Out = Sub

        def apply(): Out = subRange()
      }

    implicit def leftClosedRightOpenReverse[A <: Nat, B <: Nat, Sub <: HList]
    (implicit
      wA: Witness.Aux[Succ[A]],
      subRange: AuxF[Exclusive[B], SoftInclusive[A], Sub])
    : AuxF[Inclusive[Succ[A]], Exclusive[B], Succ[A] :: Sub] =
      new BoundedRange[Inclusive[Succ[A]], Exclusive[B]] {
        type Out =  Succ[A] :: Sub

        def apply(): Out = wA.value :: subRange()
      }

    implicit def leftOpenRightClosedReverse[A <: Nat, B <: Nat, Sub <: HList]
    (implicit subRange: AuxF[Inclusive[B], SoftInclusive[A], Sub])
    : AuxF[Exclusive[Succ[A]], Inclusive[B], Sub] =
      new BoundedRange[Exclusive[Succ[A]], Inclusive[B]] {
        type Out =  Sub

        def apply(): Out = subRange()
      }

    implicit def closedReverse[A <: Nat, B <: Nat, Sub <: HList]
    (implicit
      wA: Witness.Aux[Succ[A]],
      subRange: AuxF[Inclusive[B], SoftInclusive[A], Sub])
    : AuxF[Inclusive[Succ[A]], Inclusive[B], Succ[A] :: Sub] =
      new BoundedRange[Inclusive[Succ[A]], Inclusive[B]] {
        type Out =  Succ[A] :: Sub

        def apply(): Out = wA.value :: subRange()
      }

    object Bound {

      implicit def inclusive[A <: Nat]
      (implicit w: Witness.Aux[A])
      : Inclusive[A] =
        new Inclusive[A] {
          type Out = A

          def apply(): Out = w.value
        }

      implicit def exclusive[A <: Nat]
      (implicit w: Witness.Aux[A])
      : Exclusive[A] =
        new Exclusive[A] {
          type Out = A

          def apply(): Out = w.value
        }

    }

  }

  /**
   * Type class supporting conversion of type-level Nats to value level Ints.
   * 
   * @author Miles Sabin
   */
  trait ToInt[N <: Nat] extends Serializable {
    def apply() : Int
  }

  object ToInt {
    def apply[N <: Nat](implicit toInt: ToInt[N]): ToInt[N] = toInt

    class Inst[N <: Nat] (i: Int) extends ToInt[N]{
      def apply(): Int = i
    }

    implicit val toInt0: ToInt[_0] = new Inst[_0](0)

    //this method is used for backwards compatibility
    def toIntSucc[N <: Nat](toIntN : ToInt[N]) = new ToInt[Succ[N]] {
      def apply() = toIntN() + 1
    }

    implicit def toIntSuccM[N <: Nat]: ToInt[N] = macro ToIntMacros.applyImpl[N]
  }

  @macrocompat.bundle
  class ToIntMacros(val c: whitebox.Context) extends CaseClassMacros {
    import c.universe._

    val _0Tpe = typeOf[_0]
    val succTpe = typeOf[Succ[_]].typeConstructor
    val succSym = succTpe.typeSymbol
    val succPre = prefix(succTpe)


    def applyImpl[N <: Nat](implicit nTag: WeakTypeTag[N]): Tree = {
      val tpe = nTag.tpe.dealias

      @tailrec
      def count(u: Type, acc: Int): Int = {
        if(u <:< _0Tpe) acc
        else (u baseType succSym) match {
          case TypeRef(pre, _, List(n)) if pre =:= succPre => count(n, acc + 1)
          case _ => abort(s"$tpe is not a Nat type")
        }
      }

      q"""
            new _root_.shapeless.ops.nat.ToInt.Inst(${count(tpe, 0)}).
              asInstanceOf[ _root_.shapeless.ops.nat.ToInt[$tpe]]
          """
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy