diff --git a/.gitignore b/.gitignore index 38c48e9..7c6af4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -elm-stuff node_modules elm.js Auth.elm +generated-code +build-artifacts +*.log diff --git a/elm-stuff/.gitignore b/elm-stuff/.gitignore new file mode 100644 index 0000000..f6cea5e --- /dev/null +++ b/elm-stuff/.gitignore @@ -0,0 +1,5 @@ +build-artifacts +*.md +*.yml +.eslintrc +*.sh diff --git a/elm-stuff/exact-dependencies.json b/elm-stuff/exact-dependencies.json new file mode 100644 index 0000000..98d63ff --- /dev/null +++ b/elm-stuff/exact-dependencies.json @@ -0,0 +1,6 @@ +{ + "elm-lang/virtual-dom": "2.0.4", + "elm-lang/html": "2.0.0", + "elm-lang/http": "1.0.0", + "elm-lang/core": "5.1.1" +} \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore b/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore new file mode 100644 index 0000000..7f3cfe4 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore @@ -0,0 +1,3 @@ +elm-stuff +tests/test.js +node_modules/ \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE b/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json b/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json new file mode 100644 index 0000000..2f25729 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json @@ -0,0 +1,38 @@ +{ + "version": "5.1.1", + "summary": "Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Array", + "Basics", + "Bitwise", + "Char", + "Color", + "Date", + "Debug", + "Dict", + "Json.Decode", + "Json.Encode", + "List", + "Maybe", + "Platform", + "Platform.Cmd", + "Platform.Sub", + "Process", + "Random", + "Regex", + "Result", + "Set", + "String", + "Task", + "Time", + "Tuple" + ], + "native-modules": true, + "dependencies": {}, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm new file mode 100644 index 0000000..58ae2ba --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm @@ -0,0 +1,240 @@ +module Array exposing + ( Array + , empty, repeat, initialize, fromList + , isEmpty, length, push, append + , get, set + , slice, toList, toIndexedList + , map, indexedMap, filter, foldl, foldr + ) + +{-| A library for fast immutable arrays. The elements in an array must have the +same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast +reads, updates, and appends. + +# Arrays +@docs Array + +# Creating Arrays +@docs empty, repeat, initialize, fromList + +# Basics +@docs isEmpty, length, push, append + +# Get and Set +@docs get, set + +# Taking Arrays Apart +@docs slice, toList, toIndexedList + +# Mapping, Filtering, and Folding +@docs map, indexedMap, filter, foldl, foldr +-} + +import Native.Array +import Basics exposing (..) +import Maybe exposing (..) +import List + + +{-| Representation of fast immutable arrays. You can create arrays of integers +(`Array Int`) or strings (`Array String`) or any other type of value you can +dream up. +-} +type Array a = Array + + +{-| Initialize an array. `initialize n f` creates an array of length `n` with +the element at index `i` initialized to the result of `(f i)`. + + initialize 4 identity == fromList [0,1,2,3] + initialize 4 (\n -> n*n) == fromList [0,1,4,9] + initialize 4 (always 0) == fromList [0,0,0,0] +-} +initialize : Int -> (Int -> a) -> Array a +initialize = + Native.Array.initialize + + +{-| Creates an array with a given length, filled with a default element. + + repeat 5 0 == fromList [0,0,0,0,0] + repeat 3 "cat" == fromList ["cat","cat","cat"] + +Notice that `repeat 3 x` is the same as `initialize 3 (always x)`. +-} +repeat : Int -> a -> Array a +repeat n e = + initialize n (always e) + + +{-| Create an array from a list. +-} +fromList : List a -> Array a +fromList = + Native.Array.fromList + + +{-| Create a list of elements from an array. + + toList (fromList [3,5,8]) == [3,5,8] +-} +toList : Array a -> List a +toList = + Native.Array.toList + + +-- TODO: make this a native function. +{-| Create an indexed list from an array. Each element of the array will be +paired with its index. + + toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")] +-} +toIndexedList : Array a -> List (Int, a) +toIndexedList array = + List.map2 + (,) + (List.range 0 (Native.Array.length array - 1)) + (Native.Array.toList array) + + +{-| Apply a function on every element in an array. + + map sqrt (fromList [1,4,9]) == fromList [1,2,3] +-} +map : (a -> b) -> Array a -> Array b +map = + Native.Array.map + + +{-| Apply a function on every element with its index as first argument. + + indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10] +-} +indexedMap : (Int -> a -> b) -> Array a -> Array b +indexedMap = + Native.Array.indexedMap + + +{-| Reduce an array from the left. Read `foldl` as “fold from the left”. + + foldl (::) [] (fromList [1,2,3]) == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> Array a -> b +foldl = + Native.Array.foldl + + +{-| Reduce an array from the right. Read `foldr` as “fold from the right”. + + foldr (+) 0 (repeat 3 5) == 15 +-} +foldr : (a -> b -> b) -> b -> Array a -> b +foldr = + Native.Array.foldr + + +{-| Keep only elements that satisfy the predicate: + + filter isEven (fromList [1,2,3,4,5,6]) == (fromList [2,4,6]) +-} +filter : (a -> Bool) -> Array a -> Array a +filter isOkay arr = + let + update x xs = + if isOkay x then + Native.Array.push x xs + else + xs + in + Native.Array.foldl update Native.Array.empty arr + +{-| Return an empty array. + + length empty == 0 +-} +empty : Array a +empty = + Native.Array.empty + + +{-| Push an element to the end of an array. + + push 3 (fromList [1,2]) == fromList [1,2,3] +-} +push : a -> Array a -> Array a +push = + Native.Array.push + + +{-| Return Just the element at the index or Nothing if the index is out of range. + + get 0 (fromList [0,5,3]) == Just 0 + get 2 (fromList [0,5,3]) == Just 3 + get 5 (fromList [0,5,3]) == Nothing + get -1 (fromList [0,5,3]) == Nothing + +-} +get : Int -> Array a -> Maybe a +get i array = + if 0 <= i && i < Native.Array.length array then + Just (Native.Array.get i array) + else + Nothing + + +{-| Set the element at a particular index. Returns an updated array. +If the index is out of range, the array is unaltered. + + set 1 7 (fromList [1,2,3]) == fromList [1,7,3] +-} +set : Int -> a -> Array a -> Array a +set = + Native.Array.set + + +{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a +zero-based index where we will start our slice. The `end` is a zero-based index +that indicates the end of the slice. The slice extracts up to but not including +`end`. + + slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2] + slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3] + +Both the `start` and `end` indexes can be negative, indicating an offset from +the end of the array. + + slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3] + slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4] + +This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array` +-} +slice : Int -> Int -> Array a -> Array a +slice = + Native.Array.slice + + +{-| Return the length of an array. + + length (fromList [1,2,3]) == 3 +-} +length : Array a -> Int +length = + Native.Array.length + + +{-| Determine if an array is empty. + + isEmpty empty == True +-} +isEmpty : Array a -> Bool +isEmpty array = + length array == 0 + + +{-| Append two arrays to a new one. + + append (repeat 2 42) (repeat 3 81) == fromList [42,42,81,81,81] +-} +append : Array a -> Array a -> Array a +append = + Native.Array.append diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm new file mode 100644 index 0000000..2d06c86 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm @@ -0,0 +1,650 @@ +module Basics exposing + ( (==), (/=) + , (<), (>), (<=), (>=), max, min, Order (..), compare + , not, (&&), (||), xor + , (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + , pi, cos, sin, tan, acos, asin, atan, atan2 + , round, floor, ceiling, truncate, toFloat + , degrees, radians, turns + , toPolar, fromPolar + , isNaN, isInfinite + , toString, (++) + , identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + ) + +{-| Tons of useful functions that get imported by default. + +# Equality +@docs (==), (/=) + +# Comparison + +These functions only work on `comparable` types. This includes numbers, +characters, strings, lists of comparable things, and tuples of comparable +things. Note that tuples with 7 or more elements are not comparable; why +are your tuples so big? + +@docs (<), (>), (<=), (>=), max, min, Order, compare + +# Booleans +@docs not, (&&), (||), xor + +# Mathematics +@docs (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + +# Trigonometry +@docs pi, cos, sin, tan, acos, asin, atan, atan2 + +# Number Conversions +@docs round, floor, ceiling, truncate, toFloat + +# Angle Conversions +All angle conversions result in “standard Elm angles” +which happen to be radians. + +@docs degrees, radians, turns + +# Polar Coordinates +@docs toPolar, fromPolar + +# Floating Point Checks +@docs isNaN, isInfinite + +# Strings and Lists +@docs toString, (++) + +# Higher-Order Helpers +@docs identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + +-} + +import Native.Basics +import Native.Utils + + +{-| Convert radians to standard Elm angles (radians). -} +radians : Float -> Float +radians t = + t + + +{-| Convert degrees to standard Elm angles (radians). -} +degrees : Float -> Float +degrees = + Native.Basics.degrees + + +{-| Convert turns to standard Elm angles (radians). +One turn is equal to 360°. +-} +turns : Float -> Float +turns = + Native.Basics.turns + + +{-| Convert polar coordinates (r,θ) to Cartesian coordinates (x,y). -} +fromPolar : (Float,Float) -> (Float,Float) +fromPolar = + Native.Basics.fromPolar + + +{-| Convert Cartesian coordinates (x,y) to polar coordinates (r,θ). -} +toPolar : (Float,Float) -> (Float,Float) +toPolar = + Native.Basics.toPolar + + +{-|-} +(+) : number -> number -> number +(+) = + Native.Basics.add + + +{-|-} +(-) : number -> number -> number +(-) = + Native.Basics.sub + + +{-|-} +(*) : number -> number -> number +(*) = + Native.Basics.mul + + +{-| Floating point division. -} +(/) : Float -> Float -> Float +(/) = + Native.Basics.floatDiv + + +infixl 6 + +infixl 6 - +infixl 7 * +infixl 7 / +infixr 8 ^ + +infixl 7 // +infixl 7 % + + +{-| Integer division. The remainder is discarded. -} +(//) : Int -> Int -> Int +(//) = + Native.Basics.div + + +{-| Find the remainder after dividing one number by another. + + rem 11 4 == 3 + rem 12 4 == 0 + rem 13 4 == 1 + rem -1 4 == -1 +-} +rem : Int -> Int -> Int +rem = + Native.Basics.rem + + +{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic). + + 7 % 2 == 1 + -1 % 4 == 3 +-} +(%) : Int -> Int -> Int +(%) = + Native.Basics.mod + + +{-| Exponentiation + + 3^2 == 9 +-} +(^) : number -> number -> number +(^) = + Native.Basics.exp + + +{-|-} +cos : Float -> Float +cos = + Native.Basics.cos + + +{-|-} +sin : Float -> Float +sin = + Native.Basics.sin + + +{-|-} +tan : Float -> Float +tan = + Native.Basics.tan + + +{-|-} +acos : Float -> Float +acos = + Native.Basics.acos + + +{-|-} +asin : Float -> Float +asin = + Native.Basics.asin + + +{-| You probably do not want to use this. It takes `(y/x)` as the +argument, so there is no way to know whether the negative signs comes from +the `y` or `x`. Thus, the resulting angle is always between π/2 and -π/2 +(in quadrants I and IV). You probably want to use `atan2` instead. +-} +atan : Float -> Float +atan = + Native.Basics.atan + + +{-| This helps you find the angle of a Cartesian coordinate. +You will almost certainly want to use this instead of `atan`. +So `atan2 y x` computes *atan(y/x)* but also keeps track of which +quadrant the angle should really be in. The result will be between +π and -π, giving you the full range of angles. +-} +atan2 : Float -> Float -> Float +atan2 = + Native.Basics.atan2 + + +{-| Take the square root of a number. -} +sqrt : Float -> Float +sqrt = + Native.Basics.sqrt + + +{-| Negate a number. + + negate 42 == -42 + negate -42 == 42 + negate 0 == 0 +-} +negate : number -> number +negate = + Native.Basics.negate + + +{-| Take the absolute value of a number. -} +abs : number -> number +abs = + Native.Basics.abs + + +{-| Calculate the logarithm of a number with a given base. + + logBase 10 100 == 2 + logBase 2 256 == 8 +-} +logBase : Float -> Float -> Float +logBase = + Native.Basics.logBase + + +{-| Clamps a number within a given range. With the expression +`clamp 100 200 x` the results are as follows: + + 100 if x < 100 + x if 100 <= x < 200 + 200 if 200 <= x +-} +clamp : number -> number -> number -> number +clamp = + Native.Basics.clamp + + +{-| An approximation of pi. -} +pi : Float +pi = + Native.Basics.pi + + +{-| An approximation of e. -} +e : Float +e = + Native.Basics.e + + +{-| Check if values are “the same”. + +**Note:** Elm uses structural equality on tuples, records, and user-defined +union types. This means the values `(3, 4)` and `(3, 4)` are definitely equal. +This is not true in languages like JavaScript that use reference equality on +objects. + +**Note:** Equality (in the Elm sense) is not possible for certain types. For +example, the functions `(\n -> n + 1)` and `(\n -> 1 + n)` are “the +same” but detecting this in general is [undecidable][]. In a future +release, the compiler will detect when `(==)` is used with problematic +types and provide a helpful error message. This will require quite serious +infrastructure work that makes sense to batch with another big project, so the +stopgap is to crash as quickly as possible. Problematic types include functions +and JavaScript values like `Json.Encode.Value` which could contain functions +if passed through a port. + +[undecidable]: https://en.wikipedia.org/wiki/Undecidable_problem +-} +(==) : a -> a -> Bool +(==) = + Native.Basics.eq + + +{-| Check if values are not “the same”. + +So `(a /= b)` is the same as `(not (a == b))`. +-} +(/=) : a -> a -> Bool +(/=) = + Native.Basics.neq + + +{-|-} +(<) : comparable -> comparable -> Bool +(<) = + Native.Basics.lt + + +{-|-} +(>) : comparable -> comparable -> Bool +(>) = + Native.Basics.gt + + +{-|-} +(<=) : comparable -> comparable -> Bool +(<=) = + Native.Basics.le + + +{-|-} +(>=) : comparable -> comparable -> Bool +(>=) = + Native.Basics.ge + + +infix 4 == +infix 4 /= +infix 4 < +infix 4 > +infix 4 <= +infix 4 >= + + +{-| Compare any two comparable values. Comparable values include `String`, `Char`, +`Int`, `Float`, `Time`, or a list or tuple containing comparable values. +These are also the only values that work as `Dict` keys or `Set` members. +-} +compare : comparable -> comparable -> Order +compare = + Native.Basics.compare + + +{-| Represents the relative ordering of two things. +The relations are less than, equal to, and greater than. +-} +type Order = LT | EQ | GT + + +{-| Find the smaller of two comparables. -} +min : comparable -> comparable -> comparable +min = + Native.Basics.min + + +{-| Find the larger of two comparables. -} +max : comparable -> comparable -> comparable +max = + Native.Basics.max + + +{-| The logical AND operator. `True` if both inputs are `True`. + +**Note:** When used in the infix position, like `(left && right)`, the operator +short-circuits. This means if `left` is `False` we do not bother evaluating `right` +and just return `False` overall. +-} +(&&) : Bool -> Bool -> Bool +(&&) = + Native.Basics.and + + +{-| The logical OR operator. `True` if one or both inputs are `True`. + +**Note:** When used in the infix position, like `(left || right)`, the operator +short-circuits. This means if `left` is `True` we do not bother evaluating `right` +and just return `True` overall. +-} +(||) : Bool -> Bool -> Bool +(||) = + Native.Basics.or + + +infixr 3 && +infixr 2 || + + +{-| The exclusive-or operator. `True` if exactly one input is `True`. -} +xor : Bool -> Bool -> Bool +xor = + Native.Basics.xor + + +{-| Negate a boolean value. + + not True == False + not False == True +-} +not : Bool -> Bool +not = + Native.Basics.not + + +-- Conversions + +{-| Round a number to the nearest integer. -} +round : Float -> Int +round = + Native.Basics.round + + +{-| Truncate a number, rounding towards zero. -} +truncate : Float -> Int +truncate = + Native.Basics.truncate + + +{-| Floor function, rounding down. -} +floor : Float -> Int +floor = + Native.Basics.floor + + +{-| Ceiling function, rounding up. -} +ceiling : Float -> Int +ceiling = + Native.Basics.ceiling + + +{-| Convert an integer into a float. -} +toFloat : Int -> Float +toFloat = + Native.Basics.toFloat + + +{-| Determine whether a float is an undefined or unrepresentable number. +NaN stands for *not a number* and it is [a standardized part of floating point +numbers](http://en.wikipedia.org/wiki/NaN). + + isNaN (0/0) == True + isNaN (sqrt -1) == True + isNaN (1/0) == False -- infinity is a number + isNaN 1 == False +-} +isNaN : Float -> Bool +isNaN = + Native.Basics.isNaN + + +{-| Determine whether a float is positive or negative infinity. + + isInfinite (0/0) == False + isInfinite (sqrt -1) == False + isInfinite (1/0) == True + isInfinite 1 == False + +Notice that NaN is not infinite! For float `n` to be finite implies that +`not (isInfinite n || isNaN n)` evaluates to `True`. +-} +isInfinite : Float -> Bool +isInfinite = + Native.Basics.isInfinite + + +{-| Turn any kind of value into a string. When you view the resulting string +with `Text.fromString` it should look just like the value it came from. + + toString 42 == "42" + toString [1,2] == "[1,2]" + toString "he said, \"hi\"" == "\"he said, \\\"hi\\\"\"" +-} +toString : a -> String +toString = + Native.Utils.toString + + +{-| Put two appendable things together. This includes strings, lists, and text. + + "hello" ++ "world" == "helloworld" + [1,1,2] ++ [3,5,8] == [1,1,2,3,5,8] +-} +(++) : appendable -> appendable -> appendable +(++) = + Native.Utils.append + + +infixr 5 ++ + + +-- Function Helpers + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + not << isEven << sqrt + +You can think of this operator as equivalent to the following: + + (g << f) == (\x -> g (f x)) + +So our example expands out to something like this: + + \n -> not (isEven (sqrt n)) +-} +(<<) : (b -> c) -> (a -> b) -> (a -> c) +(<<) g f x = + g (f x) + + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + sqrt >> isEven >> not + +This direction of function composition seems less pleasant than `(<<)` which +reads nicely in expressions like: `filter (not << isRegistered) students` +-} +(>>) : (a -> b) -> (b -> c) -> (a -> c) +(>>) f g x = + g (f x) + + +{-| Forward function application `x |> f == f x`. This function is useful +for avoiding parentheses and writing code in a more natural way. +Consider the following code to create a pentagon: + + scale 2 (move (10,10) (filled blue (ngon 5 30))) + +This can also be written as: + + ngon 5 30 + |> filled blue + |> move (10,10) + |> scale 2 +-} +(|>) : a -> (a -> b) -> b +(|>) x f = + f x + + +{-| Backward function application `f <| x == f x`. This function is useful for +avoiding parentheses. Consider the following code to create a text element: + + leftAligned (monospace (fromString "code")) + +This can also be written as: + + leftAligned <| monospace <| fromString "code" +-} +(<|) : (a -> b) -> a -> b +(<|) f x = + f x + + +infixr 9 << +infixl 9 >> +infixr 0 <| +infixl 0 |> + + +{-| Given a value, returns exactly the same value. This is called +[the identity function](http://en.wikipedia.org/wiki/Identity_function). +-} +identity : a -> a +identity x = + x + + +{-| Create a function that *always* returns the same value. Useful with +functions like `map`: + + List.map (always 0) [1,2,3,4,5] == [0,0,0,0,0] + + -- List.map (\_ -> 0) [1,2,3,4,5] == [0,0,0,0,0] + -- always = (\x _ -> x) +-} +always : a -> b -> a +always a _ = + a + + +{-| Flip the order of the first two arguments to a function. -} +flip : (a -> b -> c) -> (b -> a -> c) +flip f b a = + f a b + + +{-| Change how arguments are passed to a function. +This splits paired arguments into two separate arguments. +-} +curry : ((a,b) -> c) -> a -> b -> c +curry f a b = + f (a,b) + + +{-| Change how arguments are passed to a function. +This combines two arguments into a single pair. +-} +uncurry : (a -> b -> c) -> (a,b) -> c +uncurry f (a,b) = + f a b + + +{-| A value that can never happen! For context: + + - The boolean type `Bool` has two values: `True` and `False` + - The unit type `()` has one value: `()` + - The never type `Never` has no values! + +You may see it in the wild in `Html Never` which means this HTML will never +produce any messages. You would need to write an event handler like +`onClick ??? : Attribute Never` but how can we fill in the question marks?! +So there cannot be any event handlers on that HTML. + +You may also see this used with tasks that never fail, like `Task Never ()`. + +The `Never` type is useful for restricting *arguments* to a function. Maybe my +API can only accept HTML without event handlers, so I require `Html Never` and +users can give `Html msg` and everything will go fine. Generally speaking, you +do not want `Never` in your return types though. +-} +type Never = JustOneMore Never + + +{-| A function that can never be called. Seems extremely pointless, but it +*can* come in handy. Imagine you have some HTML that should never produce any +messages. And say you want to use it in some other HTML that *does* produce +messages. You could say: + + import Html exposing (..) + + embedHtml : Html Never -> Html msg + embedHtml staticStuff = + div [] + [ text "hello" + , Html.map never staticStuff + ] + +So the `never` function is basically telling the type system, make sure no one +ever calls me! +-} +never : Never -> a +never (JustOneMore nvr) = + never nvr diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm new file mode 100644 index 0000000..14c7a82 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm @@ -0,0 +1,90 @@ +module Bitwise exposing + ( and, or, xor, complement + , shiftLeftBy, shiftRightBy, shiftRightZfBy + ) + +{-| Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation). + +# Basic Operations +@docs and, or, xor, complement + +# Bit Shifts +@docs shiftLeftBy, shiftRightBy, shiftRightZfBy +-} + +import Native.Bitwise + + +{-| Bitwise AND +-} +and : Int -> Int -> Int +and = + Native.Bitwise.and + + +{-| Bitwise OR +-} +or : Int -> Int -> Int +or = + Native.Bitwise.or + + +{-| Bitwise XOR +-} +xor : Int -> Int -> Int +xor = + Native.Bitwise.xor + + +{-| Flip each bit individually, often called bitwise NOT +-} +complement : Int -> Int +complement = + Native.Bitwise.complement + + +{-| Shift bits to the left by a given offset, filling new bits with zeros. +This can be used to multiply numbers by powers of two. + + shiftLeftBy 1 5 == 10 + shiftLeftBy 5 1 == 32 +-} +shiftLeftBy : Int -> Int -> Int +shiftLeftBy = + Native.Bitwise.shiftLeftBy + + +{-| Shift bits to the right by a given offset, filling new bits with +whatever is the topmost bit. This can be used to divide numbers by powers of two. + + shiftRightBy 1 32 == 16 + shiftRightBy 2 32 == 8 + shiftRightBy 1 -32 == -16 + +This is called an [arithmetic right shift][ars], often written (>>), and +sometimes called a sign-propagating right shift because it fills empty spots +with copies of the highest bit. + +[ars]: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift +-} +shiftRightBy : Int -> Int -> Int +shiftRightBy = + Native.Bitwise.shiftRightBy + + +{-| Shift bits to the right by a given offset, filling new bits with zeros. + + shiftRightZfBy 1 32 == 16 + shiftRightZfBy 2 32 == 8 + shiftRightZfBy 1 -32 == 2147483632 + +This is called an [logical right shift][lrs], often written (>>>), and +sometimes called a zero-fill right shift because it fills empty spots with +zeros. + +[lrs]: http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift +-} +shiftRightZfBy : Int -> Int -> Int +shiftRightZfBy = + Native.Bitwise.shiftRightZfBy + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm new file mode 100644 index 0000000..288f50b --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm @@ -0,0 +1,103 @@ +module Char exposing + ( isUpper, isLower, isDigit, isOctDigit, isHexDigit + , toUpper, toLower, toLocaleUpper, toLocaleLower + , KeyCode, toCode, fromCode + ) + +{-| Functions for working with characters. Character literals are enclosed in +`'a'` pair of single quotes. + +# Classification +@docs isUpper, isLower, isDigit, isOctDigit, isHexDigit + +# Conversion +@docs toUpper, toLower, toLocaleUpper, toLocaleLower + +# Key Codes +@docs KeyCode, toCode, fromCode + +-} + +import Native.Char +import Basics exposing ((&&), (||), (>=), (<=)) + + +isBetween : Char -> Char -> Char -> Bool +isBetween low high char = + let code = toCode char + in + (code >= toCode low) && (code <= toCode high) + + +{-| True for upper case ASCII letters. -} +isUpper : Char -> Bool +isUpper = + isBetween 'A' 'Z' + + +{-| True for lower case ASCII letters. -} +isLower : Char -> Bool +isLower = + isBetween 'a' 'z' + + +{-| True for ASCII digits `[0-9]`. -} +isDigit : Char -> Bool +isDigit = + isBetween '0' '9' + + +{-| True for ASCII octal digits `[0-7]`. -} +isOctDigit : Char -> Bool +isOctDigit = + isBetween '0' '7' + + +{-| True for ASCII hexadecimal digits `[0-9a-fA-F]`. -} +isHexDigit : Char -> Bool +isHexDigit char = + isDigit char || isBetween 'a' 'f' char || isBetween 'A' 'F' char + + +{-| Convert to upper case. -} +toUpper : Char -> Char +toUpper = + Native.Char.toUpper + + +{-| Convert to lower case. -} +toLower : Char -> Char +toLower = + Native.Char.toLower + + +{-| Convert to upper case, according to any locale-specific case mappings. -} +toLocaleUpper : Char -> Char +toLocaleUpper = + Native.Char.toLocaleUpper + + +{-| Convert to lower case, according to any locale-specific case mappings. -} +toLocaleLower : Char -> Char +toLocaleLower = + Native.Char.toLocaleLower + + +{-| Keyboard keys can be represented as integers. These are called *key codes*. +You can use [`toCode`](#toCode) and [`fromCode`](#fromCode) to convert between +key codes and characters. +-} +type alias KeyCode = Int + + +{-| Convert to key code. +-} +toCode : Char -> KeyCode +toCode = + Native.Char.toCode + + +{-| Convert from key code. -} +fromCode : KeyCode -> Char +fromCode = + Native.Char.fromCode diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm new file mode 100644 index 0000000..d150240 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm @@ -0,0 +1,456 @@ +module Color exposing + ( Color, rgb, rgba, hsl, hsla, greyscale, grayscale, complement + , Gradient, linear, radial + , toRgb, toHsl + , red, orange, yellow, green, blue, purple, brown + , lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + , darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + , white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + , lightGray, gray, darkGray + ) + +{-| Library for working with colors. Includes +[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and +[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and +built-in names. + +# Colors +@docs Color + +# Creation +@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement + +# Gradients +@docs Gradient, linear, radial + +# Extracting Colors +@docs toRgb, toHsl + +# Built-in Colors +These colors come from the [Tango +palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) +which provides aesthetically reasonable defaults for colors. Each color also +comes with a light and dark version. + +### Standard +@docs red, orange, yellow, green, blue, purple, brown + +### Light +@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + +### Dark +@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + +### Eight Shades of Grey +These colors are a compatible series of shades of grey, fitting nicely +with the Tango palette. +@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + +These are identical to the *grey* versions. It seems the spelling is regional, but +that has never helped me remember which one I should be writing. +@docs lightGray, gray, darkGray + +-} + +import Basics exposing (..) + + +{-| Representation of colors. +-} +type Color + = RGBA Int Int Int Float + | HSLA Float Float Float Float + + +{-| Create RGB colors with an alpha component for transparency. +The alpha component is specified with numbers between 0 and 1. -} +rgba : Int -> Int -> Int -> Float -> Color +rgba = + RGBA + + +{-| Create RGB colors from numbers between 0 and 255 inclusive. -} +rgb : Int -> Int -> Int -> Color +rgb r g b = + RGBA r g b 1 + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV) +with an alpha component for transparency. +-} +hsla : Float -> Float -> Float -> Float -> Color +hsla hue saturation lightness alpha = + HSLA (hue - turns (toFloat (floor (hue / (2*pi))))) saturation lightness alpha + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives +you access to colors more like a color wheel, where all hues are arranged in a +circle that you specify with standard Elm angles (radians). + + red = hsl (degrees 0) 1 0.5 + green = hsl (degrees 120) 1 0.5 + blue = hsl (degrees 240) 1 0.5 + + pastelRed = hsl (degrees 0) 0.7 0.7 + +To cycle through all colors, just cycle through degrees. The saturation level +is how vibrant the color is, like a dial between grey and bright colors. The +lightness level is a dial between white and black. +-} +hsl : Float -> Float -> Float -> Color +hsl hue saturation lightness = + hsla hue saturation lightness 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +grayscale : Float -> Color +grayscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +greyscale : Float -> Color +greyscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a “complementary color”. The two colors will +accent each other. This is the same as rotating the hue by 180°. +-} +complement : Color -> Color +complement color = + case color of + HSLA h s l a -> + hsla (h + degrees 180) s l a + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + hsla (h + degrees 180) s l a + + +{-| Extract the components of a color in the HSL format. +-} +toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float } +toHsl color = + case color of + HSLA h s l a -> + { hue=h, saturation=s, lightness=l, alpha=a } + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + { hue=h, saturation=s, lightness=l, alpha=a } + + +{-| Extract the components of a color in the RGB format. +-} +toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float } +toRgb color = + case color of + RGBA r g b a -> + { red = r, green = g, blue = b, alpha = a } + + HSLA h s l a -> + let + (r,g,b) = hslToRgb h s l + in + { red = round (255 * r) + , green = round (255 * g) + , blue = round (255 * b) + , alpha = a + } + + +fmod : Float -> Int -> Float +fmod f n = + let + integer = floor f + in + toFloat (integer % n) + f - toFloat integer + + +rgbToHsl : Int -> Int -> Int -> (Float,Float,Float) +rgbToHsl red green blue = + let + r = toFloat red / 255 + g = toFloat green / 255 + b = toFloat blue / 255 + + cMax = max (max r g) b + cMin = min (min r g) b + + c = cMax - cMin + + hue = + degrees 60 * + if cMax == r then + fmod ((g - b) / c) 6 + else if cMax == g then + ((b - r) / c) + 2 + else {- cMax == b -} + ((r - g) / c) + 4 + + lightness = + (cMax + cMin) / 2 + + saturation = + if lightness == 0 then + 0 + else + c / (1 - abs (2 * lightness - 1)) + in + (hue, saturation, lightness) + + +hslToRgb : Float -> Float -> Float -> (Float,Float,Float) +hslToRgb hue saturation lightness = + let + chroma = (1 - abs (2 * lightness - 1)) * saturation + normHue = hue / degrees 60 + + x = chroma * (1 - abs (fmod normHue 2 - 1)) + + (r,g,b) = + if normHue < 0 then (0, 0, 0) + else if normHue < 1 then (chroma, x, 0) + else if normHue < 2 then (x, chroma, 0) + else if normHue < 3 then (0, chroma, x) + else if normHue < 4 then (0, x, chroma) + else if normHue < 5 then (x, 0, chroma) + else if normHue < 6 then (chroma, 0, x) + else (0, 0, 0) + + m = lightness - chroma / 2 + in + (r + m, g + m, b + m) + + +--toV3 : Color -> V3 + +--toV4 : Color -> V4 + +{-| Abstract representation of a color gradient. +-} +type Gradient + = Linear (Float,Float) (Float,Float) (List (Float,Color)) + | Radial (Float,Float) Float (Float,Float) Float (List (Float,Color)) + + +{-| Create a linear gradient. Takes a start and end point and then a series of +“color stops” that indicate how to interpolate between the start and +end points. See [this example](http://elm-lang.org/examples/linear-gradient) for a +more visual explanation. +-} +linear : (Float, Float) -> (Float, Float) -> List (Float,Color) -> Gradient +linear = + Linear + + +{-| Create a radial gradient. First takes a start point and inner radius. Then +takes an end point and outer radius. It then takes a series of “color +stops” that indicate how to interpolate between the inner and outer +circles. See [this example](http://elm-lang.org/examples/radial-gradient) for a +more visual explanation. +-} +radial : (Float,Float) -> Float -> (Float,Float) -> Float -> List (Float,Color) -> Gradient +radial = + Radial + + +-- BUILT-IN COLORS + +{-|-} +lightRed : Color +lightRed = + RGBA 239 41 41 1 + + +{-|-} +red : Color +red = + RGBA 204 0 0 1 + + +{-|-} +darkRed : Color +darkRed = + RGBA 164 0 0 1 + + +{-|-} +lightOrange : Color +lightOrange = + RGBA 252 175 62 1 + + +{-|-} +orange : Color +orange = + RGBA 245 121 0 1 + + +{-|-} +darkOrange : Color +darkOrange = + RGBA 206 92 0 1 + + +{-|-} +lightYellow : Color +lightYellow = + RGBA 255 233 79 1 + + +{-|-} +yellow : Color +yellow = + RGBA 237 212 0 1 + + +{-|-} +darkYellow : Color +darkYellow = + RGBA 196 160 0 1 + + +{-|-} +lightGreen : Color +lightGreen = + RGBA 138 226 52 1 + + +{-|-} +green : Color +green = + RGBA 115 210 22 1 + + +{-|-} +darkGreen : Color +darkGreen = + RGBA 78 154 6 1 + + +{-|-} +lightBlue : Color +lightBlue = + RGBA 114 159 207 1 + + +{-|-} +blue : Color +blue = + RGBA 52 101 164 1 + + +{-|-} +darkBlue : Color +darkBlue = + RGBA 32 74 135 1 + + +{-|-} +lightPurple : Color +lightPurple = + RGBA 173 127 168 1 + + +{-|-} +purple : Color +purple = + RGBA 117 80 123 1 + + +{-|-} +darkPurple : Color +darkPurple = + RGBA 92 53 102 1 + + +{-|-} +lightBrown : Color +lightBrown = + RGBA 233 185 110 1 + + +{-|-} +brown : Color +brown = + RGBA 193 125 17 1 + + +{-|-} +darkBrown : Color +darkBrown = + RGBA 143 89 2 1 + + +{-|-} +black : Color +black = + RGBA 0 0 0 1 + + +{-|-} +white : Color +white = + RGBA 255 255 255 1 + + +{-|-} +lightGrey : Color +lightGrey = + RGBA 238 238 236 1 + + +{-|-} +grey : Color +grey = + RGBA 211 215 207 1 + + +{-|-} +darkGrey : Color +darkGrey = + RGBA 186 189 182 1 + + +{-|-} +lightGray : Color +lightGray = + RGBA 238 238 236 1 + + +{-|-} +gray : Color +gray = + RGBA 211 215 207 1 + + +{-|-} +darkGray : Color +darkGray = + RGBA 186 189 182 1 + + +{-|-} +lightCharcoal : Color +lightCharcoal = + RGBA 136 138 133 1 + + +{-|-} +charcoal : Color +charcoal = + RGBA 85 87 83 1 + + +{-|-} +darkCharcoal : Color +darkCharcoal = + RGBA 46 52 54 1 diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm new file mode 100644 index 0000000..0d62982 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm @@ -0,0 +1,150 @@ +module Date exposing + ( Date, fromString, toTime, fromTime + , year, month, Month(..) + , day, dayOfWeek, Day(..) + , hour, minute, second, millisecond + , now + ) + +{-| Library for working with dates. Email the mailing list if you encounter +issues with internationalization or locale formatting. + +# Dates +@docs Date, now + +# Conversions +@docs fromString, toTime, fromTime + +# Extractions +@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second, millisecond + +-} + +import Native.Date +import Task exposing (Task) +import Time exposing (Time) +import Result exposing (Result) + + + +-- DATES + + +{-| Representation of a date. +-} +type Date = Date + + +{-| Get the `Date` at the moment when this task is run. +-} +now : Task x Date +now = + Task.map fromTime Time.now + + + +-- CONVERSIONS AND EXTRACTIONS + + +{-| Represents the days of the week. +-} +type Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun + + +{-| Represents the month of the year. +-} +type Month + = Jan | Feb | Mar | Apr + | May | Jun | Jul | Aug + | Sep | Oct | Nov | Dec + + +{-| Attempt to read a date from a string. +-} +fromString : String -> Result String Date +fromString = + Native.Date.fromString + + +{-| Convert a `Date` to a time in milliseconds. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +toTime : Date -> Time +toTime = + Native.Date.toTime + + +{-| Convert a time in milliseconds into a `Date`. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +fromTime : Time -> Date +fromTime = + Native.Date.fromTime + + +{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `1990`. +-} +year : Date -> Int +year = + Native.Date.year + + +{-| Extract the month of a given date. Given the date 23 June 1990 at 11:45AM +this returns the month `Jun` as defined below. +-} +month : Date -> Month +month = + Native.Date.month + + +{-| Extract the day of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `23`. +-} +day : Date -> Int +day = + Native.Date.day + + +{-| Extract the day of the week for a given date. Given the date 23 June +1990 at 11:45AM this returns the day `Sat` as defined below. +-} +dayOfWeek : Date -> Day +dayOfWeek = + Native.Date.dayOfWeek + + +{-| Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `11`. +-} +hour : Date -> Int +hour = + Native.Date.hour + + +{-| Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `45`. +-} +minute : Date -> Int +minute = + Native.Date.minute + + +{-| Extract the second of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `0`. +-} +second : Date -> Int +second = + Native.Date.second + + +{-| Extract the millisecond of a given date. Given the date 23 June 1990 at 11:45:30.123AM +this returns the integer `123`. +-} +millisecond : Date -> Int +millisecond = + Native.Date.millisecond diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm new file mode 100644 index 0000000..49668f5 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm @@ -0,0 +1,62 @@ +module Debug exposing + ( log + , crash + ) + +{-| This library is for investigating bugs or performance problems. It should +*not* be used in production code. + +# Debugging +@docs log, crash +-} + +import Native.Debug + + +{-| Log a tagged value on the developer console, and then return the value. + + 1 + log "number" 1 -- equals 2, logs "number: 1" + length (log "start" []) -- equals 0, logs "start: []" + +Notice that `log` is not a pure function! It should *only* be used for +investigating bugs or performance problems. +-} +log : String -> a -> a +log = + Native.Debug.log + + +{-| Crash the program with an error message. This is an uncatchable error, +intended for code that is soon-to-be-implemented. For example, if you are +working with a large ADT and have partially completed a case expression, it may +make sense to do this: + + type Entity = Ship | Fish | Captain | Seagull + + drawEntity entity = + case entity of + Ship -> + ... + + Fish -> + ... + + _ -> + Debug.crash "TODO" + +The Elm compiler recognizes each `Debug.crash` and when you run into it at +runtime, the error will point to the corresponding module name and line number. +For `case` expressions that ends with a wildcard pattern and a crash, it will +also show the value that snuck through. In our example, that'd be `Captain` or +`Seagull`. + +**Use this if** you want to do some testing while you are partway through +writing a function. + +**Do not use this if** you want to do some typical try-catch exception handling. +Use the [`Maybe`](Maybe) or [`Result`](Result) libraries instead. +-} +crash : String -> a +crash = + Native.Debug.crash + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm new file mode 100644 index 0000000..0bb9501 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm @@ -0,0 +1,661 @@ +module Dict exposing + ( Dict + , empty, singleton, insert, update + , isEmpty, get, remove, member, size + , filter + , partition + , foldl, foldr, map + , union, intersect, diff, merge + , keys, values + , toList, fromList + ) + +{-| A dictionary mapping unique keys to values. The keys can be any comparable +type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or +lists of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Dictionaries +@docs Dict + +# Build +@docs empty, singleton, insert, update, remove + +# Query +@docs isEmpty, member, get, size + +# Lists +@docs keys, values, toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +# Combine +@docs union, intersect, diff, merge + +-} + + +import Basics exposing (..) +import Maybe exposing (..) +import List exposing (..) +import Native.Debug +import String + + + +-- DICTIONARIES + + +-- BBlack and NBlack should only be used during the deletion +-- algorithm. Any other occurrence is a bug and should fail an assert. +type NColor + = Red + | Black + | BBlack -- Double Black, counts as 2 blacks for the invariant + | NBlack -- Negative Black, counts as -1 blacks for the invariant + + +type LeafColor + = LBlack + | LBBlack -- Double Black, counts as 2 + + +{-| A dictionary of keys and values. So a `(Dict String User)` is a dictionary +that lets you look up a `String` (such as user names) and find the associated +`User`. +-} +type Dict k v + = RBNode_elm_builtin NColor k v (Dict k v) (Dict k v) + | RBEmpty_elm_builtin LeafColor + + +{-| Create an empty dictionary. -} +empty : Dict k v +empty = + RBEmpty_elm_builtin LBlack + + +maxWithDefault : k -> v -> Dict k v -> (k, v) +maxWithDefault k v r = + case r of + RBEmpty_elm_builtin _ -> + (k, v) + + RBNode_elm_builtin _ kr vr _ rr -> + maxWithDefault kr vr rr + + +{-| Get the value associated with a key. If the key is not found, return +`Nothing`. This is useful when you are not sure if a key will be in the +dictionary. + + animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ] + + get "Tom" animals == Just Cat + get "Jerry" animals == Just Mouse + get "Spike" animals == Nothing + +-} +get : comparable -> Dict comparable v -> Maybe v +get targetKey dict = + case dict of + RBEmpty_elm_builtin _ -> + Nothing + + RBNode_elm_builtin _ key value left right -> + case compare targetKey key of + LT -> + get targetKey left + + EQ -> + Just value + + GT -> + get targetKey right + + +{-| Determine if a key is in a dictionary. -} +member : comparable -> Dict comparable v -> Bool +member key dict = + case get key dict of + Just _ -> + True + + Nothing -> + False + + +{-| Determine the number of key-value pairs in the dictionary. -} +size : Dict k v -> Int +size dict = + sizeHelp 0 dict + + +sizeHelp : Int -> Dict k v -> Int +sizeHelp n dict = + case dict of + RBEmpty_elm_builtin _ -> + n + + RBNode_elm_builtin _ _ _ left right -> + sizeHelp (sizeHelp (n+1) right) left + + +{-| Determine if a dictionary is empty. + + isEmpty empty == True +-} +isEmpty : Dict k v -> Bool +isEmpty dict = + dict == empty + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + red node => black node + black node => same + bblack node => xxx + nblack node => xxx + + black leaf => same + bblack leaf => xxx +-} +ensureBlackRoot : Dict k v -> Dict k v +ensureBlackRoot dict = + case dict of + RBNode_elm_builtin Red key value left right -> + RBNode_elm_builtin Black key value left right + + _ -> + dict + + +{-| Insert a key-value pair into a dictionary. Replaces value when there is +a collision. -} +insert : comparable -> v -> Dict comparable v -> Dict comparable v +insert key value dict = + update key (always (Just value)) dict + + +{-| Remove a key-value pair from a dictionary. If the key is not found, +no changes are made. -} +remove : comparable -> Dict comparable v -> Dict comparable v +remove key dict = + update key (always Nothing) dict + + +type Flag = Insert | Remove | Same + + +{-| Update the value of a dictionary for a specific key with a given function. -} +update : comparable -> (Maybe v -> Maybe v) -> Dict comparable v -> Dict comparable v +update k alter dict = + let + up dict = + case dict of + -- expecting only black nodes, never double black nodes here + RBEmpty_elm_builtin _ -> + case alter Nothing of + Nothing -> + (Same, empty) + + Just v -> + (Insert, RBNode_elm_builtin Red k v empty empty) + + RBNode_elm_builtin clr key value left right -> + case compare k key of + EQ -> + case alter (Just value) of + Nothing -> + (Remove, rem clr left right) + + Just newValue -> + (Same, RBNode_elm_builtin clr key newValue left right) + + LT -> + let (flag, newLeft) = up left in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value newLeft right) + + Insert -> + (Insert, balance clr key value newLeft right) + + Remove -> + (Remove, bubble clr key value newLeft right) + + GT -> + let (flag, newRight) = up right in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value left newRight) + + Insert -> + (Insert, balance clr key value left newRight) + + Remove -> + (Remove, bubble clr key value left newRight) + + (flag, updatedDict) = + up dict + in + case flag of + Same -> + updatedDict + + Insert -> + ensureBlackRoot updatedDict + + Remove -> + blacken updatedDict + + +{-| Create a dictionary with one key-value pair. -} +singleton : comparable -> v -> Dict comparable v +singleton key value = + insert key value empty + + + +-- HELPERS + + +isBBlack : Dict k v -> Bool +isBBlack dict = + case dict of + RBNode_elm_builtin BBlack _ _ _ _ -> + True + + RBEmpty_elm_builtin LBBlack -> + True + + _ -> + False + + +moreBlack : NColor -> NColor +moreBlack color = + case color of + Black -> + BBlack + + Red -> + Black + + NBlack -> + Red + + BBlack -> + Native.Debug.crash "Can't make a double black node more black!" + + +lessBlack : NColor -> NColor +lessBlack color = + case color of + BBlack -> + Black + + Black -> + Red + + Red -> + NBlack + + NBlack -> + Native.Debug.crash "Can't make a negative black node less black!" + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + node => less black node + + bblack leaf => black leaf + black leaf => xxx +-} +lessBlackTree : Dict k v -> Dict k v +lessBlackTree dict = + case dict of + RBNode_elm_builtin c k v l r -> + RBNode_elm_builtin (lessBlack c) k v l r + + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + +reportRemBug : String -> NColor -> String -> String -> a +reportRemBug msg c lgot rgot = + Native.Debug.crash <| + String.concat + [ "Internal red-black tree invariant violated, expected " + , msg, " and got ", toString c, "/", lgot, "/", rgot + , "\nPlease report this bug to " + ] + + +-- Remove the top node from the tree, may leave behind BBlacks +rem : NColor -> Dict k v -> Dict k v -> Dict k v +rem color left right = + case (left, right) of + (RBEmpty_elm_builtin _, RBEmpty_elm_builtin _) -> + case color of + Red -> + RBEmpty_elm_builtin LBlack + + Black -> + RBEmpty_elm_builtin LBBlack + + _ -> + Native.Debug.crash "cannot have bblack or nblack nodes at this point" + + (RBEmpty_elm_builtin cl, RBNode_elm_builtin cr k v l r) -> + case (color, cl, cr) of + (Black, LBlack, Red) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/LBlack/Red" color (toString cl) (toString cr) + + (RBNode_elm_builtin cl k v l r, RBEmpty_elm_builtin cr) -> + case (color, cl, cr) of + (Black, Red, LBlack) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/Red/LBlack" color (toString cl) (toString cr) + + -- l and r are both RBNodes + (RBNode_elm_builtin cl kl vl ll rl, RBNode_elm_builtin _ _ _ _ _) -> + let + (k, v) = + maxWithDefault kl vl rl + + newLeft = + removeMax cl kl vl ll rl + in + bubble color k v newLeft right + + +-- Kills a BBlack or moves it upward, may leave behind NBlack +bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +bubble c k v l r = + if isBBlack l || isBBlack r then + balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r) + + else + RBNode_elm_builtin c k v l r + + +-- Removes rightmost node, may leave root as BBlack +removeMax : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +removeMax c k v l r = + case r of + RBEmpty_elm_builtin _ -> + rem c l r + + RBNode_elm_builtin cr kr vr lr rr -> + bubble c k v l (removeMax cr kr vr lr rr) + + +-- generalized tree balancing act +balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +balance c k v l r = + let + tree = + RBNode_elm_builtin c k v l r + in + if blackish tree then + balanceHelp tree + + else + tree + + +blackish : Dict k v -> Bool +blackish t = + case t of + RBNode_elm_builtin c _ _ _ _ -> + c == Black || c == BBlack + + RBEmpty_elm_builtin _ -> + True + + +balanceHelp : Dict k v -> Dict k v +balanceHelp tree = + case tree of + -- double red: left, left + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red yk yv (RBNode_elm_builtin Red xk xv a b) c) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: left, right + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red xk xv a (RBNode_elm_builtin Red yk yv b c)) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, left + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red zk zv (RBNode_elm_builtin Red yk yv b c) d) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, right + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red yk yv b (RBNode_elm_builtin Red zk zv c d)) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- handle double blacks + RBNode_elm_builtin BBlack xk xv a (RBNode_elm_builtin NBlack zk zv (RBNode_elm_builtin Black yk yv b c) (RBNode_elm_builtin Black _ _ _ _ as d)) -> + RBNode_elm_builtin Black yk yv (RBNode_elm_builtin Black xk xv a b) (balance Black zk zv c (redden d)) + + RBNode_elm_builtin BBlack zk zv (RBNode_elm_builtin NBlack xk xv (RBNode_elm_builtin Black _ _ _ _ as a) (RBNode_elm_builtin Black yk yv b c)) d -> + RBNode_elm_builtin Black yk yv (balance Black xk xv (redden a) b) (RBNode_elm_builtin Black zk zv c d) + + _ -> + tree + + +balancedTree : NColor -> k -> v -> k -> v -> k -> v -> Dict k v -> Dict k v -> Dict k v -> Dict k v -> Dict k v +balancedTree col xk xv yk yv zk zv a b c d = + RBNode_elm_builtin + (lessBlack col) + yk + yv + (RBNode_elm_builtin Black xk xv a b) + (RBNode_elm_builtin Black zk zv c d) + + +-- make the top node black +blacken : Dict k v -> Dict k v +blacken t = + case t of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Black k v l r + + +-- make the top node red +redden : Dict k v -> Dict k v +redden t = + case t of + RBEmpty_elm_builtin _ -> + Native.Debug.crash "can't make a Leaf red" + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Red k v l r + + + +-- COMBINE + + +{-| Combine two dictionaries. If there is a collision, preference is given +to the first dictionary. +-} +union : Dict comparable v -> Dict comparable v -> Dict comparable v +union t1 t2 = + foldl insert t2 t1 + + +{-| Keep a key-value pair when its key appears in the second dictionary. +Preference is given to values in the first dictionary. +-} +intersect : Dict comparable v -> Dict comparable v -> Dict comparable v +intersect t1 t2 = + filter (\k _ -> member k t2) t1 + + +{-| Keep a key-value pair when its key does not appear in the second dictionary. +-} +diff : Dict comparable v -> Dict comparable v -> Dict comparable v +diff t1 t2 = + foldl (\k v t -> remove k t) t1 t2 + + +{-| The most general way of combining two dictionaries. You provide three +accumulators for when a given key appears: + + 1. Only in the left dictionary. + 2. In both dictionaries. + 3. Only in the right dictionary. + +You then traverse all the keys from lowest to highest, building up whatever +you want. +-} +merge + : (comparable -> a -> result -> result) + -> (comparable -> a -> b -> result -> result) + -> (comparable -> b -> result -> result) + -> Dict comparable a + -> Dict comparable b + -> result + -> result +merge leftStep bothStep rightStep leftDict rightDict initialResult = + let + stepState rKey rValue (list, result) = + case list of + [] -> + (list, rightStep rKey rValue result) + + (lKey, lValue) :: rest -> + if lKey < rKey then + stepState rKey rValue (rest, leftStep lKey lValue result) + + else if lKey > rKey then + (list, rightStep rKey rValue result) + + else + (rest, bothStep lKey lValue rValue result) + + (leftovers, intermediateResult) = + foldl stepState (toList leftDict, initialResult) rightDict + in + List.foldl (\(k,v) result -> leftStep k v result) intermediateResult leftovers + + + +-- TRANSFORM + + +{-| Apply a function to all values in a dictionary. +-} +map : (comparable -> a -> b) -> Dict comparable a -> Dict comparable b +map f dict = + case dict of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin clr key value left right -> + RBNode_elm_builtin clr key (f key value) (map f left) (map f right) + + +{-| Fold over the key-value pairs in a dictionary, in order from lowest +key to highest key. +-} +foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldl f acc dict = + case dict of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldl f (f key value (foldl f acc left)) right + + +{-| Fold over the key-value pairs in a dictionary, in order from highest +key to lowest key. +-} +foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldr f acc t = + case t of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldr f (f key value (foldr f acc right)) left + + +{-| Keep a key-value pair when it satisfies a predicate. -} +filter : (comparable -> v -> Bool) -> Dict comparable v -> Dict comparable v +filter predicate dictionary = + let + add key value dict = + if predicate key value then + insert key value dict + + else + dict + in + foldl add empty dictionary + + +{-| Partition a dictionary according to a predicate. The first dictionary +contains all key-value pairs which satisfy the predicate, and the second +contains the rest. +-} +partition : (comparable -> v -> Bool) -> Dict comparable v -> (Dict comparable v, Dict comparable v) +partition predicate dict = + let + add key value (t1, t2) = + if predicate key value then + (insert key value t1, t2) + + else + (t1, insert key value t2) + in + foldl add (empty, empty) dict + + + +-- LISTS + + +{-| Get all of the keys in a dictionary, sorted from lowest to highest. + + keys (fromList [(0,"Alice"),(1,"Bob")]) == [0,1] +-} +keys : Dict comparable v -> List comparable +keys dict = + foldr (\key value keyList -> key :: keyList) [] dict + + +{-| Get all of the values in a dictionary, in the order of their keys. + + values (fromList [(0,"Alice"),(1,"Bob")]) == ["Alice", "Bob"] +-} +values : Dict comparable v -> List v +values dict = + foldr (\key value valueList -> value :: valueList) [] dict + + +{-| Convert a dictionary into an association list of key-value pairs, sorted by keys. -} +toList : Dict comparable v -> List (comparable,v) +toList dict = + foldr (\key value list -> (key,value) :: list) [] dict + + +{-| Convert an association list into a dictionary. -} +fromList : List (comparable,v) -> Dict comparable v +fromList assocs = + List.foldl (\(key,value) dict -> insert key value dict) empty assocs diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm new file mode 100644 index 0000000..0fc853d --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm @@ -0,0 +1,520 @@ +module Json.Decode exposing + ( Decoder, string, bool, int, float + , nullable, list, array, dict, keyValuePairs + , field, at, index + , maybe, oneOf + , decodeString, decodeValue, Value + , map, map2, map3, map4, map5, map6, map7, map8 + , lazy, value, null, succeed, fail, andThen + ) + +{-| Turn JSON values into Elm values. Definitely check out this [intro to +JSON decoders][guide] to get a feel for how this library works! + +[guide]: https://guide.elm-lang.org/interop/json.html + +# Primitives +@docs Decoder, string, bool, int, float + +# Data Structures +@docs nullable, list, array, dict, keyValuePairs + +# Object Primitives +@docs field, at, index + +# Inconsistent Structure +@docs maybe, oneOf + +# Run Decoders +@docs decodeString, decodeValue, Value + +# Mapping + +**Note:** If you run out of map functions, take a look at [elm-decode-pipeline][pipe] +which makes it easier to handle large objects, but produces lower quality type +errors. + +[pipe]: http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest + +@docs map, map2, map3, map4, map5, map6, map7, map8 + +# Fancy Decoding +@docs lazy, value, null, succeed, fail, andThen +-} + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Encode as JsEncode +import List +import Maybe exposing (Maybe(..)) +import Result exposing (Result(..)) +import Native.Json + + + +-- PRIMITIVES + + +{-| A value that knows how to decode JSON values. +-} +type Decoder a = Decoder + + +{-| Decode a JSON string into an Elm `String`. + + decodeString string "true" == Err ... + decodeString string "42" == Err ... + decodeString string "3.14" == Err ... + decodeString string "\"hello\"" == Ok "hello" + decodeString string "{ \"hello\": 42 }" == Err ... +-} +string : Decoder String +string = + Native.Json.decodePrimitive "string" + + +{-| Decode a JSON boolean into an Elm `Bool`. + + decodeString bool "true" == Ok True + decodeString bool "42" == Err ... + decodeString bool "3.14" == Err ... + decodeString bool "\"hello\"" == Err ... + decodeString bool "{ \"hello\": 42 }" == Err ... +-} +bool : Decoder Bool +bool = + Native.Json.decodePrimitive "bool" + + +{-| Decode a JSON number into an Elm `Int`. + + decodeString int "true" == Err ... + decodeString int "42" == Ok 42 + decodeString int "3.14" == Err ... + decodeString int "\"hello\"" == Err ... + decodeString int "{ \"hello\": 42 }" == Err ... +-} +int : Decoder Int +int = + Native.Json.decodePrimitive "int" + + +{-| Decode a JSON number into an Elm `Float`. + + decodeString float "true" == Err .. + decodeString float "42" == Ok 42 + decodeString float "3.14" == Ok 3.14 + decodeString float "\"hello\"" == Err ... + decodeString float "{ \"hello\": 42 }" == Err ... +-} +float : Decoder Float +float = + Native.Json.decodePrimitive "float" + + + +-- DATA STRUCTURES + + +{-| Decode a nullable JSON value into an Elm value. + + decodeString (nullable int) "13" == Ok (Just 13) + decodeString (nullable int) "42" == Ok (Just 42) + decodeString (nullable int) "null" == Ok Nothing + decodeString (nullable int) "true" == Err .. +-} +nullable : Decoder a -> Decoder (Maybe a) +nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] + + +{-| Decode a JSON array into an Elm `List`. + + decodeString (list int) "[1,2,3]" == Ok [1,2,3] + decodeString (list bool) "[true,false]" == Ok [True,False] +-} +list : Decoder a -> Decoder (List a) +list decoder = + Native.Json.decodeContainer "list" decoder + + +{-| Decode a JSON array into an Elm `Array`. + + decodeString (array int) "[1,2,3]" == Ok (Array.fromList [1,2,3]) + decodeString (array bool) "[true,false]" == Ok (Array.fromList [True,False]) +-} +array : Decoder a -> Decoder (Array a) +array decoder = + Native.Json.decodeContainer "array" decoder + + +{-| Decode a JSON object into an Elm `Dict`. + + decodeString (dict int) "{ \"alice\": 42, \"bob\": 99 }" + == Dict.fromList [("alice", 42), ("bob", 99)] +-} +dict : Decoder a -> Decoder (Dict String a) +dict decoder = + map Dict.fromList (keyValuePairs decoder) + + +{-| Decode a JSON object into an Elm `List` of pairs. + + decodeString (keyValuePairs int) "{ \"alice\": 42, \"bob\": 99 }" + == [("alice", 42), ("bob", 99)] +-} +keyValuePairs : Decoder a -> Decoder (List (String, a)) +keyValuePairs = + Native.Json.decodeKeyValuePairs + + + +-- OBJECT PRIMITIVES + + +{-| Decode a JSON object, requiring a particular field. + + decodeString (field "x" int) "{ \"x\": 3 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": 3, \"y\": 4 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": true }" == Err ... + decodeString (field "x" int) "{ \"y\": 4 }" == Err ... + + decodeString (field "name" string) "{ \"name\": \"tom\" }" == Ok "tom" + +The object *can* have other fields. Lots of them! The only thing this decoder +cares about is if `x` is present and that the value there is an `Int`. + +Check out [`map2`](#map2) to see how to decode multiple fields! +-} +field : String -> Decoder a -> Decoder a +field = + Native.Json.decodeField + + +{-| Decode a nested JSON object, requiring certain fields. + + json = """{ "person": { "name": "tom", "age": 42 } }""" + + decodeString (at ["person", "name"] string) json == Ok "tom" + decodeString (at ["person", "age" ] int ) json == Ok "42 + +This is really just a shorthand for saying things like: + + field "person" (field "name" string) == at ["person","name"] string +-} +at : List String -> Decoder a -> Decoder a +at fields decoder = + List.foldr field decoder fields + + +{-| Decode a JSON array, requiring a particular index. + + json = """[ "alice", "bob", "chuck" ]""" + + decodeString (index 0 string) json == Ok "alice" + decodeString (index 1 string) json == Ok "bob" + decodeString (index 2 string) json == Ok "chuck" + decodeString (index 3 string) json == Err ... +-} +index : Int -> Decoder a -> Decoder a +index = + Native.Json.decodeIndex + + + +-- WEIRD STRUCTURE + + +{-| Helpful for dealing with optional fields. Here are a few slightly different +examples: + + json = """{ "name": "tom", "age": 42 }""" + + decodeString (maybe (field "age" int )) json == Ok (Just 42) + decodeString (maybe (field "name" int )) json == Ok Nothing + decodeString (maybe (field "height" float)) json == Ok Nothing + + decodeString (field "age" (maybe int )) json == Ok (Just 42) + decodeString (field "name" (maybe int )) json == Ok Nothing + decodeString (field "height" (maybe float)) json == Err ... + +Notice the last example! It is saying we *must* have a field named `height` and +the content *may* be a float. There is no `height` field, so the decoder fails. + +Point is, `maybe` will make exactly what it contains conditional. For optional +fields, this means you probably want it *outside* a use of `field` or `at`. +-} +maybe : Decoder a -> Decoder (Maybe a) +maybe decoder = + Native.Json.decodeContainer "maybe" decoder + + +{-| Try a bunch of different decoders. This can be useful if the JSON may come +in a couple different formats. For example, say you want to read an array of +numbers, but some of them are `null`. + + import String + + badInt : Decoder Int + badInt = + oneOf [ int, null 0 ] + + -- decodeString (list badInt) "[1,2,null,4]" == Ok [1,2,0,4] + +Why would someone generate JSON like this? Questions like this are not good +for your health. The point is that you can use `oneOf` to handle situations +like this! + +You could also use `oneOf` to help version your data. Try the latest format, +then a few older ones that you still support. You could use `andThen` to be +even more particular if you wanted. +-} +oneOf : List (Decoder a) -> Decoder a +oneOf = + Native.Json.oneOf + + + +-- MAPPING + + +{-| Transform a decoder. Maybe you just want to know the length of a string: + + import String + + stringLength : Decoder Int + stringLength = + map String.length string + +It is often helpful to use `map` with `oneOf`, like when defining `nullable`: + + nullable : Decoder a -> Decoder (Maybe a) + nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] +-} +map : (a -> value) -> Decoder a -> Decoder value +map = + Native.Json.map1 + + +{-| Try two decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Point = { x : Float, y : Float } + + point : Decoder Point + point = + map2 Point + (field "x" float) + (field "y" float) + + -- decodeString point """{ "x": 3, "y": 4 }""" == Ok { x = 3, y = 4 } + +It tries each individual decoder and puts the result together with the `Point` +constructor. +-} +map2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value +map2 = + Native.Json.map2 + + +{-| Try three decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Person = { name : String, age : Int, height : Float } + + person : Decoder Person + person = + map3 Person + (at ["name"] string) + (at ["info","age"] int) + (at ["info","height"] float) + + -- json = """{ "name": "tom", "info": { "age": 42, "height": 1.8 } }""" + -- decodeString person json == Ok { name = "tom", age = 42, height = 1.8 } + +Like `map2` it tries each decoder in order and then give the results to the +`Person` constructor. That can be any function though! +-} +map3 : (a -> b -> c -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder value +map3 = + Native.Json.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder value +map4 = + Native.Json.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder value +map5 = + Native.Json.map5 + + +{-|-} +map6 : (a -> b -> c -> d -> e -> f -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder value +map6 = + Native.Json.map6 + + +{-|-} +map7 : (a -> b -> c -> d -> e -> f -> g -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder value +map7 = + Native.Json.map7 + + +{-|-} +map8 : (a -> b -> c -> d -> e -> f -> g -> h -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder h -> Decoder value +map8 = + Native.Json.map8 + + + +-- RUN DECODERS + + +{-| Parse the given string into a JSON value and then run the `Decoder` on it. +This will fail if the string is not well-formed JSON or if the `Decoder` +fails for some reason. + + decodeString int "4" == Ok 4 + decodeString int "1 + 2" == Err ... +-} +decodeString : Decoder a -> String -> Result String a +decodeString = + Native.Json.runOnString + + +{-| Run a `Decoder` on some JSON `Value`. You can send these JSON values +through ports, so that is probably the main time you would use this function. +-} +decodeValue : Decoder a -> Value -> Result String a +decodeValue = + Native.Json.run + + +{-| A JSON value. +-} +type alias Value = JsEncode.Value + + + +-- FANCY PRIMITIVES + + +{-| Ignore the JSON and produce a certain Elm value. + + decodeString (succeed 42) "true" == Ok 42 + decodeString (succeed 42) "[1,2,3]" == Ok 42 + decodeString (succeed 42) "hello" == Err ... -- this is not a valid JSON string + +This is handy when used with `oneOf` or `andThen`. +-} +succeed : a -> Decoder a +succeed = + Native.Json.succeed + + +{-| Ignore the JSON and make the decoder fail. This is handy when used with +`oneOf` or `andThen` where you want to give a custom error message in some +case. + +See the [`andThen`](#andThen) docs for an example. +-} +fail : String -> Decoder a +fail = + Native.Json.fail + + +{-| Create decoders that depend on previous results. If you are creating +versioned data, you might do something like this: + + info : Decoder Info + info = + field "version" int + |> andThen infoHelp + + infoHelp : Int -> Decoder Info + infoHelp version = + case version of + 4 -> + infoDecoder4 + + 3 -> + infoDecoder3 + + _ -> + fail <| + "Trying to decode info, but version " + ++ toString version ++ " is not supported." + + -- infoDecoder4 : Decoder Info + -- infoDecoder3 : Decoder Info +-} +andThen : (a -> Decoder b) -> Decoder a -> Decoder b +andThen = + Native.Json.andThen + + +{-| Sometimes you have JSON with recursive structure, like nested comments. +You can use `lazy` to make sure your decoder unrolls lazily. + + type alias Comment = + { message : String + , responses : Responses + } + + type Responses = Responses (List Comment) + + comment : Decoder Comment + comment = + map2 Comment + (field "message" string) + (field "responses" (map Responses (list (lazy (\_ -> comment))))) + +If we had said `list comment` instead, we would start expanding the value +infinitely. What is a `comment`? It is a decoder for objects where the +`responses` field contains comments. What is a `comment` though? Etc. + +By using `list (lazy (\_ -> comment))` we make sure the decoder only expands +to be as deep as the JSON we are given. You can read more about recursive data +structures [here][]. + +[here]: https://github.com/elm-lang/elm-compiler/blob/master/hints/recursive-alias.md +-} +lazy : (() -> Decoder a) -> Decoder a +lazy thunk = + andThen thunk (succeed ()) + + +{-| Do not do anything with a JSON value, just bring it into Elm as a `Value`. +This can be useful if you have particularly crazy data that you would like to +deal with later. Or if you are going to send it out a port and do not care +about its structure. +-} +value : Decoder Value +value = + Native.Json.decodePrimitive "value" + + +{-| Decode a `null` value into some Elm value. + + decodeString (null False) "null" == Ok False + decodeString (null 42) "null" == Ok 42 + decodeString (null 42) "42" == Err .. + decodeString (null 42) "false" == Err .. + +So if you ever see a `null`, this will return whatever value you specified. +-} +null : a -> Decoder a +null = + Native.Json.decodeNull diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm new file mode 100644 index 0000000..29e6fc9 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm @@ -0,0 +1,102 @@ +module Json.Encode exposing + ( Value + , encode + , string, int, float, bool, null + , list, array + , object + ) + +{-| Library for turning Elm values into Json values. + +# Encoding +@docs encode, Value + +# Primitives +@docs string, int, float, bool, null + +# Arrays +@docs list, array + +# Objects +@docs object +-} + +import Array exposing (Array) +import Native.Json + + +{-| Represents a JavaScript value. +-} +type Value = Value + + +{-| Convert a `Value` into a prettified string. The first argument specifies +the amount of indentation in the resulting string. + + person = + object + [ ("name", string "Tom") + , ("age", int 42) + ] + + compact = encode 0 person + -- {"name":"Tom","age":42} + + readable = encode 4 person + -- { + -- "name": "Tom", + -- "age": 42 + -- } +-} +encode : Int -> Value -> String +encode = + Native.Json.encode + + +{-|-} +string : String -> Value +string = + Native.Json.identity + + +{-|-} +int : Int -> Value +int = + Native.Json.identity + + +{-| Encode a Float. `Infinity` and `NaN` are encoded as `null`. +-} +float : Float -> Value +float = + Native.Json.identity + + +{-|-} +bool : Bool -> Value +bool = + Native.Json.identity + + +{-|-} +null : Value +null = + Native.Json.encodeNull + + +{-|-} +object : List (String, Value) -> Value +object = + Native.Json.encodeObject + + +{-|-} +array : Array Value -> Value +array = + Native.Json.encodeArray + + +{-|-} +list : List Value -> Value +list = + Native.Json.encodeList diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm new file mode 100644 index 0000000..0b7ddf9 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm @@ -0,0 +1,613 @@ +module List exposing + ( isEmpty, length, reverse, member + , head, tail, filter, take, drop + , singleton, repeat, range, (::), append, concat, intersperse + , partition, unzip + , map, map2, map3, map4, map5 + , filterMap, concatMap, indexedMap + , foldr, foldl + , sum, product, maximum, minimum, all, any, scanl + , sort, sortBy, sortWith + ) + +{-| A library for manipulating lists of values. Every value in a +list must have the same type. + +# Basics +@docs isEmpty, length, reverse, member + +# Sub-lists +@docs head, tail, filter, take, drop + +# Putting Lists Together +@docs singleton, repeat, range, (::), append, concat, intersperse + +# Taking Lists Apart +@docs partition, unzip + +# Mapping +@docs map, map2, map3, map4, map5 + +If you can think of a legitimate use of `mapN` where `N` is 6 or more, please +let us know on [the list](https://groups.google.com/forum/#!forum/elm-discuss). +The current sentiment is that it is already quite error prone once you get to +4 and possibly should be approached another way. + +# Special Maps +@docs filterMap, concatMap, indexedMap + +# Folding +@docs foldr, foldl + +# Special Folds +@docs sum, product, maximum, minimum, all, any, scanl + +# Sorting +@docs sort, sortBy, sortWith + +-} + +import Basics exposing (..) +import Maybe +import Maybe exposing ( Maybe(Just,Nothing) ) +import Native.List + + +{-| Add an element to the front of a list. Pronounced *cons*. + + 1 :: [2,3] == [1,2,3] + 1 :: [] == [1] +-} +(::) : a -> List a -> List a +(::) = + Native.List.cons + + +infixr 5 :: + + +{-| Extract the first element of a list. + + head [1,2,3] == Just 1 + head [] == Nothing +-} +head : List a -> Maybe a +head list = + case list of + x :: xs -> + Just x + + [] -> + Nothing + + +{-| Extract the rest of the list. + + tail [1,2,3] == Just [2,3] + tail [] == Nothing +-} +tail : List a -> Maybe (List a) +tail list = + case list of + x :: xs -> + Just xs + + [] -> + Nothing + + +{-| Determine if a list is empty. + + isEmpty [] == True +-} +isEmpty : List a -> Bool +isEmpty xs = + case xs of + [] -> + True + + _ -> + False + + +{-| Figure out whether a list contains a value. + + member 9 [1,2,3,4] == False + member 4 [1,2,3,4] == True +-} +member : a -> List a -> Bool +member x xs = + any (\a -> a == x) xs + + +{-| Apply a function to every element of a list. + + map sqrt [1,4,9] == [1,2,3] + + map not [True,False,True] == [False,True,False] +-} +map : (a -> b) -> List a -> List b +map f xs = + foldr (\x acc -> f x :: acc) [] xs + + +{-| Same as `map` but the function is also applied to the index of each +element (starting at zero). + + indexedMap (,) ["Tom","Sue","Bob"] == [ (0,"Tom"), (1,"Sue"), (2,"Bob") ] +-} +indexedMap : (Int -> a -> b) -> List a -> List b +indexedMap f xs = + map2 f (range 0 (length xs - 1)) xs + + +{-| Reduce a list from the left. + + foldl (::) [] [1,2,3] == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> List a -> b +foldl func acc list = + case list of + [] -> + acc + + x :: xs -> + foldl func (func x acc) xs + + +{-| Reduce a list from the right. + + foldr (+) 0 [1,2,3] == 6 +-} +foldr : (a -> b -> b) -> b -> List a -> b +foldr = + Native.List.foldr + + +{-| Reduce a list from the left, building up all of the intermediate results into a list. + + scanl (+) 0 [1,2,3,4] == [0,1,3,6,10] +-} +scanl : (a -> b -> b) -> b -> List a -> List b +scanl f b xs = + let + scan1 x accAcc = + case accAcc of + acc :: _ -> + f x acc :: accAcc + + [] -> + [] -- impossible + in + reverse (foldl scan1 [b] xs) + + +{-| Keep only elements that satisfy the predicate. + + filter isEven [1,2,3,4,5,6] == [2,4,6] +-} +filter : (a -> Bool) -> List a -> List a +filter pred xs = + let + conditionalCons front back = + if pred front then + front :: back + + else + back + in + foldr conditionalCons [] xs + + +{-| Apply a function that may succeed to all values in the list, but only keep +the successes. + + onlyTeens = + filterMap isTeen [3, 15, 12, 18, 24] == [15, 18] + + isTeen : Int -> Maybe Int + isTeen n = + if 13 <= n && n <= 19 then + Just n + + else + Nothing +-} +filterMap : (a -> Maybe b) -> List a -> List b +filterMap f xs = + foldr (maybeCons f) [] xs + + +maybeCons : (a -> Maybe b) -> a -> List b -> List b +maybeCons f mx xs = + case f mx of + Just x -> + x :: xs + + Nothing -> + xs + + +{-| Determine the length of a list. + + length [1,2,3] == 3 +-} +length : List a -> Int +length xs = + foldl (\_ i -> i + 1) 0 xs + + +{-| Reverse a list. + + reverse [1,2,3,4] == [4,3,2,1] +-} +reverse : List a -> List a +reverse list = + foldl (::) [] list + + +{-| Determine if all elements satisfy the predicate. + + all isEven [2,4] == True + all isEven [2,3] == False + all isEven [] == True +-} +all : (a -> Bool) -> List a -> Bool +all isOkay list = + not (any (not << isOkay) list) + + +{-| Determine if any elements satisfy the predicate. + + any isEven [2,3] == True + any isEven [1,3] == False + any isEven [] == False +-} +any : (a -> Bool) -> List a -> Bool +any isOkay list = + case list of + [] -> + False + + x :: xs -> + -- note: (isOkay x || any isOkay xs) would not get TCO + if isOkay x then + True + + else + any isOkay xs + + +{-| Put two lists together. + + append [1,1,2] [3,5,8] == [1,1,2,3,5,8] + append ['a','b'] ['c'] == ['a','b','c'] + +You can also use [the `(++)` operator](Basics#++) to append lists. +-} +append : List a -> List a -> List a +append xs ys = + case ys of + [] -> + xs + + _ -> + foldr (::) ys xs + + +{-| Concatenate a bunch of lists into a single list: + + concat [[1,2],[3],[4,5]] == [1,2,3,4,5] +-} +concat : List (List a) -> List a +concat lists = + foldr append [] lists + + +{-| Map a given function onto a list and flatten the resulting lists. + + concatMap f xs == concat (map f xs) +-} +concatMap : (a -> List b) -> List a -> List b +concatMap f list = + concat (map f list) + + +{-| Get the sum of the list elements. + + sum [1,2,3,4] == 10 +-} +sum : List number -> number +sum numbers = + foldl (+) 0 numbers + + +{-| Get the product of the list elements. + + product [1,2,3,4] == 24 +-} +product : List number -> number +product numbers = + foldl (*) 1 numbers + + +{-| Find the maximum element in a non-empty list. + + maximum [1,4,2] == Just 4 + maximum [] == Nothing +-} +maximum : List comparable -> Maybe comparable +maximum list = + case list of + x :: xs -> + Just (foldl max x xs) + + _ -> + Nothing + + +{-| Find the minimum element in a non-empty list. + + minimum [3,2,1] == Just 1 + minimum [] == Nothing +-} +minimum : List comparable -> Maybe comparable +minimum list = + case list of + x :: xs -> + Just (foldl min x xs) + + _ -> + Nothing + + +{-| Partition a list based on a predicate. The first list contains all values +that satisfy the predicate, and the second list contains all the value that do +not. + + partition (\x -> x < 3) [0,1,2,3,4,5] == ([0,1,2], [3,4,5]) + partition isEven [0,1,2,3,4,5] == ([0,2,4], [1,3,5]) +-} +partition : (a -> Bool) -> List a -> (List a, List a) +partition pred list = + let + step x (trues, falses) = + if pred x then + (x :: trues, falses) + + else + (trues, x :: falses) + in + foldr step ([],[]) list + + +{-| Combine two lists, combining them with the given function. +If one list is longer, the extra elements are dropped. + + map2 (+) [1,2,3] [1,2,3,4] == [2,4,6] + + map2 (,) [1,2,3] ['a','b'] == [ (1,'a'), (2,'b') ] + + pairs : List a -> List b -> List (a,b) + pairs lefts rights = + map2 (,) lefts rights +-} +map2 : (a -> b -> result) -> List a -> List b -> List result +map2 = + Native.List.map2 + + +{-|-} +map3 : (a -> b -> c -> result) -> List a -> List b -> List c -> List result +map3 = + Native.List.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result +map4 = + Native.List.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result +map5 = + Native.List.map5 + + +{-| Decompose a list of tuples into a tuple of lists. + + unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True]) +-} +unzip : List (a,b) -> (List a, List b) +unzip pairs = + let + step (x,y) (xs,ys) = + (x :: xs, y :: ys) + in + foldr step ([], []) pairs + + +{-| Places the given value between all members of the given list. + + intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"] +-} +intersperse : a -> List a -> List a +intersperse sep xs = + case xs of + [] -> + [] + + hd :: tl -> + let + step x rest = + sep :: x :: rest + + spersed = + foldr step [] tl + in + hd :: spersed + + +{-| Take the first *n* members of a list. + + take 2 [1,2,3,4] == [1,2] +-} +take : Int -> List a -> List a +take n list = + takeFast 0 n list + + +takeFast : Int -> Int -> List a -> List a +takeFast ctr n list = + if n <= 0 then + [] + else + case ( n, list ) of + ( _, [] ) -> + list + + ( 1, x :: _ ) -> + [ x ] + + ( 2, x :: y :: _ ) -> + [ x, y ] + + ( 3, x :: y :: z :: _ ) -> + [ x, y, z ] + + ( _, x :: y :: z :: w :: tl ) -> + if ctr > 1000 then + x :: y :: z :: w :: takeTailRec (n - 4) tl + else + x :: y :: z :: w :: takeFast (ctr + 1) (n - 4) tl + + _ -> + list + +takeTailRec : Int -> List a -> List a +takeTailRec n list = + reverse (takeReverse n list []) + + +takeReverse : Int -> List a -> List a -> List a +takeReverse n list taken = + if n <= 0 then + taken + else + case list of + [] -> + taken + + x :: xs -> + takeReverse (n - 1) xs (x :: taken) + + +{-| Drop the first *n* members of a list. + + drop 2 [1,2,3,4] == [3,4] +-} +drop : Int -> List a -> List a +drop n list = + if n <= 0 then + list + + else + case list of + [] -> + list + + x :: xs -> + drop (n-1) xs + + +{-| Create a list with only one element: + + singleton 1234 == [1234] + singleton "hi" == ["hi"] +-} +singleton : a -> List a +singleton value = + [value] + + +{-| Create a list with *n* copies of a value: + + repeat 3 (0,0) == [(0,0),(0,0),(0,0)] +-} +repeat : Int -> a -> List a +repeat n value = + repeatHelp [] n value + + +repeatHelp : List a -> Int -> a -> List a +repeatHelp result n value = + if n <= 0 then + result + + else + repeatHelp (value :: result) (n-1) value + + +{-| Create a list of numbers, every element increasing by one. +You give the lowest and highest number that should be in the list. + + range 3 6 == [3, 4, 5, 6] + range 3 3 == [3] + range 6 3 == [] +-} +range : Int -> Int -> List Int +range lo hi = + rangeHelp lo hi [] + + +rangeHelp : Int -> Int -> List Int -> List Int +rangeHelp lo hi list = + if lo <= hi then + rangeHelp lo (hi - 1) (hi :: list) + + else + list + + +{-| Sort values from lowest to highest + + sort [3,1,5] == [1,3,5] +-} +sort : List comparable -> List comparable +sort xs = + sortBy identity xs + + +{-| Sort values by a derived property. + + alice = { name="Alice", height=1.62 } + bob = { name="Bob" , height=1.85 } + chuck = { name="Chuck", height=1.76 } + + sortBy .name [chuck,alice,bob] == [alice,bob,chuck] + sortBy .height [chuck,alice,bob] == [alice,chuck,bob] + + sortBy String.length ["mouse","cat"] == ["cat","mouse"] +-} +sortBy : (a -> comparable) -> List a -> List a +sortBy = + Native.List.sortBy + + +{-| Sort values with a custom comparison function. + + sortWith flippedComparison [1,2,3,4,5] == [5,4,3,2,1] + + flippedComparison a b = + case compare a b of + LT -> GT + EQ -> EQ + GT -> LT + +This is also the most general sort function, allowing you +to define any other: `sort == sortWith compare` +-} +sortWith : (a -> a -> Order) -> List a -> List a +sortWith = + Native.List.sortWith diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm new file mode 100644 index 0000000..337a246 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm @@ -0,0 +1,157 @@ +module Maybe exposing + ( Maybe(Just,Nothing) + , andThen + , map, map2, map3, map4, map5 + , withDefault + ) + +{-| This library fills a bunch of important niches in Elm. A `Maybe` can help +you with optional arguments, error handling, and records with optional fields. + +# Definition +@docs Maybe + +# Common Helpers +@docs withDefault, map, map2, map3, map4, map5 + +# Chaining Maybes +@docs andThen +-} + +{-| Represent values that may or may not exist. It can be useful if you have a +record field that is only filled in sometimes. Or if a function takes a value +sometimes, but does not absolutely need it. + + -- A person, but maybe we do not know their age. + type alias Person = + { name : String + , age : Maybe Int + } + + tom = { name = "Tom", age = Just 42 } + sue = { name = "Sue", age = Nothing } +-} +type Maybe a + = Just a + | Nothing + + +{-| Provide a default value, turning an optional value into a normal +value. This comes in handy when paired with functions like +[`Dict.get`](Dict#get) which gives back a `Maybe`. + + withDefault 100 (Just 42) -- 42 + withDefault 100 Nothing -- 100 + + withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" + +-} +withDefault : a -> Maybe a -> a +withDefault default maybe = + case maybe of + Just value -> value + Nothing -> default + + +{-| Transform a `Maybe` value with a given function: + + map sqrt (Just 9) == Just 3 + map sqrt Nothing == Nothing +-} +map : (a -> b) -> Maybe a -> Maybe b +map f maybe = + case maybe of + Just value -> Just (f value) + Nothing -> Nothing + + +{-| Apply a function if all the arguments are `Just` a value. + + map2 (+) (Just 3) (Just 4) == Just 7 + map2 (+) (Just 3) Nothing == Nothing + map2 (+) Nothing (Just 4) == Nothing +-} +map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value +map2 func ma mb = + case (ma,mb) of + (Just a, Just b) -> + Just (func a b) + + _ -> + Nothing + + +{-|-} +map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value +map3 func ma mb mc = + case (ma,mb,mc) of + (Just a, Just b, Just c) -> + Just (func a b c) + + _ -> + Nothing + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value +map4 func ma mb mc md = + case (ma,mb,mc,md) of + (Just a, Just b, Just c, Just d) -> + Just (func a b c d) + + _ -> + Nothing + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value +map5 func ma mb mc md me = + case (ma,mb,mc,md,me) of + (Just a, Just b, Just c, Just d, Just e) -> + Just (func a b c d e) + + _ -> + Nothing + + +{-| Chain together many computations that may fail. It is helpful to see its +definition: + + andThen : (a -> Maybe b) -> Maybe a -> Maybe b + andThen callback maybe = + case maybe of + Just value -> + callback value + + Nothing -> + Nothing + +This means we only continue with the callback if things are going well. For +example, say you need to use (`head : List Int -> Maybe Int`) to get the +first month from a `List` and then make sure it is between 1 and 12: + + toValidMonth : Int -> Maybe Int + toValidMonth month = + if month >= 1 && month <= 12 then + Just month + else + Nothing + + getFirstMonth : List Int -> Maybe Int + getFirstMonth months = + head months + |> andThen toValidMonth + +If `head` fails and results in `Nothing` (because the `List` was `empty`), +this entire chain of operations will short-circuit and result in `Nothing`. +If `toValidMonth` results in `Nothing`, again the chain of computations +will result in `Nothing`. +-} +andThen : (a -> Maybe b) -> Maybe a -> Maybe b +andThen callback maybeValue = + case maybeValue of + Just value -> + callback value + + Nothing -> + Nothing diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js new file mode 100644 index 0000000..7ddd42d --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js @@ -0,0 +1,967 @@ +//import Native.List // + +var _elm_lang$core$Native_Array = function() { + +// A RRB-Tree has two distinct data types. +// Leaf -> "height" is always 0 +// "table" is an array of elements +// Node -> "height" is always greater than 0 +// "table" is an array of child nodes +// "lengths" is an array of accumulated lengths of the child nodes + +// M is the maximal table size. 32 seems fast. E is the allowed increase +// of search steps when concatting to find an index. Lower values will +// decrease balancing, but will increase search steps. +var M = 32; +var E = 2; + +// An empty array. +var empty = { + ctor: '_Array', + height: 0, + table: [] +}; + + +function get(i, array) +{ + if (i < 0 || i >= length(array)) + { + throw new Error( + 'Index ' + i + ' is out of range. Check the length of ' + + 'your array first or use getMaybe or getWithDefault.'); + } + return unsafeGet(i, array); +} + + +function unsafeGet(i, array) +{ + for (var x = array.height; x > 0; x--) + { + var slot = i >> (x * 5); + while (array.lengths[slot] <= i) + { + slot++; + } + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array = array.table[slot]; + } + return array.table[i]; +} + + +// Sets the value at the index i. Only the nodes leading to i will get +// copied and updated. +function set(i, item, array) +{ + if (i < 0 || length(array) <= i) + { + return array; + } + return unsafeSet(i, item, array); +} + + +function unsafeSet(i, item, array) +{ + array = nodeCopy(array); + + if (array.height === 0) + { + array.table[i] = item; + } + else + { + var slot = getSlot(i, array); + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array.table[slot] = unsafeSet(i, item, array.table[slot]); + } + return array; +} + + +function initialize(len, f) +{ + if (len <= 0) + { + return empty; + } + var h = Math.floor( Math.log(len) / Math.log(M) ); + return initialize_(f, h, 0, len); +} + +function initialize_(f, h, from, to) +{ + if (h === 0) + { + var table = new Array((to - from) % (M + 1)); + for (var i = 0; i < table.length; i++) + { + table[i] = f(from + i); + } + return { + ctor: '_Array', + height: 0, + table: table + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = initialize_(f, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +function fromList(list) +{ + if (list.ctor === '[]') + { + return empty; + } + + // Allocate M sized blocks (table) and write list elements to it. + var table = new Array(M); + var nodes = []; + var i = 0; + + while (list.ctor !== '[]') + { + table[i] = list._0; + list = list._1; + i++; + + // table is full, so we can push a leaf containing it into the + // next node. + if (i === M) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table + }; + fromListPush(leaf, nodes); + table = new Array(M); + i = 0; + } + } + + // Maybe there is something left on the table. + if (i > 0) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table.splice(0, i) + }; + fromListPush(leaf, nodes); + } + + // Go through all of the nodes and eventually push them into higher nodes. + for (var h = 0; h < nodes.length - 1; h++) + { + if (nodes[h].table.length > 0) + { + fromListPush(nodes[h], nodes); + } + } + + var head = nodes[nodes.length - 1]; + if (head.height > 0 && head.table.length === 1) + { + return head.table[0]; + } + else + { + return head; + } +} + +// Push a node into a higher node as a child. +function fromListPush(toPush, nodes) +{ + var h = toPush.height; + + // Maybe the node on this height does not exist. + if (nodes.length === h) + { + var node = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + nodes.push(node); + } + + nodes[h].table.push(toPush); + var len = length(toPush); + if (nodes[h].lengths.length > 0) + { + len += nodes[h].lengths[nodes[h].lengths.length - 1]; + } + nodes[h].lengths.push(len); + + if (nodes[h].table.length === M) + { + fromListPush(nodes[h], nodes); + nodes[h] = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + } +} + +// Pushes an item via push_ to the bottom right of a tree. +function push(item, a) +{ + var pushed = push_(item, a); + if (pushed !== null) + { + return pushed; + } + + var newTree = create(item, a.height); + return siblise(a, newTree); +} + +// Recursively tries to push an item to the bottom-right most +// tree possible. If there is no space left for the item, +// null will be returned. +function push_(item, a) +{ + // Handle resursion stop at leaf level. + if (a.height === 0) + { + if (a.table.length < M) + { + var newA = { + ctor: '_Array', + height: 0, + table: a.table.slice() + }; + newA.table.push(item); + return newA; + } + else + { + return null; + } + } + + // Recursively push + var pushed = push_(item, botRight(a)); + + // There was space in the bottom right tree, so the slot will + // be updated. + if (pushed !== null) + { + var newA = nodeCopy(a); + newA.table[newA.table.length - 1] = pushed; + newA.lengths[newA.lengths.length - 1]++; + return newA; + } + + // When there was no space left, check if there is space left + // for a new slot with a tree which contains only the item + // at the bottom. + if (a.table.length < M) + { + var newSlot = create(item, a.height - 1); + var newA = nodeCopy(a); + newA.table.push(newSlot); + newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot)); + return newA; + } + else + { + return null; + } +} + +// Converts an array into a list of elements. +function toList(a) +{ + return toList_(_elm_lang$core$Native_List.Nil, a); +} + +function toList_(list, a) +{ + for (var i = a.table.length - 1; i >= 0; i--) + { + list = + a.height === 0 + ? _elm_lang$core$Native_List.Cons(a.table[i], list) + : toList_(list, a.table[i]); + } + return list; +} + +// Maps a function over the elements of an array. +function map(f, a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? f(a.table[i]) + : map(f, a.table[i]); + } + return newA; +} + +// Maps a function over the elements with their index as first argument. +function indexedMap(f, a) +{ + return indexedMap_(f, a, 0); +} + +function indexedMap_(f, a, from) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? A2(f, from + i, a.table[i]) + : indexedMap_(f, a.table[i], i == 0 ? from : from + a.lengths[i - 1]); + } + return newA; +} + +function foldl(f, b, a) +{ + if (a.height === 0) + { + for (var i = 0; i < a.table.length; i++) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = 0; i < a.table.length; i++) + { + b = foldl(f, b, a.table[i]); + } + } + return b; +} + +function foldr(f, b, a) +{ + if (a.height === 0) + { + for (var i = a.table.length; i--; ) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = a.table.length; i--; ) + { + b = foldr(f, b, a.table[i]); + } + } + return b; +} + +// TODO: currently, it slices the right, then the left. This can be +// optimized. +function slice(from, to, a) +{ + if (from < 0) + { + from += length(a); + } + if (to < 0) + { + to += length(a); + } + return sliceLeft(from, sliceRight(to, a)); +} + +function sliceRight(to, a) +{ + if (to === length(a)) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(0, to); + return newA; + } + + // Slice the right recursively. + var right = getSlot(to, a); + var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (right === 0) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(0, right), + lengths: a.lengths.slice(0, right) + }; + if (sliced.table.length > 0) + { + newA.table[right] = sliced; + newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0); + } + return newA; +} + +function sliceLeft(from, a) +{ + if (from === 0) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(from, a.table.length + 1); + return newA; + } + + // Slice the left recursively. + var left = getSlot(from, a); + var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (left === a.table.length - 1) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(left, a.table.length + 1), + lengths: new Array(a.table.length - left) + }; + newA.table[0] = sliced; + var len = 0; + for (var i = 0; i < newA.table.length; i++) + { + len += length(newA.table[i]); + newA.lengths[i] = len; + } + + return newA; +} + +// Appends two trees. +function append(a,b) +{ + if (a.table.length === 0) + { + return b; + } + if (b.table.length === 0) + { + return a; + } + + var c = append_(a, b); + + // Check if both nodes can be crunshed together. + if (c[0].table.length + c[1].table.length <= M) + { + if (c[0].table.length === 0) + { + return c[1]; + } + if (c[1].table.length === 0) + { + return c[0]; + } + + // Adjust .table and .lengths + c[0].table = c[0].table.concat(c[1].table); + if (c[0].height > 0) + { + var len = length(c[0]); + for (var i = 0; i < c[1].lengths.length; i++) + { + c[1].lengths[i] += len; + } + c[0].lengths = c[0].lengths.concat(c[1].lengths); + } + + return c[0]; + } + + if (c[0].height > 0) + { + var toRemove = calcToRemove(a, b); + if (toRemove > E) + { + c = shuffle(c[0], c[1], toRemove); + } + } + + return siblise(c[0], c[1]); +} + +// Returns an array of two nodes; right and left. One node _may_ be empty. +function append_(a, b) +{ + if (a.height === 0 && b.height === 0) + { + return [a, b]; + } + + if (a.height !== 1 || b.height !== 1) + { + if (a.height === b.height) + { + a = nodeCopy(a); + b = nodeCopy(b); + var appended = append_(botRight(a), botLeft(b)); + + insertRight(a, appended[1]); + insertLeft(b, appended[0]); + } + else if (a.height > b.height) + { + a = nodeCopy(a); + var appended = append_(botRight(a), b); + + insertRight(a, appended[0]); + b = parentise(appended[1], appended[1].height + 1); + } + else + { + b = nodeCopy(b); + var appended = append_(a, botLeft(b)); + + var left = appended[0].table.length === 0 ? 0 : 1; + var right = left === 0 ? 1 : 0; + insertLeft(b, appended[left]); + a = parentise(appended[right], appended[right].height + 1); + } + } + + // Check if balancing is needed and return based on that. + if (a.table.length === 0 || b.table.length === 0) + { + return [a, b]; + } + + var toRemove = calcToRemove(a, b); + if (toRemove <= E) + { + return [a, b]; + } + return shuffle(a, b, toRemove); +} + +// Helperfunctions for append_. Replaces a child node at the side of the parent. +function insertRight(parent, node) +{ + var index = parent.table.length - 1; + parent.table[index] = node; + parent.lengths[index] = length(node); + parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0; +} + +function insertLeft(parent, node) +{ + if (node.table.length > 0) + { + parent.table[0] = node; + parent.lengths[0] = length(node); + + var len = length(parent.table[0]); + for (var i = 1; i < parent.lengths.length; i++) + { + len += length(parent.table[i]); + parent.lengths[i] = len; + } + } + else + { + parent.table.shift(); + for (var i = 1; i < parent.lengths.length; i++) + { + parent.lengths[i] = parent.lengths[i] - parent.lengths[0]; + } + parent.lengths.shift(); + } +} + +// Returns the extra search steps for E. Refer to the paper. +function calcToRemove(a, b) +{ + var subLengths = 0; + for (var i = 0; i < a.table.length; i++) + { + subLengths += a.table[i].table.length; + } + for (var i = 0; i < b.table.length; i++) + { + subLengths += b.table[i].table.length; + } + + var toRemove = a.table.length + b.table.length; + return toRemove - (Math.floor((subLengths - 1) / M) + 1); +} + +// get2, set2 and saveSlot are helpers for accessing elements over two arrays. +function get2(a, b, index) +{ + return index < a.length + ? a[index] + : b[index - a.length]; +} + +function set2(a, b, index, value) +{ + if (index < a.length) + { + a[index] = value; + } + else + { + b[index - a.length] = value; + } +} + +function saveSlot(a, b, index, slot) +{ + set2(a.table, b.table, index, slot); + + var l = (index === 0 || index === a.lengths.length) + ? 0 + : get2(a.lengths, a.lengths, index - 1); + + set2(a.lengths, b.lengths, index, l + length(slot)); +} + +// Creates a node or leaf with a given length at their arrays for perfomance. +// Is only used by shuffle. +function createNode(h, length) +{ + if (length < 0) + { + length = 0; + } + var a = { + ctor: '_Array', + height: h, + table: new Array(length) + }; + if (h > 0) + { + a.lengths = new Array(length); + } + return a; +} + +// Returns an array of two balanced nodes. +function shuffle(a, b, toRemove) +{ + var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove)); + var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove)); + + // Skip the slots with size M. More precise: copy the slot references + // to the new node + var read = 0; + while (get2(a.table, b.table, read).table.length % M === 0) + { + set2(newA.table, newB.table, read, get2(a.table, b.table, read)); + set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read)); + read++; + } + + // Pulling items from left to right, caching in a slot before writing + // it into the new nodes. + var write = read; + var slot = new createNode(a.height - 1, 0); + var from = 0; + + // If the current slot is still containing data, then there will be at + // least one more write, so we do not break this loop yet. + while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) + { + // Find out the max possible items for copying. + var source = get2(a.table, b.table, read); + var to = Math.min(M - slot.table.length, source.table.length); + + // Copy and adjust size table. + slot.table = slot.table.concat(source.table.slice(from, to)); + if (slot.height > 0) + { + var len = slot.lengths.length; + for (var i = len; i < len + to - from; i++) + { + slot.lengths[i] = length(slot.table[i]); + slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0); + } + } + + from += to; + + // Only proceed to next slots[i] if the current one was + // fully copied. + if (source.table.length <= to) + { + read++; from = 0; + } + + // Only create a new slot if the current one is filled up. + if (slot.table.length === M) + { + saveSlot(newA, newB, write, slot); + slot = createNode(a.height - 1, 0); + write++; + } + } + + // Cleanup after the loop. Copy the last slot into the new nodes. + if (slot.table.length > 0) + { + saveSlot(newA, newB, write, slot); + write++; + } + + // Shift the untouched slots to the left + while (read < a.table.length + b.table.length ) + { + saveSlot(newA, newB, write, get2(a.table, b.table, read)); + read++; + write++; + } + + return [newA, newB]; +} + +// Navigation functions +function botRight(a) +{ + return a.table[a.table.length - 1]; +} +function botLeft(a) +{ + return a.table[0]; +} + +// Copies a node for updating. Note that you should not use this if +// only updating only one of "table" or "lengths" for performance reasons. +function nodeCopy(a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice() + }; + if (a.height > 0) + { + newA.lengths = a.lengths.slice(); + } + return newA; +} + +// Returns how many items are in the tree. +function length(array) +{ + if (array.height === 0) + { + return array.table.length; + } + else + { + return array.lengths[array.lengths.length - 1]; + } +} + +// Calculates in which slot of "table" the item probably is, then +// find the exact slot via forward searching in "lengths". Returns the index. +function getSlot(i, a) +{ + var slot = i >> (5 * a.height); + while (a.lengths[slot] <= i) + { + slot++; + } + return slot; +} + +// Recursively creates a tree with a given height containing +// only the given item. +function create(item, h) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: [item] + }; + } + return { + ctor: '_Array', + height: h, + table: [create(item, h - 1)], + lengths: [1] + }; +} + +// Recursively creates a tree that contains the given tree. +function parentise(tree, h) +{ + if (h === tree.height) + { + return tree; + } + + return { + ctor: '_Array', + height: h, + table: [parentise(tree, h - 1)], + lengths: [length(tree)] + }; +} + +// Emphasizes blood brotherhood beneath two trees. +function siblise(a, b) +{ + return { + ctor: '_Array', + height: a.height + 1, + table: [a, b], + lengths: [length(a), length(a) + length(b)] + }; +} + +function toJSArray(a) +{ + var jsArray = new Array(length(a)); + toJSArray_(jsArray, 0, a); + return jsArray; +} + +function toJSArray_(jsArray, i, a) +{ + for (var t = 0; t < a.table.length; t++) + { + if (a.height === 0) + { + jsArray[i + t] = a.table[t]; + } + else + { + var inc = t === 0 ? 0 : a.lengths[t - 1]; + toJSArray_(jsArray, i + inc, a.table[t]); + } + } +} + +function fromJSArray(jsArray) +{ + if (jsArray.length === 0) + { + return empty; + } + var h = Math.floor(Math.log(jsArray.length) / Math.log(M)); + return fromJSArray_(jsArray, h, 0, jsArray.length); +} + +function fromJSArray_(jsArray, h, from, to) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: jsArray.slice(from, to) + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = fromJSArray_(jsArray, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i - 1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +return { + empty: empty, + fromList: fromList, + toList: toList, + initialize: F2(initialize), + append: F2(append), + push: F2(push), + slice: F3(slice), + get: F2(get), + set: F3(set), + map: F2(map), + indexedMap: F2(indexedMap), + foldl: F3(foldl), + foldr: F3(foldr), + length: length, + + toJSArray: toJSArray, + fromJSArray: fromJSArray +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js new file mode 100644 index 0000000..1d97bf3 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js @@ -0,0 +1,141 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Basics = function() { + +function div(a, b) +{ + return (a / b) | 0; +} +function rem(a, b) +{ + return a % b; +} +function mod(a, b) +{ + if (b === 0) + { + throw new Error('Cannot perform mod 0. Division by zero error.'); + } + var r = a % b; + var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r + b) : -mod(-a, -b)); + + return m === b ? 0 : m; +} +function logBase(base, n) +{ + return Math.log(n) / Math.log(base); +} +function negate(n) +{ + return -n; +} +function abs(n) +{ + return n < 0 ? -n : n; +} + +function min(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) < 0 ? a : b; +} +function max(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) > 0 ? a : b; +} +function clamp(lo, hi, n) +{ + return _elm_lang$core$Native_Utils.cmp(n, lo) < 0 + ? lo + : _elm_lang$core$Native_Utils.cmp(n, hi) > 0 + ? hi + : n; +} + +var ord = ['LT', 'EQ', 'GT']; + +function compare(x, y) +{ + return { ctor: ord[_elm_lang$core$Native_Utils.cmp(x, y) + 1] }; +} + +function xor(a, b) +{ + return a !== b; +} +function not(b) +{ + return !b; +} +function isInfinite(n) +{ + return n === Infinity || n === -Infinity; +} + +function truncate(n) +{ + return n | 0; +} + +function degrees(d) +{ + return d * Math.PI / 180; +} +function turns(t) +{ + return 2 * Math.PI * t; +} +function fromPolar(point) +{ + var r = point._0; + var t = point._1; + return _elm_lang$core$Native_Utils.Tuple2(r * Math.cos(t), r * Math.sin(t)); +} +function toPolar(point) +{ + var x = point._0; + var y = point._1; + return _elm_lang$core$Native_Utils.Tuple2(Math.sqrt(x * x + y * y), Math.atan2(y, x)); +} + +return { + div: F2(div), + rem: F2(rem), + mod: F2(mod), + + pi: Math.PI, + e: Math.E, + cos: Math.cos, + sin: Math.sin, + tan: Math.tan, + acos: Math.acos, + asin: Math.asin, + atan: Math.atan, + atan2: F2(Math.atan2), + + degrees: degrees, + turns: turns, + fromPolar: fromPolar, + toPolar: toPolar, + + sqrt: Math.sqrt, + logBase: F2(logBase), + negate: negate, + abs: abs, + min: F2(min), + max: F2(max), + clamp: F3(clamp), + compare: F2(compare), + + xor: F2(xor), + not: not, + + truncate: truncate, + ceiling: Math.ceil, + floor: Math.floor, + round: Math.round, + toFloat: function(x) { return x; }, + isNaN: isNaN, + isInfinite: isInfinite +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js new file mode 100644 index 0000000..a597f82 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js @@ -0,0 +1,13 @@ +var _elm_lang$core$Native_Bitwise = function() { + +return { + and: F2(function and(a, b) { return a & b; }), + or: F2(function or(a, b) { return a | b; }), + xor: F2(function xor(a, b) { return a ^ b; }), + complement: function complement(a) { return ~a; }, + shiftLeftBy: F2(function(offset, a) { return a << offset; }), + shiftRightBy: F2(function(offset, a) { return a >> offset; }), + shiftRightZfBy: F2(function(offset, a) { return a >>> offset; }) +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js new file mode 100644 index 0000000..56c2957 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js @@ -0,0 +1,14 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Char = function() { + +return { + fromCode: function(c) { return _elm_lang$core$Native_Utils.chr(String.fromCharCode(c)); }, + toCode: function(c) { return c.charCodeAt(0); }, + toUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toUpperCase()); }, + toLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLowerCase()); }, + toLocaleUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleUpperCase()); }, + toLocaleLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleLowerCase()); } +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js new file mode 100644 index 0000000..cb64193 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js @@ -0,0 +1,33 @@ +//import Result // + +var _elm_lang$core$Native_Date = function() { + +function fromString(str) +{ + var date = new Date(str); + return isNaN(date.getTime()) + ? _elm_lang$core$Result$Err('Unable to parse \'' + str + '\' as a date. Dates must be in the ISO 8601 format.') + : _elm_lang$core$Result$Ok(date); +} + +var dayTable = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; +var monthTable = + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + +return { + fromString: fromString, + year: function(d) { return d.getFullYear(); }, + month: function(d) { return { ctor: monthTable[d.getMonth()] }; }, + day: function(d) { return d.getDate(); }, + hour: function(d) { return d.getHours(); }, + minute: function(d) { return d.getMinutes(); }, + second: function(d) { return d.getSeconds(); }, + millisecond: function(d) { return d.getMilliseconds(); }, + toTime: function(d) { return d.getTime(); }, + fromTime: function(t) { return new Date(t); }, + dayOfWeek: function(d) { return { ctor: dayTable[d.getDay()] }; } +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js new file mode 100644 index 0000000..15ce1dc --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js @@ -0,0 +1,30 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Debug = function() { + +function log(tag, value) +{ + var msg = tag + ': ' + _elm_lang$core$Native_Utils.toString(value); + var process = process || {}; + if (process.stdout) + { + process.stdout.write(msg); + } + else + { + console.log(msg); + } + return value; +} + +function crash(message) +{ + throw new Error(message); +} + +return { + crash: crash, + log: F2(log) +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js new file mode 100644 index 0000000..61df889 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js @@ -0,0 +1,575 @@ +//import Maybe, Native.Array, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_Json = function() { + + +// CORE DECODERS + +function succeed(msg) +{ + return { + ctor: '', + tag: 'succeed', + msg: msg + }; +} + +function fail(msg) +{ + return { + ctor: '', + tag: 'fail', + msg: msg + }; +} + +function decodePrimitive(tag) +{ + return { + ctor: '', + tag: tag + }; +} + +function decodeContainer(tag, decoder) +{ + return { + ctor: '', + tag: tag, + decoder: decoder + }; +} + +function decodeNull(value) +{ + return { + ctor: '', + tag: 'null', + value: value + }; +} + +function decodeField(field, decoder) +{ + return { + ctor: '', + tag: 'field', + field: field, + decoder: decoder + }; +} + +function decodeIndex(index, decoder) +{ + return { + ctor: '', + tag: 'index', + index: index, + decoder: decoder + }; +} + +function decodeKeyValuePairs(decoder) +{ + return { + ctor: '', + tag: 'key-value', + decoder: decoder + }; +} + +function mapMany(f, decoders) +{ + return { + ctor: '', + tag: 'map-many', + func: f, + decoders: decoders + }; +} + +function andThen(callback, decoder) +{ + return { + ctor: '', + tag: 'andThen', + decoder: decoder, + callback: callback + }; +} + +function oneOf(decoders) +{ + return { + ctor: '', + tag: 'oneOf', + decoders: decoders + }; +} + + +// DECODING OBJECTS + +function map1(f, d1) +{ + return mapMany(f, [d1]); +} + +function map2(f, d1, d2) +{ + return mapMany(f, [d1, d2]); +} + +function map3(f, d1, d2, d3) +{ + return mapMany(f, [d1, d2, d3]); +} + +function map4(f, d1, d2, d3, d4) +{ + return mapMany(f, [d1, d2, d3, d4]); +} + +function map5(f, d1, d2, d3, d4, d5) +{ + return mapMany(f, [d1, d2, d3, d4, d5]); +} + +function map6(f, d1, d2, d3, d4, d5, d6) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6]); +} + +function map7(f, d1, d2, d3, d4, d5, d6, d7) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7]); +} + +function map8(f, d1, d2, d3, d4, d5, d6, d7, d8) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7, d8]); +} + + +// DECODE HELPERS + +function ok(value) +{ + return { tag: 'ok', value: value }; +} + +function badPrimitive(type, value) +{ + return { tag: 'primitive', type: type, value: value }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badField(field, nestedProblems) +{ + return { tag: 'field', field: field, rest: nestedProblems }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badOneOf(problems) +{ + return { tag: 'oneOf', problems: problems }; +} + +function bad(msg) +{ + return { tag: 'fail', msg: msg }; +} + +function badToString(problem) +{ + var context = '_'; + while (problem) + { + switch (problem.tag) + { + case 'primitive': + return 'Expecting ' + problem.type + + (context === '_' ? '' : ' at ' + context) + + ' but instead got: ' + jsToString(problem.value); + + case 'index': + context += '[' + problem.index + ']'; + problem = problem.rest; + break; + + case 'field': + context += '.' + problem.field; + problem = problem.rest; + break; + + case 'oneOf': + var problems = problem.problems; + for (var i = 0; i < problems.length; i++) + { + problems[i] = badToString(problems[i]); + } + return 'I ran into the following problems' + + (context === '_' ? '' : ' at ' + context) + + ':\n\n' + problems.join('\n'); + + case 'fail': + return 'I ran into a `fail` decoder' + + (context === '_' ? '' : ' at ' + context) + + ': ' + problem.msg; + } + } +} + +function jsToString(value) +{ + return value === undefined + ? 'undefined' + : JSON.stringify(value); +} + + +// DECODE + +function runOnString(decoder, string) +{ + var json; + try + { + json = JSON.parse(string); + } + catch (e) + { + return _elm_lang$core$Result$Err('Given an invalid JSON: ' + e.message); + } + return run(decoder, json); +} + +function run(decoder, value) +{ + var result = runHelp(decoder, value); + return (result.tag === 'ok') + ? _elm_lang$core$Result$Ok(result.value) + : _elm_lang$core$Result$Err(badToString(result)); +} + +function runHelp(decoder, value) +{ + switch (decoder.tag) + { + case 'bool': + return (typeof value === 'boolean') + ? ok(value) + : badPrimitive('a Bool', value); + + case 'int': + if (typeof value !== 'number') { + return badPrimitive('an Int', value); + } + + if (-2147483647 < value && value < 2147483647 && (value | 0) === value) { + return ok(value); + } + + if (isFinite(value) && !(value % 1)) { + return ok(value); + } + + return badPrimitive('an Int', value); + + case 'float': + return (typeof value === 'number') + ? ok(value) + : badPrimitive('a Float', value); + + case 'string': + return (typeof value === 'string') + ? ok(value) + : (value instanceof String) + ? ok(value + '') + : badPrimitive('a String', value); + + case 'null': + return (value === null) + ? ok(decoder.value) + : badPrimitive('null', value); + + case 'value': + return ok(value); + + case 'list': + if (!(value instanceof Array)) + { + return badPrimitive('a List', value); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i = value.length; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result) + } + list = _elm_lang$core$Native_List.Cons(result.value, list); + } + return ok(list); + + case 'array': + if (!(value instanceof Array)) + { + return badPrimitive('an Array', value); + } + + var len = value.length; + var array = new Array(len); + for (var i = len; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result); + } + array[i] = result.value; + } + return ok(_elm_lang$core$Native_Array.fromJSArray(array)); + + case 'maybe': + var result = runHelp(decoder.decoder, value); + return (result.tag === 'ok') + ? ok(_elm_lang$core$Maybe$Just(result.value)) + : ok(_elm_lang$core$Maybe$Nothing); + + case 'field': + var field = decoder.field; + if (typeof value !== 'object' || value === null || !(field in value)) + { + return badPrimitive('an object with a field named `' + field + '`', value); + } + + var result = runHelp(decoder.decoder, value[field]); + return (result.tag === 'ok') ? result : badField(field, result); + + case 'index': + var index = decoder.index; + if (!(value instanceof Array)) + { + return badPrimitive('an array', value); + } + if (index >= value.length) + { + return badPrimitive('a longer array. Need index ' + index + ' but there are only ' + value.length + ' entries', value); + } + + var result = runHelp(decoder.decoder, value[index]); + return (result.tag === 'ok') ? result : badIndex(index, result); + + case 'key-value': + if (typeof value !== 'object' || value === null || value instanceof Array) + { + return badPrimitive('an object', value); + } + + var keyValuePairs = _elm_lang$core$Native_List.Nil; + for (var key in value) + { + var result = runHelp(decoder.decoder, value[key]); + if (result.tag !== 'ok') + { + return badField(key, result); + } + var pair = _elm_lang$core$Native_Utils.Tuple2(key, result.value); + keyValuePairs = _elm_lang$core$Native_List.Cons(pair, keyValuePairs); + } + return ok(keyValuePairs); + + case 'map-many': + var answer = decoder.func; + var decoders = decoder.decoders; + for (var i = 0; i < decoders.length; i++) + { + var result = runHelp(decoders[i], value); + if (result.tag !== 'ok') + { + return result; + } + answer = answer(result.value); + } + return ok(answer); + + case 'andThen': + var result = runHelp(decoder.decoder, value); + return (result.tag !== 'ok') + ? result + : runHelp(decoder.callback(result.value), value); + + case 'oneOf': + var errors = []; + var temp = decoder.decoders; + while (temp.ctor !== '[]') + { + var result = runHelp(temp._0, value); + + if (result.tag === 'ok') + { + return result; + } + + errors.push(result); + + temp = temp._1; + } + return badOneOf(errors); + + case 'fail': + return bad(decoder.msg); + + case 'succeed': + return ok(decoder.msg); + } +} + + +// EQUALITY + +function equality(a, b) +{ + if (a === b) + { + return true; + } + + if (a.tag !== b.tag) + { + return false; + } + + switch (a.tag) + { + case 'succeed': + case 'fail': + return a.msg === b.msg; + + case 'bool': + case 'int': + case 'float': + case 'string': + case 'value': + return true; + + case 'null': + return a.value === b.value; + + case 'list': + case 'array': + case 'maybe': + case 'key-value': + return equality(a.decoder, b.decoder); + + case 'field': + return a.field === b.field && equality(a.decoder, b.decoder); + + case 'index': + return a.index === b.index && equality(a.decoder, b.decoder); + + case 'map-many': + if (a.func !== b.func) + { + return false; + } + return listEquality(a.decoders, b.decoders); + + case 'andThen': + return a.callback === b.callback && equality(a.decoder, b.decoder); + + case 'oneOf': + return listEquality(a.decoders, b.decoders); + } +} + +function listEquality(aDecoders, bDecoders) +{ + var len = aDecoders.length; + if (len !== bDecoders.length) + { + return false; + } + for (var i = 0; i < len; i++) + { + if (!equality(aDecoders[i], bDecoders[i])) + { + return false; + } + } + return true; +} + + +// ENCODE + +function encode(indentLevel, value) +{ + return JSON.stringify(value, null, indentLevel); +} + +function identity(value) +{ + return value; +} + +function encodeObject(keyValuePairs) +{ + var obj = {}; + while (keyValuePairs.ctor !== '[]') + { + var pair = keyValuePairs._0; + obj[pair._0] = pair._1; + keyValuePairs = keyValuePairs._1; + } + return obj; +} + +return { + encode: F2(encode), + runOnString: F2(runOnString), + run: F2(run), + + decodeNull: decodeNull, + decodePrimitive: decodePrimitive, + decodeContainer: F2(decodeContainer), + + decodeField: F2(decodeField), + decodeIndex: F2(decodeIndex), + + map1: F2(map1), + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + map6: F7(map6), + map7: F8(map7), + map8: F9(map8), + decodeKeyValuePairs: decodeKeyValuePairs, + + andThen: F2(andThen), + fail: fail, + succeed: succeed, + oneOf: oneOf, + + identity: identity, + encodeNull: null, + encodeArray: _elm_lang$core$Native_Array.toJSArray, + encodeList: _elm_lang$core$Native_List.toArray, + encodeObject: encodeObject, + + equality: equality +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js new file mode 100644 index 0000000..ccefb9c --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js @@ -0,0 +1,137 @@ +//import Native.Utils // + +var _elm_lang$core$Native_List = function() { + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { ctor: '::', _0: hd, _1: tl }; +} + +function fromArray(arr) +{ + var out = Nil; + for (var i = arr.length; i--; ) + { + out = Cons(arr[i], out); + } + return out; +} + +function toArray(xs) +{ + var out = []; + while (xs.ctor !== '[]') + { + out.push(xs._0); + xs = xs._1; + } + return out; +} + +function foldr(f, b, xs) +{ + var arr = toArray(xs); + var acc = b; + for (var i = arr.length; i--; ) + { + acc = A2(f, arr[i], acc); + } + return acc; +} + +function map2(f, xs, ys) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]') + { + arr.push(A2(f, xs._0, ys._0)); + xs = xs._1; + ys = ys._1; + } + return fromArray(arr); +} + +function map3(f, xs, ys, zs) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]' && zs.ctor !== '[]') + { + arr.push(A3(f, xs._0, ys._0, zs._0)); + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map4(f, ws, xs, ys, zs) +{ + var arr = []; + while ( ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A4(f, ws._0, xs._0, ys._0, zs._0)); + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map5(f, vs, ws, xs, ys, zs) +{ + var arr = []; + while ( vs.ctor !== '[]' + && ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A5(f, vs._0, ws._0, xs._0, ys._0, zs._0)); + vs = vs._1; + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function sortBy(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + return _elm_lang$core$Native_Utils.cmp(f(a), f(b)); + })); +} + +function sortWith(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + var ord = f(a)(b).ctor; + return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1; + })); +} + +return { + Nil: Nil, + Cons: Cons, + cons: F2(Cons), + toArray: toArray, + fromArray: fromArray, + + foldr: F3(foldr), + + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + sortBy: F2(sortBy), + sortWith: F2(sortWith) +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js new file mode 100644 index 0000000..bd6da19 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js @@ -0,0 +1,559 @@ +//import // + +var _elm_lang$core$Native_Platform = function() { + + +// PROGRAMS + +function program(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flags !== 'undefined') + { + throw new Error( + 'The `' + moduleName + '` module does not need flags.\n' + + 'Call ' + moduleName + '.worker() with no arguments and you should be all set!' + ); + } + + return initialize( + impl.init, + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function programWithFlags(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flagDecoder === 'undefined') + { + throw new Error( + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + ); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Err') + { + throw new Error( + moduleName + '.worker(...) was called with an unexpected argument.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0 + ); + } + + return initialize( + impl.init(result._0), + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function renderer(enqueue, _) +{ + return function(_) {}; +} + + +// HTML TO PROGRAM + +function htmlToProgram(vnode) +{ + var emptyBag = batch(_elm_lang$core$Native_List.Nil); + var noChange = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + emptyBag + ); + + return _elm_lang$virtual_dom$VirtualDom$program({ + init: noChange, + view: function(model) { return main; }, + update: F2(function(msg, model) { return noChange; }), + subscriptions: function (model) { return emptyBag; } + }); +} + + +// INITIALIZE A PROGRAM + +function initialize(init, update, subscriptions, renderer) +{ + // ambient state + var managers = {}; + var updateView; + + // init and update state in main process + var initApp = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var model = init._0; + updateView = renderer(enqueue, model); + var cmds = init._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + + function onMessage(msg, model) + { + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var results = A2(update, msg, model); + model = results._0; + updateView(model); + var cmds = results._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + } + + var mainProcess = spawnLoop(initApp, onMessage); + + function enqueue(msg) + { + _elm_lang$core$Native_Scheduler.rawSend(mainProcess, msg); + } + + var ports = setupEffects(managers, enqueue); + + return ports ? { ports: ports } : {}; +} + + +// EFFECT MANAGERS + +var effectManagers = {}; + +function setupEffects(managers, callback) +{ + var ports; + + // setup all necessary effect managers + for (var key in effectManagers) + { + var manager = effectManagers[key]; + + if (manager.isForeign) + { + ports = ports || {}; + ports[key] = manager.tag === 'cmd' + ? setupOutgoingPort(key) + : setupIncomingPort(key, callback); + } + + managers[key] = makeManager(manager, callback); + } + + return ports; +} + +function makeManager(info, callback) +{ + var router = { + main: callback, + self: undefined + }; + + var tag = info.tag; + var onEffects = info.onEffects; + var onSelfMsg = info.onSelfMsg; + + function onMessage(msg, state) + { + if (msg.ctor === 'self') + { + return A3(onSelfMsg, router, msg._0, state); + } + + var fx = msg._0; + switch (tag) + { + case 'cmd': + return A3(onEffects, router, fx.cmds, state); + + case 'sub': + return A3(onEffects, router, fx.subs, state); + + case 'fx': + return A4(onEffects, router, fx.cmds, fx.subs, state); + } + } + + var process = spawnLoop(info.init, onMessage); + router.self = process; + return process; +} + +function sendToApp(router, msg) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + router.main(msg); + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sendToSelf(router, msg) +{ + return A2(_elm_lang$core$Native_Scheduler.send, router.self, { + ctor: 'self', + _0: msg + }); +} + + +// HELPER for STATEFUL LOOPS + +function spawnLoop(init, onMessage) +{ + var andThen = _elm_lang$core$Native_Scheduler.andThen; + + function loop(state) + { + var handleMsg = _elm_lang$core$Native_Scheduler.receive(function(msg) { + return onMessage(msg, state); + }); + return A2(andThen, loop, handleMsg); + } + + var task = A2(andThen, loop, init); + + return _elm_lang$core$Native_Scheduler.rawSpawn(task); +} + + +// BAGS + +function leaf(home) +{ + return function(value) + { + return { + type: 'leaf', + home: home, + value: value + }; + }; +} + +function batch(list) +{ + return { + type: 'node', + branches: list + }; +} + +function map(tagger, bag) +{ + return { + type: 'map', + tagger: tagger, + tree: bag + } +} + + +// PIPE BAGS INTO EFFECT MANAGERS + +function dispatchEffects(managers, cmdBag, subBag) +{ + var effectsDict = {}; + gatherEffects(true, cmdBag, effectsDict, null); + gatherEffects(false, subBag, effectsDict, null); + + for (var home in managers) + { + var fx = home in effectsDict + ? effectsDict[home] + : { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + + _elm_lang$core$Native_Scheduler.rawSend(managers[home], { ctor: 'fx', _0: fx }); + } +} + +function gatherEffects(isCmd, bag, effectsDict, taggers) +{ + switch (bag.type) + { + case 'leaf': + var home = bag.home; + var effect = toEffect(isCmd, home, taggers, bag.value); + effectsDict[home] = insert(isCmd, effect, effectsDict[home]); + return; + + case 'node': + var list = bag.branches; + while (list.ctor !== '[]') + { + gatherEffects(isCmd, list._0, effectsDict, taggers); + list = list._1; + } + return; + + case 'map': + gatherEffects(isCmd, bag.tree, effectsDict, { + tagger: bag.tagger, + rest: taggers + }); + return; + } +} + +function toEffect(isCmd, home, taggers, value) +{ + function applyTaggers(x) + { + var temp = taggers; + while (temp) + { + x = temp.tagger(x); + temp = temp.rest; + } + return x; + } + + var map = isCmd + ? effectManagers[home].cmdMap + : effectManagers[home].subMap; + + return A2(map, applyTaggers, value) +} + +function insert(isCmd, newEffect, effects) +{ + effects = effects || { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + if (isCmd) + { + effects.cmds = _elm_lang$core$Native_List.Cons(newEffect, effects.cmds); + return effects; + } + effects.subs = _elm_lang$core$Native_List.Cons(newEffect, effects.subs); + return effects; +} + + +// PORTS + +function checkPortName(name) +{ + if (name in effectManagers) + { + throw new Error('There can only be one port named `' + name + '`, but your program has multiple.'); + } +} + + +// OUTGOING PORTS + +function outgoingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'cmd', + cmdMap: outgoingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var outgoingPortMap = F2(function cmdMap(tagger, value) { + return value; +}); + +function setupOutgoingPort(name) +{ + var subs = []; + var converter = effectManagers[name].converter; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function onEffects(router, cmdList, state) + { + while (cmdList.ctor !== '[]') + { + // grab a separate reference to subs in case unsubscribe is called + var currentSubs = subs; + var value = converter(cmdList._0); + for (var i = 0; i < currentSubs.length; i++) + { + currentSubs[i](value); + } + cmdList = cmdList._1; + } + return init; + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function subscribe(callback) + { + subs.push(callback); + } + + function unsubscribe(callback) + { + // copy subs into a new array in case unsubscribe is called within a + // subscribed callback + subs = subs.slice(); + var index = subs.indexOf(callback); + if (index >= 0) + { + subs.splice(index, 1); + } + } + + return { + subscribe: subscribe, + unsubscribe: unsubscribe + }; +} + + +// INCOMING PORTS + +function incomingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'sub', + subMap: incomingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var incomingPortMap = F2(function subMap(tagger, finalTagger) +{ + return function(value) + { + return tagger(finalTagger(value)); + }; +}); + +function setupIncomingPort(name, callback) +{ + var sentBeforeInit = []; + var subs = _elm_lang$core$Native_List.Nil; + var converter = effectManagers[name].converter; + var currentOnEffects = preInitOnEffects; + var currentSend = preInitSend; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function preInitOnEffects(router, subList, state) + { + var postInitResult = postInitOnEffects(router, subList, state); + + for(var i = 0; i < sentBeforeInit.length; i++) + { + postInitSend(sentBeforeInit[i]); + } + + sentBeforeInit = null; // to release objects held in queue + currentSend = postInitSend; + currentOnEffects = postInitOnEffects; + return postInitResult; + } + + function postInitOnEffects(router, subList, state) + { + subs = subList; + return init; + } + + function onEffects(router, subList, state) + { + return currentOnEffects(router, subList, state); + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function preInitSend(value) + { + sentBeforeInit.push(value); + } + + function postInitSend(value) + { + var temp = subs; + while (temp.ctor !== '[]') + { + callback(temp._0(value)); + temp = temp._1; + } + } + + function send(incomingValue) + { + var result = A2(_elm_lang$core$Json_Decode$decodeValue, converter, incomingValue); + if (result.ctor === 'Err') + { + throw new Error('Trying to send an unexpected type of value through port `' + name + '`:\n' + result._0); + } + + currentSend(result._0); + } + + return { send: send }; +} + +return { + // routers + sendToApp: F2(sendToApp), + sendToSelf: F2(sendToSelf), + + // global setup + effectManagers: effectManagers, + outgoingPort: outgoingPort, + incomingPort: incomingPort, + + htmlToProgram: htmlToProgram, + program: program, + programWithFlags: programWithFlags, + initialize: initialize, + + // effect bags + leaf: leaf, + batch: batch, + map: F2(map) +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js new file mode 100644 index 0000000..d3cc0dd --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js @@ -0,0 +1,119 @@ +//import Maybe, Native.List // + +var _elm_lang$core$Native_Regex = function() { + +function escape(str) +{ + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +} +function caseInsensitive(re) +{ + return new RegExp(re.source, 'gi'); +} +function regex(raw) +{ + return new RegExp(raw, 'g'); +} + +function contains(re, string) +{ + return string.match(re) !== null; +} + +function find(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var out = []; + var number = 0; + var string = str; + var lastIndex = re.lastIndex; + var prevLastIndex = -1; + var result; + while (number++ < n && (result = re.exec(string))) + { + if (prevLastIndex === re.lastIndex) break; + var i = result.length - 1; + var subs = new Array(i); + while (i > 0) + { + var submatch = result[i]; + subs[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + out.push({ + match: result[0], + submatches: _elm_lang$core$Native_List.fromArray(subs), + index: result.index, + number: number + }); + prevLastIndex = re.lastIndex; + } + re.lastIndex = lastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +function replace(n, re, replacer, string) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var count = 0; + function jsReplacer(match) + { + if (count++ >= n) + { + return match; + } + var i = arguments.length - 3; + var submatches = new Array(i); + while (i > 0) + { + var submatch = arguments[i]; + submatches[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + return replacer({ + match: match, + submatches: _elm_lang$core$Native_List.fromArray(submatches), + index: arguments[arguments.length - 2], + number: count + }); + } + return string.replace(re, jsReplacer); +} + +function split(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + if (n === Infinity) + { + return _elm_lang$core$Native_List.fromArray(str.split(re)); + } + var string = str; + var result; + var out = []; + var start = re.lastIndex; + var restoreLastIndex = re.lastIndex; + while (n--) + { + if (!(result = re.exec(string))) break; + out.push(string.slice(start, result.index)); + start = re.lastIndex; + } + out.push(string.slice(start)); + re.lastIndex = restoreLastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +return { + regex: regex, + caseInsensitive: caseInsensitive, + escape: escape, + + contains: F2(contains), + find: F3(find), + replace: F4(replace), + split: F3(split) +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js new file mode 100644 index 0000000..00f8259 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js @@ -0,0 +1,281 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Scheduler = function() { + +var MAX_STEPS = 10000; + + +// TASKS + +function succeed(value) +{ + return { + ctor: '_Task_succeed', + value: value + }; +} + +function fail(error) +{ + return { + ctor: '_Task_fail', + value: error + }; +} + +function nativeBinding(callback) +{ + return { + ctor: '_Task_nativeBinding', + callback: callback, + cancel: null + }; +} + +function andThen(callback, task) +{ + return { + ctor: '_Task_andThen', + callback: callback, + task: task + }; +} + +function onError(callback, task) +{ + return { + ctor: '_Task_onError', + callback: callback, + task: task + }; +} + +function receive(callback) +{ + return { + ctor: '_Task_receive', + callback: callback + }; +} + + +// PROCESSES + +function rawSpawn(task) +{ + var process = { + ctor: '_Process', + id: _elm_lang$core$Native_Utils.guid(), + root: task, + stack: null, + mailbox: [] + }; + + enqueue(process); + + return process; +} + +function spawn(task) +{ + return nativeBinding(function(callback) { + var process = rawSpawn(task); + callback(succeed(process)); + }); +} + +function rawSend(process, msg) +{ + process.mailbox.push(msg); + enqueue(process); +} + +function send(process, msg) +{ + return nativeBinding(function(callback) { + rawSend(process, msg); + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function kill(process) +{ + return nativeBinding(function(callback) { + var root = process.root; + if (root.ctor === '_Task_nativeBinding' && root.cancel) + { + root.cancel(); + } + + process.root = null; + + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sleep(time) +{ + return nativeBinding(function(callback) { + var id = setTimeout(function() { + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }, time); + + return function() { clearTimeout(id); }; + }); +} + + +// STEP PROCESSES + +function step(numSteps, process) +{ + while (numSteps < MAX_STEPS) + { + var ctor = process.root.ctor; + + if (ctor === '_Task_succeed') + { + while (process.stack && process.stack.ctor === '_Task_onError') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_fail') + { + while (process.stack && process.stack.ctor === '_Task_andThen') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_andThen') + { + process.stack = { + ctor: '_Task_andThen', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_onError') + { + process.stack = { + ctor: '_Task_onError', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_nativeBinding') + { + process.root.cancel = process.root.callback(function(newRoot) { + process.root = newRoot; + enqueue(process); + }); + + break; + } + + if (ctor === '_Task_receive') + { + var mailbox = process.mailbox; + if (mailbox.length === 0) + { + break; + } + + process.root = process.root.callback(mailbox.shift()); + ++numSteps; + continue; + } + + throw new Error(ctor); + } + + if (numSteps < MAX_STEPS) + { + return numSteps + 1; + } + enqueue(process); + + return numSteps; +} + + +// WORK QUEUE + +var working = false; +var workQueue = []; + +function enqueue(process) +{ + workQueue.push(process); + + if (!working) + { + setTimeout(work, 0); + working = true; + } +} + +function work() +{ + var numSteps = 0; + var process; + while (numSteps < MAX_STEPS && (process = workQueue.shift())) + { + if (process.root) + { + numSteps = step(numSteps, process); + } + } + if (!process) + { + working = false; + return; + } + setTimeout(work, 0); +} + + +return { + succeed: succeed, + fail: fail, + nativeBinding: nativeBinding, + andThen: F2(andThen), + onError: F2(onError), + receive: receive, + + spawn: spawn, + kill: kill, + sleep: sleep, + send: F2(send), + + rawSpawn: rawSpawn, + rawSend: rawSend +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js new file mode 100644 index 0000000..3a21c76 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js @@ -0,0 +1,339 @@ +//import Maybe, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_String = function() { + +function isEmpty(str) +{ + return str.length === 0; +} +function cons(chr, str) +{ + return chr + str; +} +function uncons(str) +{ + var hd = str[0]; + if (hd) + { + return _elm_lang$core$Maybe$Just(_elm_lang$core$Native_Utils.Tuple2(_elm_lang$core$Native_Utils.chr(hd), str.slice(1))); + } + return _elm_lang$core$Maybe$Nothing; +} +function append(a, b) +{ + return a + b; +} +function concat(strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(''); +} +function length(str) +{ + return str.length; +} +function map(f, str) +{ + var out = str.split(''); + for (var i = out.length; i--; ) + { + out[i] = f(_elm_lang$core$Native_Utils.chr(out[i])); + } + return out.join(''); +} +function filter(pred, str) +{ + return str.split('').map(_elm_lang$core$Native_Utils.chr).filter(pred).join(''); +} +function reverse(str) +{ + return str.split('').reverse().join(''); +} +function foldl(f, b, str) +{ + var len = str.length; + for (var i = 0; i < len; ++i) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function foldr(f, b, str) +{ + for (var i = str.length; i--; ) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function split(sep, str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(sep)); +} +function join(sep, strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(sep); +} +function repeat(n, str) +{ + var result = ''; + while (n > 0) + { + if (n & 1) + { + result += str; + } + n >>= 1, str += str; + } + return result; +} +function slice(start, end, str) +{ + return str.slice(start, end); +} +function left(n, str) +{ + return n < 1 ? '' : str.slice(0, n); +} +function right(n, str) +{ + return n < 1 ? '' : str.slice(-n); +} +function dropLeft(n, str) +{ + return n < 1 ? str : str.slice(n); +} +function dropRight(n, str) +{ + return n < 1 ? str : str.slice(0, -n); +} +function pad(n, chr, str) +{ + var half = (n - str.length) / 2; + return repeat(Math.ceil(half), chr) + str + repeat(half | 0, chr); +} +function padRight(n, chr, str) +{ + return str + repeat(n - str.length, chr); +} +function padLeft(n, chr, str) +{ + return repeat(n - str.length, chr) + str; +} + +function trim(str) +{ + return str.trim(); +} +function trimLeft(str) +{ + return str.replace(/^\s+/, ''); +} +function trimRight(str) +{ + return str.replace(/\s+$/, ''); +} + +function words(str) +{ + return _elm_lang$core$Native_List.fromArray(str.trim().split(/\s+/g)); +} +function lines(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(/\r\n|\r|\n/g)); +} + +function toUpper(str) +{ + return str.toUpperCase(); +} +function toLower(str) +{ + return str.toLowerCase(); +} + +function any(pred, str) +{ + for (var i = str.length; i--; ) + { + if (pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return true; + } + } + return false; +} +function all(pred, str) +{ + for (var i = str.length; i--; ) + { + if (!pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return false; + } + } + return true; +} + +function contains(sub, str) +{ + return str.indexOf(sub) > -1; +} +function startsWith(sub, str) +{ + return str.indexOf(sub) === 0; +} +function endsWith(sub, str) +{ + return str.length >= sub.length && + str.lastIndexOf(sub) === str.length - sub.length; +} +function indexes(sub, str) +{ + var subLen = sub.length; + + if (subLen < 1) + { + return _elm_lang$core$Native_List.Nil; + } + + var i = 0; + var is = []; + + while ((i = str.indexOf(sub, i)) > -1) + { + is.push(i); + i = i + subLen; + } + + return _elm_lang$core$Native_List.fromArray(is); +} + + +function toInt(s) +{ + var len = s.length; + + // if empty + if (len === 0) + { + return intErr(s); + } + + // if hex + var c = s[0]; + if (c === '0' && s[1] === 'x') + { + for (var i = 2; i < len; ++i) + { + var c = s[i]; + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) + { + continue; + } + return intErr(s); + } + return _elm_lang$core$Result$Ok(parseInt(s, 16)); + } + + // is decimal + if (c > '9' || (c < '0' && c !== '-' && c !== '+')) + { + return intErr(s); + } + for (var i = 1; i < len; ++i) + { + var c = s[i]; + if (c < '0' || '9' < c) + { + return intErr(s); + } + } + + return _elm_lang$core$Result$Ok(parseInt(s, 10)); +} + +function intErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to an Int"); +} + + +function toFloat(s) +{ + // check if it is a hex, octal, or binary number + if (s.length === 0 || /[\sxbo]/.test(s)) + { + return floatErr(s); + } + var n = +s; + // faster isNaN check + return n === n ? _elm_lang$core$Result$Ok(n) : floatErr(s); +} + +function floatErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to a Float"); +} + + +function toList(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split('').map(_elm_lang$core$Native_Utils.chr)); +} +function fromList(chars) +{ + return _elm_lang$core$Native_List.toArray(chars).join(''); +} + +return { + isEmpty: isEmpty, + cons: F2(cons), + uncons: uncons, + append: F2(append), + concat: concat, + length: length, + map: F2(map), + filter: F2(filter), + reverse: reverse, + foldl: F3(foldl), + foldr: F3(foldr), + + split: F2(split), + join: F2(join), + repeat: F2(repeat), + + slice: F3(slice), + left: F2(left), + right: F2(right), + dropLeft: F2(dropLeft), + dropRight: F2(dropRight), + + pad: F3(pad), + padLeft: F3(padLeft), + padRight: F3(padRight), + + trim: trim, + trimLeft: trimLeft, + trimRight: trimRight, + + words: words, + lines: lines, + + toUpper: toUpper, + toLower: toLower, + + any: F2(any), + all: F2(all), + + contains: F2(contains), + startsWith: F2(startsWith), + endsWith: F2(endsWith), + indexes: F2(indexes), + + toInt: toInt, + toFloat: toFloat, + toList: toList, + fromList: fromList +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js new file mode 100644 index 0000000..6b665ea --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js @@ -0,0 +1,27 @@ +//import Native.Scheduler // + +var _elm_lang$core$Native_Time = function() { + +var now = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + callback(_elm_lang$core$Native_Scheduler.succeed(Date.now())); +}); + +function setInterval_(interval, task) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var id = setInterval(function() { + _elm_lang$core$Native_Scheduler.rawSpawn(task); + }, interval); + + return function() { clearInterval(id); }; + }); +} + +return { + now: now, + setInterval_: F2(setInterval_) +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js new file mode 100644 index 0000000..20aed5f --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js @@ -0,0 +1,488 @@ +//import // + +var _elm_lang$core$Native_Utils = function() { + +// COMPARISONS + +function eq(x, y) +{ + var stack = []; + var isEqual = eqHelp(x, y, 0, stack); + var pair; + while (isEqual && (pair = stack.pop())) + { + isEqual = eqHelp(pair.x, pair.y, 0, stack); + } + return isEqual; +} + + +function eqHelp(x, y, depth, stack) +{ + if (depth > 100) + { + stack.push({ x: x, y: y }); + return true; + } + + if (x === y) + { + return true; + } + + if (typeof x !== 'object') + { + if (typeof x === 'function') + { + throw new Error( + 'Trying to use `(==)` on functions. There is no way to know if functions are "the same" in the Elm sense.' + + ' Read more about this at http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#==' + + ' which describes why it is this way and what the better version will look like.' + ); + } + return false; + } + + if (x === null || y === null) + { + return false + } + + if (x instanceof Date) + { + return x.getTime() === y.getTime(); + } + + if (!('ctor' in x)) + { + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; + } + + // convert Dicts and Sets to lists + if (x.ctor === 'RBNode_elm_builtin' || x.ctor === 'RBEmpty_elm_builtin') + { + x = _elm_lang$core$Dict$toList(x); + y = _elm_lang$core$Dict$toList(y); + } + if (x.ctor === 'Set_elm_builtin') + { + x = _elm_lang$core$Set$toList(x); + y = _elm_lang$core$Set$toList(y); + } + + // check if lists are equal without recursion + if (x.ctor === '::') + { + var a = x; + var b = y; + while (a.ctor === '::' && b.ctor === '::') + { + if (!eqHelp(a._0, b._0, depth + 1, stack)) + { + return false; + } + a = a._1; + b = b._1; + } + return a.ctor === b.ctor; + } + + // check if Arrays are equal + if (x.ctor === '_Array') + { + var xs = _elm_lang$core$Native_Array.toJSArray(x); + var ys = _elm_lang$core$Native_Array.toJSArray(y); + if (xs.length !== ys.length) + { + return false; + } + for (var i = 0; i < xs.length; i++) + { + if (!eqHelp(xs[i], ys[i], depth + 1, stack)) + { + return false; + } + } + return true; + } + + if (!eqHelp(x.ctor, y.ctor, depth + 1, stack)) + { + return false; + } + + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; +} + +// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on +// the particular integer values assigned to LT, EQ, and GT. + +var LT = -1, EQ = 0, GT = 1; + +function cmp(x, y) +{ + if (typeof x !== 'object') + { + return x === y ? EQ : x < y ? LT : GT; + } + + if (x instanceof String) + { + var a = x.valueOf(); + var b = y.valueOf(); + return a === b ? EQ : a < b ? LT : GT; + } + + if (x.ctor === '::' || x.ctor === '[]') + { + while (x.ctor === '::' && y.ctor === '::') + { + var ord = cmp(x._0, y._0); + if (ord !== EQ) + { + return ord; + } + x = x._1; + y = y._1; + } + return x.ctor === y.ctor ? EQ : x.ctor === '[]' ? LT : GT; + } + + if (x.ctor.slice(0, 6) === '_Tuple') + { + var ord; + var n = x.ctor.slice(6) - 0; + var err = 'cannot compare tuples with more than 6 elements.'; + if (n === 0) return EQ; + if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord; + if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord; + if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord; + if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord; + if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord; + if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord; + if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } } + return EQ; + } + + throw new Error( + 'Comparison error: comparison is only defined on ints, ' + + 'floats, times, chars, strings, lists of comparable values, ' + + 'and tuples of comparable values.' + ); +} + + +// COMMON VALUES + +var Tuple0 = { + ctor: '_Tuple0' +}; + +function Tuple2(x, y) +{ + return { + ctor: '_Tuple2', + _0: x, + _1: y + }; +} + +function chr(c) +{ + return new String(c); +} + + +// GUID + +var count = 0; +function guid(_) +{ + return count++; +} + + +// RECORDS + +function update(oldRecord, updatedFields) +{ + var newRecord = {}; + + for (var key in oldRecord) + { + newRecord[key] = oldRecord[key]; + } + + for (var key in updatedFields) + { + newRecord[key] = updatedFields[key]; + } + + return newRecord; +} + + +//// LIST STUFF //// + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { + ctor: '::', + _0: hd, + _1: tl + }; +} + +function append(xs, ys) +{ + // append Strings + if (typeof xs === 'string') + { + return xs + ys; + } + + // append Lists + if (xs.ctor === '[]') + { + return ys; + } + var root = Cons(xs._0, Nil); + var curr = root; + xs = xs._1; + while (xs.ctor !== '[]') + { + curr._1 = Cons(xs._0, Nil); + xs = xs._1; + curr = curr._1; + } + curr._1 = ys; + return root; +} + + +// CRASHES + +function crash(moduleName, region) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '` ' + regionToString(region) + '\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function crashCase(moduleName, region, value) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '`\n\n' + + 'This was caused by the `case` expression ' + regionToString(region) + '.\n' + + 'One of the branches ended with a crash and the following value got through:\n\n ' + toString(value) + '\n\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function regionToString(region) +{ + if (region.start.line == region.end.line) + { + return 'on line ' + region.start.line; + } + return 'between lines ' + region.start.line + ' and ' + region.end.line; +} + + +// TO STRING + +function toString(v) +{ + var type = typeof v; + if (type === 'function') + { + return ''; + } + + if (type === 'boolean') + { + return v ? 'True' : 'False'; + } + + if (type === 'number') + { + return v + ''; + } + + if (v instanceof String) + { + return '\'' + addSlashes(v, true) + '\''; + } + + if (type === 'string') + { + return '"' + addSlashes(v, false) + '"'; + } + + if (v === null) + { + return 'null'; + } + + if (type === 'object' && 'ctor' in v) + { + var ctorStarter = v.ctor.substring(0, 5); + + if (ctorStarter === '_Tupl') + { + var output = []; + for (var k in v) + { + if (k === 'ctor') continue; + output.push(toString(v[k])); + } + return '(' + output.join(',') + ')'; + } + + if (ctorStarter === '_Task') + { + return '' + } + + if (v.ctor === '_Array') + { + var list = _elm_lang$core$Array$toList(v); + return 'Array.fromList ' + toString(list); + } + + if (v.ctor === '') + { + return ''; + } + + if (v.ctor === '_Process') + { + return ''; + } + + if (v.ctor === '::') + { + var output = '[' + toString(v._0); + v = v._1; + while (v.ctor === '::') + { + output += ',' + toString(v._0); + v = v._1; + } + return output + ']'; + } + + if (v.ctor === '[]') + { + return '[]'; + } + + if (v.ctor === 'Set_elm_builtin') + { + return 'Set.fromList ' + toString(_elm_lang$core$Set$toList(v)); + } + + if (v.ctor === 'RBNode_elm_builtin' || v.ctor === 'RBEmpty_elm_builtin') + { + return 'Dict.fromList ' + toString(_elm_lang$core$Dict$toList(v)); + } + + var output = ''; + for (var i in v) + { + if (i === 'ctor') continue; + var str = toString(v[i]); + var c0 = str[0]; + var parenless = c0 === '{' || c0 === '(' || c0 === '<' || c0 === '"' || str.indexOf(' ') < 0; + output += ' ' + (parenless ? str : '(' + str + ')'); + } + return v.ctor + output; + } + + if (type === 'object') + { + if (v instanceof Date) + { + return '<' + v.toString() + '>'; + } + + if (v.elm_web_socket) + { + return ''; + } + + var output = []; + for (var k in v) + { + output.push(k + ' = ' + toString(v[k])); + } + if (output.length === 0) + { + return '{}'; + } + return '{ ' + output.join(', ') + ' }'; + } + + return ''; +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + eq: eq, + cmp: cmp, + Tuple0: Tuple0, + Tuple2: Tuple2, + chr: chr, + update: update, + guid: guid, + + append: F2(append), + + crash: crash, + crashCase: crashCase, + + toString: toString +}; + +}(); \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm new file mode 100644 index 0000000..2a136cc --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm @@ -0,0 +1,145 @@ +module Platform exposing + ( Program, program, programWithFlags + , Task, ProcessId + , Router, sendToApp, sendToSelf + ) + +{-| + +# Programs +@docs Program, program, programWithFlags + +# Platform Internals + +## Tasks and Processes +@docs Task, ProcessId + +## Effect Manager Helpers + +An extremely tiny portion of library authors should ever write effect managers. +Fundamentally, Elm needs maybe 10 of them total. I get that people are smart, +curious, etc. but that is not a substitute for a legitimate reason to make an +effect manager. Do you have an *organic need* this fills? Or are you just +curious? Public discussions of your explorations should be framed accordingly. + +@docs Router, sendToApp, sendToSelf +-} + +import Basics exposing (Never) +import Native.Platform +import Native.Scheduler +import Platform.Cmd exposing (Cmd) +import Platform.Sub exposing (Sub) + + + +-- PROGRAMS + + +{-| A `Program` describes how to manage your Elm app. + +You can create [headless][] programs with the [`program`](#program) and +[`programWithFlags`](#programWithFlags) functions. Similar functions exist in +[`Html`][html] that let you specify a view. + +[headless]: https://en.wikipedia.org/wiki/Headless_software +[html]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html + +Honestly, it is totally normal if this seems crazy at first. The best way to +understand is to work through [guide.elm-lang.org](http://guide.elm-lang.org/). +It makes way more sense in context! +-} +type Program flags model msg = Program + + +{-| Create a [headless][] program. This is great if you want to use Elm as the +“brain” for something else. You can still communicate with JS via +ports and manage your model, you just do not have to specify a `view`. + +[headless]: https://en.wikipedia.org/wiki/Headless_software + +Initializing a headless program from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker(); +``` +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program Never model msg +program = + Native.Platform.program + + +{-| Same as [`program`](#program), but you can provide flags. Initializing a +headless program (with flags) from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker({ user: 'Tom', token: 1234 }); +``` + +Whatever argument you provide to `worker` will get converted to an Elm value, +allowing you to configure your Elm program however you want from JavaScript! +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program flags model msg +programWithFlags = + Native.Platform.programWithFlags + + + +-- TASKS and PROCESSES + +{-| Head over to the documentation for the [`Task`](Task) module for more +information on this. It is only defined here because it is a platform +primitive. +-} +type Task err ok = Task + + +{-| Head over to the documentation for the [`Process`](Process) module for +information on this. It is only defined here because it is a platform +primitive. +-} +type ProcessId = ProcessId + + + +-- EFFECT MANAGER INTERNALS + + +{-| An effect manager has access to a “router” that routes messages between +the main app and your individual effect manager. +-} +type Router appMsg selfMsg = + Router + + +{-| Send the router a message for the main loop of your app. This message will +be handled by the overall `update` function, just like events from `Html`. +-} +sendToApp : Router msg a -> msg -> Task x () +sendToApp = + Native.Platform.sendToApp + + +{-| Send the router a message for your effect manager. This message will +be routed to the `onSelfMsg` function, where you can update the state of your +effect manager as necessary. + +As an example, the effect manager for web sockets +-} +sendToSelf : Router a msg -> msg -> Task x () +sendToSelf = + Native.Platform.sendToSelf + + +hack = + Native.Scheduler.succeed diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm new file mode 100644 index 0000000..a4ae4ed --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm @@ -0,0 +1,67 @@ +module Platform.Cmd exposing + ( Cmd + , map + , batch + , none + , (!) + ) + +{-| + +# Effects + +Elm has **managed effects**, meaning that things like HTTP requests or writing +to disk are all treated as *data* in Elm. When this data is given to the Elm +runtime system, it can do some “query optimization” before actually performing +the effect. Perhaps unexpectedly, this managed effects idea is the heart of why +Elm is so nice for testing, reuse, reproducibility, etc. + +There are two kinds of managed effects you will use in your programs: commands +and subscriptions. + +@docs Cmd, map, batch, none, (!) + +-} + +import Native.Platform + + +{-| A command is a way of telling Elm, “Hey, I want you to do this thing!” +So if you want to send an HTTP request, you would need to command Elm to do it. +Or if you wanted to ask for geolocation, you would need to command Elm to go +get it. + +Every `Cmd` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, commands will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they +fit into a real application! +-} +type Cmd msg = Cmd + + +{-|-} +map : (a -> msg) -> Cmd a -> Cmd msg +map = + Native.Platform.map + + +{-|-} +batch : List (Cmd msg) -> Cmd msg +batch = + Native.Platform.batch + + +{-|-} +none : Cmd msg +none = + batch [] + + +{-|-} +(!) : model -> List (Cmd msg) -> (model, Cmd msg) +(!) model commands = + (model, batch commands) + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm new file mode 100644 index 0000000..03f2f81 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm @@ -0,0 +1,52 @@ +module Platform.Sub exposing + ( Sub + , map + , batch + , none + ) + +{-| + +@docs Sub, map, batch, none +-} + +import Native.Platform + + +{-| A subscription is a way of telling Elm, “Hey, let me know if anything +interesting happens over there!” So if you want to listen for messages on a web +socket, you would tell Elm to create a subscription. If you want to get clock +ticks, you would tell Elm to subscribe to that. The cool thing here is that +this means *Elm* manages all the details of subscriptions instead of *you*. +So if a web socket goes down, *you* do not need to manually reconnect with an +exponential backoff strategy, *Elm* does this all for you behind the scenes! + +Every `Sub` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, subscriptions will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they fit +into a real application! +-} +type Sub msg = Sub + + +{-|-} +map : (a -> msg) -> Sub a -> Sub msg +map = + Native.Platform.map + + +{-|-} +batch : List (Sub msg) -> Sub msg +batch = + Native.Platform.batch + + +{-|-} +none : Sub msg +none = + batch [] + + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm new file mode 100644 index 0000000..0ef59af --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm @@ -0,0 +1,106 @@ +module Process exposing + ( Id + , spawn + , sleep + , kill + ) + +{-| + +# Processes +@docs Id, spawn, sleep, kill + +## Future Plans + +Right now, this library is pretty sparse. For example, there is no public API +for processes to communicate with each other. This is a really important +ability, but it is also something that is extraordinarily easy to get wrong! + +I think the trend will be towards an Erlang style of concurrency, where every +process has an “event queue” that anyone can send messages to. I currently +think the API will be extended to be more like this: + + type Id exit msg + + spawn : Task exit a -> Task x (Id exit Never) + + kill : Id exit msg -> Task x () + + send : Id exit msg -> msg -> Task x () + +A process `Id` will have two type variables to make sure all communication is +valid. The `exit` type describes the messages that are produced if the process +fails because of user code. So if processes are linked and trapping errors, +they will need to handle this. The `msg` type just describes what kind of +messages this process can be sent by strangers. + +We shall see though! This is just a draft that does not cover nearly everything +it needs to, so the long-term vision for concurrency in Elm will be rolling out +slowly as I get more data and experience. + +I ask that people bullish on compiling to node.js keep this in mind. I think we +can do better than the hopelessly bad concurrency model of node.js, and I hope +the Elm community will be supportive of being more ambitious, even if it takes +longer. That’s kind of what Elm is all about. +-} + +import Basics exposing (Never) +import Native.Scheduler +import Platform +import Task exposing (Task) +import Time exposing (Time) + + +{-| A light-weight process that runs concurrently. You can use `spawn` to +get a bunch of different tasks running in different processes. The Elm runtime +will interleave their progress. So if a task is taking too long, we will pause +it at an `andThen` and switch over to other stuff. + +**Note:** We make a distinction between *concurrency* which means interleaving +different sequences and *parallelism* which means running different +sequences at the exact same time. For example, a +[time-sharing system](https://en.wikipedia.org/wiki/Time-sharing) is definitely +concurrent, but not necessarily parallel. So even though JS runs within a +single OS-level thread, Elm can still run things concurrently. +-} +type alias Id = + Platform.ProcessId + + +{-| Run a task in its own light-weight process. In the following example, +`task1` and `task2` will be interleaved. If `task1` makes a long HTTP request +or is just taking a long time, we can hop over to `task2` and do some work +there. + + spawn task1 + |> Task.andThen (\_ -> spawn task2) + +**Note:** This creates a relatively restricted kind of `Process` because it +cannot receive any messages. More flexibility for user-defined processes will +come in a later release! +-} +spawn : Task x a -> Task y Id +spawn = + Native.Scheduler.spawn + + +{-| Block progress on the current process for a given amount of time. The +JavaScript equivalent of this is [`setTimeout`][setTimeout] which lets you +delay work until later. + +[setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout +-} +sleep : Time -> Task x () +sleep = + Native.Scheduler.sleep + + +{-| Sometimes you `spawn` a process, but later decide it would be a waste to +have it keep running and doing stuff. The `kill` function will force a process +to bail on whatever task it is running. So if there is an HTTP request in +flight, it will also abort the request. +-} +kill : Id -> Task x () +kill = + Native.Scheduler.kill + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm new file mode 100644 index 0000000..d506433 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm @@ -0,0 +1,532 @@ +effect module Random where { command = MyCmd } exposing + ( Generator, Seed + , bool, int, float + , list, pair + , map, map2, map3, map4, map5 + , andThen + , minInt, maxInt + , generate + , step, initialSeed + ) + +{-| This library helps you generate pseudo-random values. + +This library is all about building [`generators`](#Generator) for whatever +type of values you need. There are a bunch of primitive generators like +[`bool`](#bool) and [`int`](#int) that you can build up into fancier +generators with functions like [`list`](#list) and [`map`](#map). + +It may be helpful to [read about JSON decoders][json] because they work very +similarly. + +[json]: https://evancz.gitbooks.io/an-introduction-to-elm/content/interop/json.html + +> *Note:* This is an implementation of the Portable Combined Generator of +L'Ecuyer for 32-bit computers. It is almost a direct translation from the +[System.Random](http://hackage.haskell.org/package/random-1.0.1.1/docs/System-Random.html) +module. It has a period of roughly 2.30584e18. + +# Generators +@docs Generator + +# Primitive Generators +@docs bool, int, float + +# Data Structure Generators +@docs pair, list + +# Custom Generators +@docs map, map2, map3, map4, map5, andThen + +# Generate Values +@docs generate + +# Generate Values Manually +@docs step, Seed, initialSeed + +# Constants +@docs maxInt, minInt + +-} + +import Basics exposing (..) +import List exposing ((::)) +import Platform +import Platform.Cmd exposing (Cmd) +import Task exposing (Task) +import Time +import Tuple + + + +-- PRIMITIVE GENERATORS + + +{-| Create a generator that produces boolean values. The following example +simulates a coin flip that may land heads or tails. + + type Flip = Heads | Tails + + coinFlip : Generator Flip + coinFlip = + map (\b -> if b then Heads else Tails) bool +-} +bool : Generator Bool +bool = + map ((==) 1) (int 0 1) + + +{-| Generate 32-bit integers in a given range. + + int 0 10 -- an integer between zero and ten + int -5 5 -- an integer between -5 and 5 + + int minInt maxInt -- an integer in the widest range feasible + +This function *can* produce values outside of the range [[`minInt`](#minInt), +[`maxInt`](#maxInt)] but sufficient randomness is not guaranteed. +-} +int : Int -> Int -> Generator Int +int a b = + Generator <| \(Seed seed) -> + let + (lo,hi) = + if a < b then (a,b) else (b,a) + + k = hi - lo + 1 + -- 2^31 - 87 + base = 2147483561 + n = iLogBase base k + + f n acc state = + case n of + 0 -> (acc, state) + _ -> + let + (x, nextState) = seed.next state + in + f (n - 1) (x + acc * base) nextState + + (v, nextState) = + f n 1 seed.state + in + ( lo + v % k + , Seed { seed | state = nextState } + ) + + +iLogBase : Int -> Int -> Int +iLogBase b i = + if i < b then + 1 + else + 1 + iLogBase b (i // b) + + +{-| The maximum value for randomly generated 32-bit ints: 2147483647 -} +maxInt : Int +maxInt = + 2147483647 + + +{-| The minimum value for randomly generated 32-bit ints: -2147483648 -} +minInt : Int +minInt = + -2147483648 + + +{-| Generate floats in a given range. The following example is a generator +that produces decimals between 0 and 1. + + probability : Generator Float + probability = + float 0 1 +-} +float : Float -> Float -> Generator Float +float a b = + Generator <| \seed -> + let + (lo, hi) = + if a < b then (a,b) else (b,a) + + (number, newSeed) = + step (int minInt maxInt) seed + + negativeOneToOne = + toFloat number / toFloat (maxInt - minInt) + + scaled = + (lo+hi)/2 + ((hi-lo) * negativeOneToOne) + in + (scaled, newSeed) + + + +-- DATA STRUCTURES + + +{-| Create a pair of random values. A common use of this might be to generate +a point in a certain 2D space. Imagine we have a collage that is 400 pixels +wide and 200 pixels tall. + + randomPoint : Generator (Int,Int) + randomPoint = + pair (int -200 200) (int -100 100) + +-} +pair : Generator a -> Generator b -> Generator (a,b) +pair genA genB = + map2 (,) genA genB + + +{-| Create a list of random values. + + floatList : Generator (List Float) + floatList = + list 10 (float 0 1) + + intList : Generator (List Int) + intList = + list 5 (int 0 100) + + intPairs : Generator (List (Int, Int)) + intPairs = + list 10 <| pair (int 0 100) (int 0 100) +-} +list : Int -> Generator a -> Generator (List a) +list n (Generator generate) = + Generator <| \seed -> + listHelp [] n generate seed + + +listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed) +listHelp list n generate seed = + if n < 1 then + (List.reverse list, seed) + + else + let + (value, newSeed) = + generate seed + in + listHelp (value :: list) (n-1) generate newSeed + + + +-- CUSTOM GENERATORS + + +{-| Transform the values produced by a generator. The following examples show +how to generate booleans and letters based on a basic integer generator. + + bool : Generator Bool + bool = + map ((==) 1) (int 0 1) + + lowercaseLetter : Generator Char + lowercaseLetter = + map (\n -> Char.fromCode (n + 97)) (int 0 25) + + uppercaseLetter : Generator Char + uppercaseLetter = + map (\n -> Char.fromCode (n + 65)) (int 0 25) + +-} +map : (a -> b) -> Generator a -> Generator b +map func (Generator genA) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + in + (func a, seed1) + + +{-| Combine two generators. + +This function is used to define things like [`pair`](#pair) where you want to +put two generators together. + + pair : Generator a -> Generator b -> Generator (a,b) + pair genA genB = + map2 (,) genA genB + +-} +map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c +map2 func (Generator genA) (Generator genB) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + in + (func a b, seed2) + + +{-| Combine three generators. This could be used to produce random colors. + + import Color + + rgb : Generator Color.Color + rgb = + map3 Color.rgb (int 0 255) (int 0 255) (int 0 255) + + hsl : Generator Color.Color + hsl = + map3 Color.hsl (map degrees (int 0 360)) (float 0 1) (float 0 1) +-} +map3 : (a -> b -> c -> d) -> Generator a -> Generator b -> Generator c -> Generator d +map3 func (Generator genA) (Generator genB) (Generator genC) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + in + (func a b c, seed3) + + +{-| Combine four generators. +-} +map4 : (a -> b -> c -> d -> e) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e +map4 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + in + (func a b c d, seed4) + + +{-| Combine five generators. +-} +map5 : (a -> b -> c -> d -> e -> f) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e -> Generator f +map5 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) (Generator genE) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + (e, seed5) = genE seed4 + in + (func a b c d e, seed5) + + +{-| Chain random operations, threading through the seed. In the following +example, we will generate a random letter by putting together uppercase and +lowercase letters. + + letter : Generator Char + letter = + bool + |> andThen upperOrLower + + upperOrLower : Bool -> Generator Char + upperOrLower b = + if b then uppercaseLetter else lowercaseLetter + + -- bool : Generator Bool + -- uppercaseLetter : Generator Char + -- lowercaseLetter : Generator Char +-} +andThen : (a -> Generator b) -> Generator a -> Generator b +andThen callback (Generator generate) = + Generator <| \seed -> + let + (result, newSeed) = + generate seed + + (Generator genB) = + callback result + in + genB newSeed + + + +-- IMPLEMENTATION + + +{-| A `Generator` is like a recipe for generating certain random values. So a +`Generator Int` describes how to generate integers and a `Generator String` +describes how to generate strings. + +To actually *run* a generator and produce the random values, you need to use +functions like [`generate`](#generate) and [`initialSeed`](#initialSeed). +-} +type Generator a = + Generator (Seed -> (a, Seed)) + + +type State = State Int Int + + +{-| A `Seed` is the source of randomness in this whole system. Whenever +you want to use a generator, you need to pair it with a seed. +-} +type Seed = + Seed + { state : State + , next : State -> (Int, State) + , split : State -> (State, State) + , range : State -> (Int,Int) + } + + +{-| Generate a random value as specified by a given `Generator`. + +In the following example, we are trying to generate a number between 0 and 100 +with the `int 0 100` generator. Each time we call `step` we need to provide a +seed. This will produce a random number and a *new* seed to use if we want to +run other generators later. + +So here it is done right, where we get a new seed from each `step` call and +thread that through. + + seed0 = initialSeed 31415 + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed1 ==> (31, seed2) + -- step (int 0 100) seed2 ==> (99, seed3) + +Notice that we use different seeds on each line. This is important! If you use +the same seed, you get the same results. + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) +-} +step : Generator a -> Seed -> (a, Seed) +step (Generator generator) seed = + generator seed + + +{-| Create a “seed” of randomness which makes it possible to +generate random values. If you use the same seed many times, it will result +in the same thing every time! A good way to get an unexpected seed is to use +the current time. +-} +initialSeed : Int -> Seed +initialSeed n = + Seed + { state = initState n + , next = next + , split = split + , range = range + } + + +{-| Produce the initial generator state. Distinct arguments should be likely +to produce distinct generator states. +-} +initState : Int -> State +initState seed = + let + s = max seed -seed + q = s // (magicNum6-1) + s1 = s % (magicNum6-1) + s2 = q % (magicNum7-1) + in + State (s1+1) (s2+1) + + +magicNum0 = 40014 +magicNum1 = 53668 +magicNum2 = 12211 +magicNum3 = 52774 +magicNum4 = 40692 +magicNum5 = 3791 +magicNum6 = 2147483563 +magicNum7 = 2147483399 +magicNum8 = 2147483562 + + +next : State -> (Int, State) +next (State state1 state2) = + -- Div always rounds down and so random numbers are biased + -- ideally we would use division that rounds towards zero so + -- that in the negative case it rounds up and in the positive case + -- it rounds down. Thus half the time it rounds up and half the time it + -- rounds down + let + k1 = state1 // magicNum1 + rawState1 = magicNum0 * (state1 - k1 * magicNum1) - k1 * magicNum2 + newState1 = if rawState1 < 0 then rawState1 + magicNum6 else rawState1 + k2 = state2 // magicNum3 + rawState2 = magicNum4 * (state2 - k2 * magicNum3) - k2 * magicNum5 + newState2 = if rawState2 < 0 then rawState2 + magicNum7 else rawState2 + z = newState1 - newState2 + newZ = if z < 1 then z + magicNum8 else z + in + (newZ, State newState1 newState2) + + +split : State -> (State, State) +split (State s1 s2 as std) = + let + new_s1 = + if s1 == magicNum6-1 then 1 else s1 + 1 + + new_s2 = + if s2 == 1 then magicNum7-1 else s2 - 1 + + (State t1 t2) = + Tuple.second (next std) + in + (State new_s1 t2, State t1 new_s2) + + +range : State -> (Int,Int) +range _ = + (0, magicNum8) + + + +-- MANAGER + + +{-| Create a command that will generate random values. + +Read more about how to use this in your programs in [The Elm Architecture +tutorial][arch] which has a section specifically [about random values][rand]. + +[arch]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/index.html +[rand]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/effects/random.html +-} +generate : (a -> msg) -> Generator a -> Cmd msg +generate tagger generator = + command (Generate (map tagger generator)) + + +type MyCmd msg = Generate (Generator msg) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap func (Generate generator) = + Generate (map func generator) + + +init : Task Never Seed +init = + Time.now + |> Task.andThen (\t -> Task.succeed (initialSeed (round t))) + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> Seed -> Task Never Seed +onEffects router commands seed = + case commands of + [] -> + Task.succeed seed + + Generate generator :: rest -> + let + (value, newSeed) = + step generator seed + in + Platform.sendToApp router value + |> Task.andThen (\_ -> onEffects router rest newSeed) + + +onSelfMsg : Platform.Router msg Never -> Never -> Seed -> Task Never Seed +onSelfMsg _ _ seed = + Task.succeed seed diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm new file mode 100644 index 0000000..2d58ecf --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm @@ -0,0 +1,148 @@ +module Regex exposing + ( Regex + , regex, escape, caseInsensitive + , HowMany(..), Match + , contains, find, replace, split + ) + +{-| A library for working with regular expressions. It uses [the +same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions). + +# Create +@docs Regex, regex, escape, caseInsensitive + +# Helpful Data Structures + +These data structures are needed to help define functions like [`find`](#find) +and [`replace`](#replace). + +@docs HowMany, Match + +# Use +@docs contains, find, replace, split + +-} + +import Maybe exposing (Maybe) +import Native.Regex + + +{-| A regular expression, describing a certain set of strings. +-} +type Regex = Regex + + +{-| Escape strings to be regular expressions, making all special characters +safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series +of `a`’s that start at the beginning of the line. +-} +escape : String -> String +escape = + Native.Regex.escape + + +{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern). + +Be careful to escape backslashes properly! For example, `"\w"` is escaping the +letter `w` which is probably not what you want. You probably want `"\\w"` +instead, which escapes the backslash. +-} +regex : String -> Regex +regex = + Native.Regex.regex + + + +{-| Make a regex case insensitive -} +caseInsensitive : Regex -> Regex +caseInsensitive = + Native.Regex.caseInsensitive + + +{-| Check to see if a Regex is contained in a string. + + contains (regex "123") "12345" == True + contains (regex "b+") "aabbcc" == True + + contains (regex "789") "12345" == False + contains (regex "z+") "aabbcc" == False +-} +contains : Regex -> String -> Bool +contains = + Native.Regex.contains + + +{-| A `Match` represents all of the details about a particular match in a string. +Here are details on each field: + + * `match` — the full string of the match. + * `submatches` — a regex might have [subpatterns, surrounded by + parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches). + If there are N subpatterns, there will be N elements in the `submatches` list. + Each submatch in this list is a `Maybe` because not all subpatterns may trigger. + For example, `(regex "(a+)|(b+)")` will either match many `a`’s or + many `b`’s, but never both. + * `index` — the index of the match in the original string. + * `number` — if you find many matches, you can think of each one + as being labeled with a `number` starting at one. So the first time you + find a match, that is match `number` one. Second time is match `number` two. + This is useful when paired with `replace All` if replacement is dependent on how + many times a pattern has appeared before. +-} +type alias Match = + { match : String + , submatches : List (Maybe String) + , index : Int + , number : Int + } + + +{-| `HowMany` is used to specify how many matches you want to make. So +`replace All` would replace every match, but `replace (AtMost 2)` would +replace at most two matches (i.e. zero, one, two, but never three or more). +-} +type HowMany = All | AtMost Int + + +{-| Find matches in a string: + + findTwoCommas = find (AtMost 2) (regex ",") + + -- map .index (findTwoCommas "a,b,c,d,e") == [1,3] + -- map .index (findTwoCommas "a b c d e") == [] + + places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake." + + -- map .match places == ["on a boat", "in a lake"] + -- map .submatches places == [ [Just "boat"], [Just "lake"] ] +-} +find : HowMany -> Regex -> String -> List Match +find = + Native.Regex.find + + +{-| Replace matches. The function from `Match` to `String` lets +you use the details of a specific match when making replacements. + + devowel = replace All (regex "[aeiou]") (\_ -> "") + + -- devowel "The quick brown fox" == "Th qck brwn fx" + + reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match) + + -- reverseWords "deliver mined parts" == "reviled denim strap" +-} +replace : HowMany -> Regex -> (Match -> String) -> String -> String +replace = + Native.Regex.replace + + +{-| Split a string, using the regex as the separator. + + split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"] + + split All (regex ",") "a,b,c,d" == ["a","b","c","d"] +-} +split : HowMany -> Regex -> String -> List String +split = + Native.Regex.split diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm new file mode 100644 index 0000000..61c678c --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm @@ -0,0 +1,210 @@ +module Result exposing + ( Result(..) + , withDefault + , map, map2, map3, map4, map5 + , andThen + , toMaybe, fromMaybe, mapError + ) + +{-| A `Result` is the result of a computation that may fail. This is a great +way to manage errors in Elm. + +# Type and Constructors +@docs Result + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen + +# Handling Errors +@docs withDefault, toMaybe, fromMaybe, mapError +-} + +import Maybe exposing ( Maybe(Just, Nothing) ) + + +{-| A `Result` is either `Ok` meaning the computation succeeded, or it is an +`Err` meaning that there was some failure. +-} +type Result error value + = Ok value + | Err error + + +{-| If the result is `Ok` return the value, but if the result is an `Err` then +return a given default value. The following examples try to parse integers. + + Result.withDefault 0 (String.toInt "123") == 123 + Result.withDefault 0 (String.toInt "abc") == 0 +-} +withDefault : a -> Result x a -> a +withDefault def result = + case result of + Ok a -> + a + + Err _ -> + def + + +{-| Apply a function to a result. If the result is `Ok`, it will be converted. +If the result is an `Err`, the same error value will propagate through. + + map sqrt (Ok 4.0) == Ok 2.0 + map sqrt (Err "bad input") == Err "bad input" +-} +map : (a -> value) -> Result x a -> Result x value +map func ra = + case ra of + Ok a -> Ok (func a) + Err e -> Err e + + +{-| Apply a function to two results, if both results are `Ok`. If not, +the first argument which is an `Err` will propagate through. + + map2 (+) (String.toInt "1") (String.toInt "2") == Ok 3 + map2 (+) (String.toInt "1") (String.toInt "y") == Err "could not convert string 'y' to an Int" + map2 (+) (String.toInt "x") (String.toInt "y") == Err "could not convert string 'x' to an Int" +-} +map2 : (a -> b -> value) -> Result x a -> Result x b -> Result x value +map2 func ra rb = + case (ra,rb) of + (Ok a, Ok b) -> Ok (func a b) + (Err x, _) -> Err x + (_, Err x) -> Err x + + +{-|-} +map3 : (a -> b -> c -> value) -> Result x a -> Result x b -> Result x c -> Result x value +map3 func ra rb rc = + case (ra,rb,rc) of + (Ok a, Ok b, Ok c) -> Ok (func a b c) + (Err x, _, _) -> Err x + (_, Err x, _) -> Err x + (_, _, Err x) -> Err x + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x value +map4 func ra rb rc rd = + case (ra,rb,rc,rd) of + (Ok a, Ok b, Ok c, Ok d) -> Ok (func a b c d) + (Err x, _, _, _) -> Err x + (_, Err x, _, _) -> Err x + (_, _, Err x, _) -> Err x + (_, _, _, Err x) -> Err x + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x e -> Result x value +map5 func ra rb rc rd re = + case (ra,rb,rc,rd,re) of + (Ok a, Ok b, Ok c, Ok d, Ok e) -> Ok (func a b c d e) + (Err x, _, _, _, _) -> Err x + (_, Err x, _, _, _) -> Err x + (_, _, Err x, _, _) -> Err x + (_, _, _, Err x, _) -> Err x + (_, _, _, _, Err x) -> Err x + + +{-| Chain together a sequence of computations that may fail. It is helpful +to see its definition: + + andThen : (a -> Result e b) -> Result e a -> Result e b + andThen callback result = + case result of + Ok value -> callback value + Err msg -> Err msg + +This means we only continue with the callback if things are going well. For +example, say you need to use (`toInt : String -> Result String Int`) to parse +a month and make sure it is between 1 and 12: + + toValidMonth : Int -> Result String Int + toValidMonth month = + if month >= 1 && month <= 12 + then Ok month + else Err "months must be between 1 and 12" + + toMonth : String -> Result String Int + toMonth rawString = + toInt rawString + |> andThen toValidMonth + + -- toMonth "4" == Ok 4 + -- toMonth "9" == Ok 9 + -- toMonth "a" == Err "cannot parse to an Int" + -- toMonth "0" == Err "months must be between 1 and 12" + +This allows us to come out of a chain of operations with quite a specific error +message. It is often best to create a custom type that explicitly represents +the exact ways your computation may fail. This way it is easy to handle in your +code. +-} +andThen : (a -> Result x b) -> Result x a -> Result x b +andThen callback result = + case result of + Ok value -> + callback value + + Err msg -> + Err msg + + +{-| Transform an `Err` value. For example, say the errors we get have too much +information: + + parseInt : String -> Result ParseError Int + + type alias ParseError = + { message : String + , code : Int + , position : (Int,Int) + } + + mapError .message (parseInt "123") == Ok 123 + mapError .message (parseInt "abc") == Err "char 'a' is not a number" +-} +mapError : (x -> y) -> Result x a -> Result y a +mapError f result = + case result of + Ok v -> + Ok v + + Err e -> + Err (f e) + + +{-| Convert to a simpler `Maybe` if the actual error message is not needed or +you need to interact with some code that primarily uses maybes. + + parseInt : String -> Result ParseError Int + + maybeParseInt : String -> Maybe Int + maybeParseInt string = + toMaybe (parseInt string) +-} +toMaybe : Result x a -> Maybe a +toMaybe result = + case result of + Ok v -> Just v + Err _ -> Nothing + + +{-| Convert from a simple `Maybe` to interact with some code that primarily +uses `Results`. + + parseInt : String -> Maybe Int + + resultParseInt : String -> Result String Int + resultParseInt string = + fromMaybe ("error parsing string: " ++ toString string) (parseInt string) +-} +fromMaybe : x -> Maybe a -> Result x a +fromMaybe err maybe = + case maybe of + Just v -> Ok v + Nothing -> Err err diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm new file mode 100644 index 0000000..9b1914a --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm @@ -0,0 +1,168 @@ +module Set exposing + ( Set + , empty, singleton, insert, remove + , isEmpty, member, size + , foldl, foldr, map + , filter, partition + , union, intersect, diff + , toList, fromList + ) + +{-| A set of unique values. The values can be any comparable type. This +includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or lists +of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Sets +@docs Set + +# Build +@docs empty, singleton, insert, remove + +# Query +@docs isEmpty, member, size + +# Combine +@docs union, intersect, diff + +# Lists +@docs toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +-} + +import Basics exposing ((<|)) +import Dict as Dict +import List as List + + +{-| Represents a set of unique values. So `(Set Int)` is a set of integers and +`(Set String)` is a set of strings. +-} +type Set t = + Set_elm_builtin (Dict.Dict t ()) + + +{-| Create an empty set. +-} +empty : Set a +empty = + Set_elm_builtin Dict.empty + + +{-| Create a set with one value. +-} +singleton : comparable -> Set comparable +singleton k = + Set_elm_builtin <| Dict.singleton k () + + +{-| Insert a value into a set. +-} +insert : comparable -> Set comparable -> Set comparable +insert k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.insert k () d + + +{-| Remove a value from a set. If the value is not found, no changes are made. +-} +remove : comparable -> Set comparable -> Set comparable +remove k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.remove k d + + +{-| Determine if a set is empty. +-} +isEmpty : Set a -> Bool +isEmpty (Set_elm_builtin d) = + Dict.isEmpty d + + +{-| Determine if a value is in a set. +-} +member : comparable -> Set comparable -> Bool +member k (Set_elm_builtin d) = + Dict.member k d + + +{-| Determine the number of elements in a set. +-} +size : Set a -> Int +size (Set_elm_builtin d) = + Dict.size d + + +{-| Get the union of two sets. Keep all values. +-} +union : Set comparable -> Set comparable -> Set comparable +union (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.union d1 d2 + + +{-| Get the intersection of two sets. Keeps values that appear in both sets. +-} +intersect : Set comparable -> Set comparable -> Set comparable +intersect (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.intersect d1 d2 + + +{-| Get the difference between the first set and the second. Keeps values +that do not appear in the second set. +-} +diff : Set comparable -> Set comparable -> Set comparable +diff (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.diff d1 d2 + + +{-| Convert a set into a list, sorted from lowest to highest. +-} +toList : Set comparable -> List comparable +toList (Set_elm_builtin d) = + Dict.keys d + + +{-| Convert a list into a set, removing any duplicates. +-} +fromList : List comparable -> Set comparable +fromList xs = List.foldl insert empty xs + + +{-| Fold over the values in a set, in order from lowest to highest. +-} +foldl : (comparable -> b -> b) -> b -> Set comparable -> b +foldl f b (Set_elm_builtin d) = + Dict.foldl (\k _ b -> f k b) b d + + +{-| Fold over the values in a set, in order from highest to lowest. +-} +foldr : (comparable -> b -> b) -> b -> Set comparable -> b +foldr f b (Set_elm_builtin d) = + Dict.foldr (\k _ b -> f k b) b d + + +{-| Map a function onto a set, creating a new set with no duplicates. +-} +map : (comparable -> comparable2) -> Set comparable -> Set comparable2 +map f s = fromList (List.map f (toList s)) + + +{-| Create a new set consisting only of elements which satisfy a predicate. +-} +filter : (comparable -> Bool) -> Set comparable -> Set comparable +filter p (Set_elm_builtin d) = + Set_elm_builtin <| Dict.filter (\k _ -> p k) d + + +{-| Create two new sets; the first consisting of elements which satisfy a +predicate, the second consisting of elements which do not. +-} +partition : (comparable -> Bool) -> Set comparable -> (Set comparable, Set comparable) +partition p (Set_elm_builtin d) = + let + (p1, p2) = Dict.partition (\k _ -> p k) d + in + (Set_elm_builtin p1, Set_elm_builtin p2) diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm new file mode 100644 index 0000000..a648e8d --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm @@ -0,0 +1,464 @@ +module String exposing + ( isEmpty, length, reverse, repeat + , cons, uncons, fromChar, append, concat, split, join, words, lines + , slice, left, right, dropLeft, dropRight + , contains, startsWith, endsWith, indexes, indices + , toInt, toFloat, toList, fromList + , toUpper, toLower, pad, padLeft, padRight, trim, trimLeft, trimRight + , map, filter, foldl, foldr, any, all + ) + +{-| A built-in representation for efficient string manipulation. String literals +are enclosed in `"double quotes"`. Strings are *not* lists of characters. + +# Basics +@docs isEmpty, length, reverse, repeat + +# Building and Splitting +@docs cons, uncons, fromChar, append, concat, split, join, words, lines + +# Get Substrings +@docs slice, left, right, dropLeft, dropRight + +# Check for Substrings +@docs contains, startsWith, endsWith, indexes, indices + +# Conversions +@docs toInt, toFloat, toList, fromList + +# Formatting +Cosmetic operations such as padding with extra characters or trimming whitespace. + +@docs toUpper, toLower, + pad, padLeft, padRight, + trim, trimLeft, trimRight + +# Higher-Order Functions +@docs map, filter, foldl, foldr, any, all +-} + +import Native.String +import Char +import Maybe exposing (Maybe) +import Result exposing (Result) + + +{-| Determine if a string is empty. + + isEmpty "" == True + isEmpty "the world" == False +-} +isEmpty : String -> Bool +isEmpty = + Native.String.isEmpty + + +{-| Add a character to the beginning of a string. + + cons 'T' "he truth is out there" == "The truth is out there" +-} +cons : Char -> String -> String +cons = + Native.String.cons + + +{-| Create a string from a given character. + + fromChar 'a' == "a" +-} +fromChar : Char -> String +fromChar char = + cons char "" + + +{-| Split a non-empty string into its head and tail. This lets you +pattern match on strings exactly as you would with lists. + + uncons "abc" == Just ('a',"bc") + uncons "" == Nothing +-} +uncons : String -> Maybe (Char, String) +uncons = + Native.String.uncons + + +{-| Append two strings. You can also use [the `(++)` operator](Basics#++) +to do this. + + append "butter" "fly" == "butterfly" +-} +append : String -> String -> String +append = + Native.String.append + + +{-| Concatenate many strings into one. + + concat ["never","the","less"] == "nevertheless" +-} +concat : List String -> String +concat = + Native.String.concat + + +{-| Get the length of a string. + + length "innumerable" == 11 + length "" == 0 + +-} +length : String -> Int +length = + Native.String.length + + +{-| Transform every character in a string + + map (\c -> if c == '/' then '.' else c) "a/b/c" == "a.b.c" +-} +map : (Char -> Char) -> String -> String +map = + Native.String.map + + +{-| Keep only the characters that satisfy the predicate. + + filter isDigit "R2-D2" == "22" +-} +filter : (Char -> Bool) -> String -> String +filter = + Native.String.filter + + +{-| Reverse a string. + + reverse "stressed" == "desserts" +-} +reverse : String -> String +reverse = + Native.String.reverse + + +{-| Reduce a string from the left. + + foldl cons "" "time" == "emit" +-} +foldl : (Char -> b -> b) -> b -> String -> b +foldl = + Native.String.foldl + + +{-| Reduce a string from the right. + + foldr cons "" "time" == "time" +-} +foldr : (Char -> b -> b) -> b -> String -> b +foldr = + Native.String.foldr + + +{-| Split a string using a given separator. + + split "," "cat,dog,cow" == ["cat","dog","cow"] + split "/" "home/evan/Desktop/" == ["home","evan","Desktop", ""] + +Use [`Regex.split`](Regex#split) if you need something more flexible. +-} +split : String -> String -> List String +split = + Native.String.split + + +{-| Put many strings together with a given separator. + + join "a" ["H","w","ii","n"] == "Hawaiian" + join " " ["cat","dog","cow"] == "cat dog cow" + join "/" ["home","evan","Desktop"] == "home/evan/Desktop" +-} +join : String -> List String -> String +join = + Native.String.join + + +{-| Repeat a string *n* times. + + repeat 3 "ha" == "hahaha" +-} +repeat : Int -> String -> String +repeat = + Native.String.repeat + + +{-| Take a substring given a start and end index. Negative indexes +are taken starting from the *end* of the list. + + slice 7 9 "snakes on a plane!" == "on" + slice 0 6 "snakes on a plane!" == "snakes" + slice 0 -7 "snakes on a plane!" == "snakes on a" + slice -6 -1 "snakes on a plane!" == "plane" +-} +slice : Int -> Int -> String -> String +slice = + Native.String.slice + + +{-| Take *n* characters from the left side of a string. + + left 2 "Mulder" == "Mu" +-} +left : Int -> String -> String +left = + Native.String.left + + +{-| Take *n* characters from the right side of a string. + + right 2 "Scully" == "ly" +-} +right : Int -> String -> String +right = + Native.String.right + + +{-| Drop *n* characters from the left side of a string. + + dropLeft 2 "The Lone Gunmen" == "e Lone Gunmen" +-} +dropLeft : Int -> String -> String +dropLeft = + Native.String.dropLeft + + +{-| Drop *n* characters from the right side of a string. + + dropRight 2 "Cigarette Smoking Man" == "Cigarette Smoking M" +-} +dropRight : Int -> String -> String +dropRight = + Native.String.dropRight + + +{-| Pad a string on both sides until it has a given length. + + pad 5 ' ' "1" == " 1 " + pad 5 ' ' "11" == " 11 " + pad 5 ' ' "121" == " 121 " +-} +pad : Int -> Char -> String -> String +pad = + Native.String.pad + + +{-| Pad a string on the left until it has a given length. + + padLeft 5 '.' "1" == "....1" + padLeft 5 '.' "11" == "...11" + padLeft 5 '.' "121" == "..121" +-} +padLeft : Int -> Char -> String -> String +padLeft = + Native.String.padLeft + + +{-| Pad a string on the right until it has a given length. + + padRight 5 '.' "1" == "1...." + padRight 5 '.' "11" == "11..." + padRight 5 '.' "121" == "121.." +-} +padRight : Int -> Char -> String -> String +padRight = + Native.String.padRight + + +{-| Get rid of whitespace on both sides of a string. + + trim " hats \n" == "hats" +-} +trim : String -> String +trim = + Native.String.trim + + +{-| Get rid of whitespace on the left of a string. + + trimLeft " hats \n" == "hats \n" +-} +trimLeft : String -> String +trimLeft = + Native.String.trimLeft + + +{-| Get rid of whitespace on the right of a string. + + trimRight " hats \n" == " hats" +-} +trimRight : String -> String +trimRight = + Native.String.trimRight + + +{-| Break a string into words, splitting on chunks of whitespace. + + words "How are \t you? \n Good?" == ["How","are","you?","Good?"] +-} +words : String -> List String +words = + Native.String.words + + +{-| Break a string into lines, splitting on newlines. + + lines "How are you?\nGood?" == ["How are you?", "Good?"] +-} +lines : String -> List String +lines = + Native.String.lines + + +{-| Convert a string to all upper case. Useful for case-insensitive comparisons +and VIRTUAL YELLING. + + toUpper "skinner" == "SKINNER" +-} +toUpper : String -> String +toUpper = + Native.String.toUpper + + +{-| Convert a string to all lower case. Useful for case-insensitive comparisons. + + toLower "X-FILES" == "x-files" +-} +toLower : String -> String +toLower = + Native.String.toLower + + +{-| Determine whether *any* characters satisfy a predicate. + + any isDigit "90210" == True + any isDigit "R2-D2" == True + any isDigit "heart" == False +-} +any : (Char -> Bool) -> String -> Bool +any = + Native.String.any + + +{-| Determine whether *all* characters satisfy a predicate. + + all isDigit "90210" == True + all isDigit "R2-D2" == False + all isDigit "heart" == False +-} +all : (Char -> Bool) -> String -> Bool +all = + Native.String.all + + +{-| See if the second string contains the first one. + + contains "the" "theory" == True + contains "hat" "theory" == False + contains "THE" "theory" == False + +Use [`Regex.contains`](Regex#contains) if you need something more flexible. +-} +contains : String -> String -> Bool +contains = + Native.String.contains + + +{-| See if the second string starts with the first one. + + startsWith "the" "theory" == True + startsWith "ory" "theory" == False +-} +startsWith : String -> String -> Bool +startsWith = + Native.String.startsWith + + +{-| See if the second string ends with the first one. + + endsWith "the" "theory" == False + endsWith "ory" "theory" == True +-} +endsWith : String -> String -> Bool +endsWith = + Native.String.endsWith + + +{-| Get all of the indexes for a substring in another string. + + indexes "i" "Mississippi" == [1,4,7,10] + indexes "ss" "Mississippi" == [2,5] + indexes "needle" "haystack" == [] +-} +indexes : String -> String -> List Int +indexes = + Native.String.indexes + + +{-| Alias for `indexes`. -} +indices : String -> String -> List Int +indices = + Native.String.indexes + + +{-| Try to convert a string into an int, failing on improperly formatted strings. + + String.toInt "123" == Ok 123 + String.toInt "-42" == Ok -42 + String.toInt "3.1" == Err "could not convert string '3.1' to an Int" + String.toInt "31a" == Err "could not convert string '31a' to an Int" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toInt "42") == 42 + Result.withDefault 0 (String.toInt "ab") == 0 +-} +toInt : String -> Result String Int +toInt = + Native.String.toInt + + +{-| Try to convert a string into a float, failing on improperly formatted strings. + + String.toFloat "123" == Ok 123.0 + String.toFloat "-42" == Ok -42.0 + String.toFloat "3.1" == Ok 3.1 + String.toFloat "31a" == Err "could not convert string '31a' to a Float" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toFloat "42.5") == 42.5 + Result.withDefault 0 (String.toFloat "cats") == 0 +-} +toFloat : String -> Result String Float +toFloat = + Native.String.toFloat + + +{-| Convert a string to a list of characters. + + toList "abc" == ['a','b','c'] +-} +toList : String -> List Char +toList = + Native.String.toList + + +{-| Convert a list of characters into a String. Can be useful if you +want to create a string primarily by consing, perhaps for decoding +something. + + fromList ['a','b','c'] == "abc" +-} +fromList : List Char -> String +fromList = + Native.String.fromList + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm new file mode 100644 index 0000000..94fde9e --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm @@ -0,0 +1,277 @@ +effect module Task where { command = MyCmd } exposing + ( Task + , succeed, fail + , map, map2, map3, map4, map5 + , sequence + , andThen + , onError, mapError + , perform, attempt + ) + +{-| Tasks make it easy to describe asynchronous operations that may fail, like +HTTP requests or writing to a database. For more information, see the [Elm +documentation on Tasks](http://guide.elm-lang.org/error_handling/task.html). + +# Basics +@docs Task, succeed, fail + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen, sequence + +# Errors +@docs onError, mapError + +# Commands +@docs perform, attempt + +-} + +import Basics exposing (Never, (|>), (<<)) +import List exposing ((::)) +import Maybe exposing (Maybe(Just,Nothing)) +import Native.Scheduler +import Platform +import Platform.Cmd exposing (Cmd) +import Result exposing (Result(Ok,Err)) + + + +{-| Represents asynchronous effects that may fail. It is useful for stuff like +HTTP. + +For example, maybe we have a task with the type (`Task String User`). This means +that when we perform the task, it will either fail with a `String` message or +succeed with a `User`. So this could represent a task that is asking a server +for a certain user. +-} +type alias Task err ok = + Platform.Task err ok + + + +-- BASICS + + +{-| A task that succeeds immediately when run. + + succeed 42 -- results in 42 +-} +succeed : a -> Task x a +succeed = + Native.Scheduler.succeed + + +{-| A task that fails immediately when run. + + fail "file not found" : Task String a +-} +fail : x -> Task x a +fail = + Native.Scheduler.fail + + + +-- MAPPING + + +{-| Transform a task. + + map sqrt (succeed 9) -- succeed 3 +-} +map : (a -> b) -> Task x a -> Task x b +map func taskA = + taskA + |> andThen (\a -> succeed (func a)) + + +{-| Put the results of two tasks together. If either task fails, the whole +thing fails. It also runs in order so the first task will be completely +finished before the second task starts. + + map2 (+) (succeed 9) (succeed 3) -- succeed 12 +-} +map2 : (a -> b -> result) -> Task x a -> Task x b -> Task x result +map2 func taskA taskB = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> succeed (func a b))) + + +{-|-} +map3 : (a -> b -> c -> result) -> Task x a -> Task x b -> Task x c -> Task x result +map3 func taskA taskB taskC = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> succeed (func a b c)))) + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x result +map4 func taskA taskB taskC taskD = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> succeed (func a b c d))))) + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x e -> Task x result +map5 func taskA taskB taskC taskD taskE = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> taskE + |> andThen (\e -> succeed (func a b c d e)))))) + + +{-| Start with a list of tasks, and turn them into a single task that returns a +list. The tasks will be run in order one-by-one and if any task fails the whole +sequence fails. + + sequence [ succeed 1, succeed 2 ] -- succeed [ 1, 2 ] + +This can be useful if you need to make a bunch of HTTP requests one-by-one. +-} +sequence : List (Task x a) -> Task x (List a) +sequence tasks = + case tasks of + [] -> + succeed [] + + task :: remainingTasks -> + map2 (::) task (sequence remainingTasks) + + + +-- CHAINING + + +{-| Chain together a task and a callback. The first task will run, and if it is +successful, you give the result to the callback resulting in another task. This +task then gets run. + + succeed 2 + |> andThen (\n -> succeed (n + 2)) + -- succeed 4 + +This is useful for chaining tasks together. Maybe you need to get a user from +your servers *and then* lookup their picture once you know their name. +-} +andThen : (a -> Task x b) -> Task x a -> Task x b +andThen = + Native.Scheduler.andThen + + +-- ERRORS + +{-| Recover from a failure in a task. If the given task fails, we use the +callback to recover. + + fail "file not found" + |> onError (\msg -> succeed 42) + -- succeed 42 + + succeed 9 + |> onError (\msg -> succeed 42) + -- succeed 9 +-} +onError : (x -> Task y a) -> Task x a -> Task y a +onError = + Native.Scheduler.onError + + +{-| Transform the error value. This can be useful if you need a bunch of error +types to match up. + + type Error = Http Http.Error | WebGL WebGL.Error + + getResources : Task Error Resource + getResources = + sequence [ mapError Http serverTask, mapError WebGL textureTask ] +-} +mapError : (x -> y) -> Task x a -> Task y a +mapError convert task = + task + |> onError (fail << convert) + + + +-- COMMANDS + + +type MyCmd msg = + Perform (Task Never msg) + + +{-| The only way to *do* things in Elm is to give commands to the Elm runtime. +So we describe some complex behavior with a `Task` and then command the runtime +to `perform` that task. For example, getting the current time looks like this: + + import Task + import Time exposing (Time) + + type Msg = Click | NewTime Time + + update : Msg -> Model -> ( Model, Cmd Msg ) + update msg model = + case msg of + Click -> + ( model, Task.perform NewTime Time.now ) + + NewTime time -> + ... +-} +perform : (a -> msg) -> Task Never a -> Cmd msg +perform toMessage task = + command (Perform (map toMessage task)) + + +{-| Command the Elm runtime to attempt a task that might fail! +-} +attempt : (Result x a -> msg) -> Task x a -> Cmd msg +attempt resultToMessage task = + command (Perform ( + task + |> andThen (succeed << resultToMessage << Ok) + |> onError (succeed << resultToMessage << Err) + )) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap tagger (Perform task) = + Perform (map tagger task) + + + +-- MANAGER + + +init : Task Never () +init = + succeed () + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> () -> Task Never () +onEffects router commands state = + map + (\_ -> ()) + (sequence (List.map (spawnCmd router) commands)) + + +onSelfMsg : Platform.Router msg Never -> Never -> () -> Task Never () +onSelfMsg _ _ _ = + succeed () + + +spawnCmd : Platform.Router msg Never -> MyCmd msg -> Task x () +spawnCmd router (Perform task) = + Native.Scheduler.spawn ( + task + |> andThen (Platform.sendToApp router) + ) diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm new file mode 100644 index 0000000..b50cdfe --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm @@ -0,0 +1,243 @@ +effect module Time where { subscription = MySub } exposing + ( Time + , now, every + , millisecond, second, minute, hour + , inMilliseconds, inSeconds, inMinutes, inHours + ) + +{-| Library for working with time. + +# Time +@docs Time, now, every + +# Units +@docs millisecond, second, minute, hour, + inMilliseconds, inSeconds, inMinutes, inHours + +-} + + +import Basics exposing (..) +import Dict +import List exposing ((::)) +import Maybe exposing (Maybe(..)) +import Native.Scheduler +import Native.Time +import Platform +import Platform.Sub exposing (Sub) +import Task exposing (Task) + + + +-- TIMES + + +{-| Type alias to make it clearer when you are working with time values. +Using the `Time` helpers like `second` and `inSeconds` instead of raw numbers +is very highly recommended. +-} +type alias Time = Float + + +{-| Get the `Time` at the moment when this task is run. +-} +now : Task x Time +now = + Native.Time.now + + +{-| Subscribe to the current time. First you provide an interval describing how +frequently you want updates. Second, you give a tagger that turns a time into a +message for your `update` function. So if you want to hear about the current +time every second, you would say something like this: + + type Msg = Tick Time | ... + + subscriptions model = + every second Tick + +Check out the [Elm Architecture Tutorial][arch] for more info on how +subscriptions work. + +[arch]: https://github.com/evancz/elm-architecture-tutorial/ + +**Note:** this function is not for animation! You need to use something based +on `requestAnimationFrame` to get smooth animations. This is based on +`setInterval` which is better for recurring tasks like “check on something +every 30 seconds”. +-} +every : Time -> (Time -> msg) -> Sub msg +every interval tagger = + subscription (Every interval tagger) + + + +-- UNITS + + +{-| Units of time, making it easier to specify things like a half-second +`(500 * millisecond)` without remembering Elm’s underlying units of time. +-} +millisecond : Time +millisecond = + 1 + + +{-|-} +second : Time +second = + 1000 * millisecond + + +{-|-} +minute : Time +minute = + 60 * second + + +{-|-} +hour : Time +hour = + 60 * minute + + +{-|-} +inMilliseconds : Time -> Float +inMilliseconds t = + t + + +{-|-} +inSeconds : Time -> Float +inSeconds t = + t / second + + +{-|-} +inMinutes : Time -> Float +inMinutes t = + t / minute + + +{-|-} +inHours : Time -> Float +inHours t = + t / hour + + + +-- SUBSCRIPTIONS + + +type MySub msg = + Every Time (Time -> msg) + + +subMap : (a -> b) -> MySub a -> MySub b +subMap f (Every interval tagger) = + Every interval (f << tagger) + + + +-- EFFECT MANAGER + + +type alias State msg = + { taggers : Taggers msg + , processes : Processes + } + + +type alias Processes = + Dict.Dict Time Platform.ProcessId + + +type alias Taggers msg = + Dict.Dict Time (List (Time -> msg)) + + +init : Task Never (State msg) +init = + Task.succeed (State Dict.empty Dict.empty) + + +onEffects : Platform.Router msg Time -> List (MySub msg) -> State msg -> Task Never (State msg) +onEffects router subs {processes} = + let + newTaggers = + List.foldl addMySub Dict.empty subs + + leftStep interval taggers (spawnList, existingDict, killTask) = + (interval :: spawnList, existingDict, killTask) + + bothStep interval taggers id (spawnList, existingDict, killTask) = + (spawnList, Dict.insert interval id existingDict, killTask) + + rightStep _ id (spawnList, existingDict, killTask) = + ( spawnList + , existingDict + , Native.Scheduler.kill id + |> Task.andThen (\_ -> killTask) + ) + + (spawnList, existingDict, killTask) = + Dict.merge + leftStep + bothStep + rightStep + newTaggers + processes + ([], Dict.empty, Task.succeed ()) + in + killTask + |> Task.andThen (\_ -> spawnHelp router spawnList existingDict) + |> Task.andThen (\newProcesses -> Task.succeed (State newTaggers newProcesses)) + + +addMySub : MySub msg -> Taggers msg -> Taggers msg +addMySub (Every interval tagger) state = + case Dict.get interval state of + Nothing -> + Dict.insert interval [tagger] state + + Just taggers -> + Dict.insert interval (tagger :: taggers) state + + +spawnHelp : Platform.Router msg Time -> List Time -> Processes -> Task.Task x Processes +spawnHelp router intervals processes = + case intervals of + [] -> + Task.succeed processes + + interval :: rest -> + let + spawnTimer = + Native.Scheduler.spawn (setInterval interval (Platform.sendToSelf router interval)) + + spawnRest id = + spawnHelp router rest (Dict.insert interval id processes) + in + spawnTimer + |> Task.andThen spawnRest + + +onSelfMsg : Platform.Router msg Time -> Time -> State msg -> Task Never (State msg) +onSelfMsg router interval state = + case Dict.get interval state.taggers of + Nothing -> + Task.succeed state + + Just taggers -> + let + tellTaggers time = + Task.sequence (List.map (\tagger -> Platform.sendToApp router (tagger time)) taggers) + in + now + |> Task.andThen tellTaggers + |> Task.andThen (\_ -> Task.succeed state) + + +setInterval : Time -> Task Never () -> Task x Never +setInterval = + Native.Time.setInterval_ diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm b/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm new file mode 100644 index 0000000..ab4c401 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm @@ -0,0 +1,61 @@ +module Tuple exposing + ( first, second + , mapFirst, mapSecond + ) + +{-| Some helpers for working with 2-tuples. + +**Note:** For larger chunks of data, it is best to switch to using records. So +instead of representing a 3D point as `(3,4,5)` and wondering why there are no +helper functions, represent it as `{ x = 3, y = 4, z = 5 }` and use all the +built-in syntax for records. + +@docs first, second, mapFirst, mapSecond + +-} + + + +{-| Extract the first value from a tuple. + + first (3, 4) == 3 + first ("john", "doe") == "john" +-} +first : (a1, a2) -> a1 +first (x,_) = + x + + +{-| Extract the second value from a tuple. + + second (3, 4) == 4 + second ("john", "doe") == "doe" +-} +second : (a1, a2) -> a2 +second (_,y) = + y + + +{-| Transform the first value in a tuple. + + import String + + mapFirst String.reverse ("stressed", 16) == ("desserts", 16) + mapFirst String.length ("stressed", 16) == (8, 16) +-} +mapFirst : (a -> b) -> (a, a2) -> (b, a2) +mapFirst func (x,y) = + (func x, y) + + +{-| Transform the second value in a tuple. + + import String + + mapSecond sqrt ("stressed", 16) == ("stressed", 4) + mapSecond (\x -> x + 1) ("stressed", 16) == ("stressed", 17) +-} +mapSecond : (a -> b) -> (a1, a) -> (a1, b) +mapSecond func (x,y) = + (x, func y) + diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm new file mode 100644 index 0000000..0fb81c9 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm @@ -0,0 +1,50 @@ +port module Main exposing (..) + +import Basics exposing (..) +import Task exposing (..) +import Test exposing (..) +import Platform.Cmd exposing (Cmd) +import Json.Decode exposing (Value) +import Test.Runner.Node exposing (run, TestProgram) +import Test.Array as Array +import Test.Basics as Basics +import Test.Bitwise as Bitwise +import Test.Char as Char +import Test.CodeGen as CodeGen +import Test.Dict as Dict +import Test.Maybe as Maybe +import Test.Equality as Equality +import Test.Json as Json +import Test.List as List +import Test.Result as Result +import Test.Set as Set +import Test.String as String +import Test.Regex as Regex + + +tests : Test +tests = + describe "Elm Standard Library Tests" + [ Array.tests + , Basics.tests + , Bitwise.tests + , Char.tests + , CodeGen.tests + , Dict.tests + , Equality.tests + , Json.tests + , List.tests + , Result.tests + , Set.tests + , String.tests + , Regex.tests + , Maybe.tests + ] + + +main : TestProgram +main = + run emit tests + + +port emit : ( String, Value ) -> Cmd msg diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm new file mode 100644 index 0000000..e32b49d --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm @@ -0,0 +1,120 @@ +module Test.Array exposing (tests) + +import Array +import Basics exposing (..) +import List +import List exposing ((::)) +import Maybe exposing (..) +import Native.Array +import Test exposing (..) +import Expect + + +mergeSplit : Int -> Array.Array a -> Array.Array a +mergeSplit n arr = + let + left = + Array.slice 0 n arr + + right = + Array.slice n (Array.length arr) arr + in + Array.append left right + + +holeArray : Array.Array Int +holeArray = + List.foldl mergeSplit (Array.fromList (List.range 0 100)) (List.range 0 100) + + +mapArray : Array.Array a -> Array.Array a +mapArray array = + Array.indexedMap + (\i el -> + case (Array.get i array) of + Just x -> + x + + Nothing -> + el + ) + array + + +tests : Test +tests = + let + creationTests = + describe "Creation" + [ test "empty" <| \() -> Expect.equal Array.empty (Array.fromList []) + , test "initialize" <| \() -> Expect.equal (Array.initialize 4 identity) (Array.fromList [ 0, 1, 2, 3 ]) + , test "initialize 2" <| \() -> Expect.equal (Array.initialize 4 (\n -> n * n)) (Array.fromList [ 0, 1, 4, 9 ]) + , test "initialize 3" <| \() -> Expect.equal (Array.initialize 4 (always 0)) (Array.fromList [ 0, 0, 0, 0 ]) + , test "initialize Empty" <| \() -> Expect.equal (Array.initialize 0 identity) Array.empty + , test "initialize 4" <| \() -> Expect.equal (Array.initialize 2 (always 0)) (Array.fromList [ 0, 0 ]) + , test "initialize negative" <| \() -> Expect.equal (Array.initialize -1 identity) Array.empty + , test "repeat" <| \() -> Expect.equal (Array.repeat 5 40) (Array.fromList [ 40, 40, 40, 40, 40 ]) + , test "repeat 2" <| \() -> Expect.equal (Array.repeat 5 0) (Array.fromList [ 0, 0, 0, 0, 0 ]) + , test "repeat 3" <| \() -> Expect.equal (Array.repeat 3 "cat") (Array.fromList [ "cat", "cat", "cat" ]) + , test "fromList" <| \() -> Expect.equal (Array.fromList []) Array.empty + ] + + basicsTests = + describe "Basics" + [ test "length" <| \() -> Expect.equal 3 (Array.length (Array.fromList [ 1, 2, 3 ])) + , test "length - Long" <| \() -> Expect.equal 10000 (Array.length (Array.repeat 10000 0)) + , test "push" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.push 3 (Array.fromList [ 1, 2 ])) + , test "append" <| \() -> Expect.equal [ 42, 42, 81, 81, 81 ] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81))) + , test "appendEmpty 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append Array.empty (Array.fromList <| List.range 1 33))) + , test "appendEmpty 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 33) Array.empty)) + , test "appendSmall 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 30) (Array.fromList <| List.range 31 33))) + , test "appendSmall 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 3) (Array.fromList <| List.range 4 33))) + , test "appendAndSlice" <| \() -> Expect.equal (List.range 0 100) (Array.toList holeArray) + ] + + getAndSetTests = + describe "Get and Set" + [ test "get" <| \() -> Expect.equal (Just 2) (Array.get 1 (Array.fromList [ 3, 2, 1 ])) + , test "get 2" <| \() -> Expect.equal Nothing (Array.get 5 (Array.fromList [ 3, 2, 1 ])) + , test "get 3" <| \() -> Expect.equal Nothing (Array.get -1 (Array.fromList [ 3, 2, 1 ])) + , test "set" <| \() -> Expect.equal (Array.fromList [ 1, 7, 3 ]) (Array.set 1 7 (Array.fromList [ 1, 2, 3 ])) + ] + + takingArraysApartTests = + describe "Taking Arrays Apart" + [ test "toList" <| \() -> Expect.equal [ 3, 5, 8 ] (Array.toList (Array.fromList [ 3, 5, 8 ])) + , test "toIndexedList" <| \() -> Expect.equal [ ( 0, "cat" ), ( 1, "dog" ) ] (Array.toIndexedList (Array.fromList [ "cat", "dog" ])) + , test "slice 1" <| \() -> Expect.equal (Array.fromList [ 0, 1, 2 ]) (Array.slice 0 3 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 2" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 4 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 3" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 -1 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 4" <| \() -> Expect.equal (Array.fromList [ 2 ]) (Array.slice -3 -2 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 5" <| \() -> Expect.equal 63 (Array.length <| Array.slice 65 (65 + 63) <| Array.fromList (List.range 1 200)) + ] + + mappingAndFoldingTests = + describe "Mapping and Folding" + [ test "map" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.map sqrt (Array.fromList [ 1, 4, 9 ])) + , test "indexedMap 1" <| \() -> Expect.equal (Array.fromList [ 0, 5, 10 ]) (Array.indexedMap (*) (Array.fromList [ 5, 5, 5 ])) + , test "indexedMap 2" <| \() -> Expect.equal (List.range 0 99) (Array.toList (Array.indexedMap always (Array.repeat 100 0))) + , test "large indexed map" <| \() -> Expect.equal (List.range 0 <| 32768 - 1) (Array.toList <| mapArray <| Array.initialize 32768 identity) + , test "foldl 1" <| \() -> Expect.equal [ 3, 2, 1 ] (Array.foldl (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldl 2" <| \() -> Expect.equal 33 (Array.foldl (+) 0 (Array.repeat 33 1)) + , test "foldr 1" <| \() -> Expect.equal 15 (Array.foldr (+) 0 (Array.repeat 3 5)) + , test "foldr 2" <| \() -> Expect.equal [ 1, 2, 3 ] (Array.foldr (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldr 3" <| \() -> Expect.equal 53 (Array.foldr (-) 54 (Array.fromList [ 10, 11 ])) + , test "filter" <| \() -> Expect.equal (Array.fromList [ 2, 4, 6 ]) (Array.filter (\x -> x % 2 == 0) (Array.fromList <| List.range 1 6)) + ] + + nativeTests = + describe "Conversion to JS Arrays" + [ test "jsArrays" <| \() -> Expect.equal (Array.fromList <| List.range 1 1100) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList <| List.range 1 1100))) + ] + in + describe "Array" + [ creationTests + , basicsTests + , getAndSetTests + , takingArraysApartTests + , mappingAndFoldingTests + , nativeTests + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm new file mode 100644 index 0000000..56742cb --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm @@ -0,0 +1,220 @@ +module Test.Basics exposing (tests) + +import Array +import Tuple exposing (first, second) +import Basics exposing (..) +import Date +import Set +import Dict +import Test exposing (..) +import Expect +import List +import String + + +tests : Test +tests = + let + comparison = + describe "Comparison" + [ test "max" <| \() -> Expect.equal 42 (max 32 42) + , test "min" <| \() -> Expect.equal 42 (min 91 42) + , test "clamp low" <| \() -> Expect.equal 10 (clamp 10 20 5) + , test "clamp mid" <| \() -> Expect.equal 15 (clamp 10 20 15) + , test "clamp high" <| \() -> Expect.equal 20 (clamp 10 20 25) + , test "5 < 6" <| \() -> Expect.equal True (5 < 6) + , test "6 < 5" <| \() -> Expect.equal False (6 < 5) + , test "6 < 6" <| \() -> Expect.equal False (6 < 6) + , test "5 > 6" <| \() -> Expect.equal False (5 > 6) + , test "6 > 5" <| \() -> Expect.equal True (6 > 5) + , test "6 > 6" <| \() -> Expect.equal False (6 > 6) + , test "5 <= 6" <| \() -> Expect.equal True (5 <= 6) + , test "6 <= 5" <| \() -> Expect.equal False (6 <= 5) + , test "6 <= 6" <| \() -> Expect.equal True (6 <= 6) + , test "compare \"A\" \"B\"" <| \() -> Expect.equal LT (compare "A" "B") + , test "compare 'f' 'f'" <| \() -> Expect.equal EQ (compare 'f' 'f') + , test "compare (1, 2, 3, 4, 5, 6) (0, 1, 2, 3, 4, 5)" <| \() -> Expect.equal GT (compare ( 1, 2, 3, 4, 5, 6 ) ( 0, 1, 2, 3, 4, 5 )) + , test "compare ['a'] ['b']" <| \() -> Expect.equal LT (compare [ 'a' ] [ 'b' ]) + , test "array equality" <| \() -> Expect.equal (Array.fromList [ 1, 1, 1, 1 ]) (Array.repeat 4 1) + , test "set equality" <| \() -> Expect.equal (Set.fromList [ 1, 2 ]) (Set.fromList [ 2, 1 ]) + , test "dict equality" <| \() -> Expect.equal (Dict.fromList [ ( 1, 1 ), ( 2, 2 ) ]) (Dict.fromList [ ( 2, 2 ), ( 1, 1 ) ]) + , test "char equality" <| \() -> Expect.notEqual '0' '饑' + , test "date equality" <| \() -> Expect.equal (Date.fromString "2/7/1992") (Date.fromString "2/7/1992") + , test "date equality" <| \() -> Expect.notEqual (Date.fromString "11/16/1995") (Date.fromString "2/7/1992") + ] + + toStringTests = + describe "toString Tests" + [ test "toString Int" <| \() -> Expect.equal "42" (toString 42) + , test "toString Float" <| \() -> Expect.equal "42.52" (toString 42.52) + , test "toString Char" <| \() -> Expect.equal "'c'" (toString 'c') + , test "toString Char single quote" <| \() -> Expect.equal "'\\''" (toString '\'') + , test "toString Char double quote" <| \() -> Expect.equal "'\"'" (toString '"') + , test "toString String single quote" <| \() -> Expect.equal "\"not 'escaped'\"" (toString "not 'escaped'") + , test "toString String double quote" <| \() -> Expect.equal "\"are \\\"escaped\\\"\"" (toString "are \"escaped\"") + , test "toString record" <| \() -> Expect.equal "{ field = [0] }" (toString { field = [ 0 ] }) + -- TODO + --, test "toString record, special case" <| \() -> Expect.equal "{ ctor = [0] }" (toString { ctor = [ 0 ] }) + ] + + trigTests = + describe "Trigonometry Tests" + [ test "radians 0" <| \() -> Expect.equal 0 (radians 0) + , test "radians positive" <| \() -> Expect.equal 5 (radians 5) + , test "radians negative" <| \() -> Expect.equal -5 (radians -5) + , test "degrees 0" <| \() -> Expect.equal 0 (degrees 0) + , test "degrees 90" <| \() -> Expect.lessThan 0.01 (abs (1.57 - degrees 90)) + -- This should test to enough precision to know if anything's breaking + , test "degrees -145" <| \() -> Expect.lessThan 0.01 (abs (-2.53 - degrees -145)) + -- This should test to enough precision to know if anything's breaking + , test "turns 0" <| \() -> Expect.equal 0 (turns 0) + , test "turns 8" <| \() -> Expect.lessThan 0.01 (abs (50.26 - turns 8)) + -- This should test to enough precision to know if anything's breaking + , test "turns -133" <| \() -> Expect.lessThan 0.01 (abs (-835.66 - turns -133)) + -- This should test to enough precision to know if anything's breaking + , test "fromPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 0 )) + , test "fromPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (fromPolar ( 1, 0 )) + , test "fromPolar (0, 1)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 1 )) + , test "fromPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( x, y ) = + fromPolar ( 1, 1 ) + in + 0.54 - x < 0.01 && 0.84 - y < 0.01 + ) + , test "toPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (toPolar ( 0, 0 )) + , test "toPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (toPolar ( 1, 0 )) + , test "toPolar (0, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 0, 1 ) + in + r == 1 && abs (1.57 - theta) < 0.01 + ) + , test "toPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 1, 1 ) + in + abs (1.41 - r) < 0.01 && abs (0.78 - theta) < 0.01 + ) + , test "cos" <| \() -> Expect.equal 1 (cos 0) + , test "sin" <| \() -> Expect.equal 0 (sin 0) + , test "tan" <| \() -> Expect.lessThan 0.01 (abs (12.67 - tan 17.2)) + , test "acos" <| \() -> Expect.lessThan 0.01 (abs (3.14 - acos -1)) + , test "asin" <| \() -> Expect.lessThan 0.01 (abs (0.3 - asin 0.3)) + , test "atan" <| \() -> Expect.lessThan 0.01 (abs (1.57 - atan 4567.8)) + , test "atan2" <| \() -> Expect.lessThan 0.01 (abs (1.55 - atan2 36 0.65)) + , test "pi" <| \() -> Expect.lessThan 0.01 (abs (3.14 - pi)) + ] + + basicMathTests = + describe "Basic Math Tests" + [ test "add float" <| \() -> Expect.equal 159 (155.6 + 3.4) + , test "add int" <| \() -> Expect.equal 17 ((round 10) + (round 7)) + , test "subtract float" <| \() -> Expect.equal -6.3 (1 - 7.3) + , test "subtract int" <| \() -> Expect.equal 1130 ((round 9432) - (round 8302)) + , test "multiply float" <| \() -> Expect.equal 432 (96 * 4.5) + , test "multiply int" <| \() -> Expect.equal 90 ((round 10) * (round 9)) + , test "divide float" <| \() -> Expect.equal 13.175 (527 / 40) + , test "divide int" <| \() -> Expect.equal 23 (70 // 3) + , test "2 |> rem 7" <| \() -> Expect.equal 1 (2 |> rem 7) + , test "4 |> rem -1" <| \() -> Expect.equal -1 (4 |> rem -1) + , test "7 % 2" <| \() -> Expect.equal 1 (7 % 2) + , test "-1 % 4" <| \() -> Expect.equal 3 (-1 % 4) + , test "3^2" <| \() -> Expect.equal 9 (3 ^ 2) + , test "sqrt" <| \() -> Expect.equal 9 (sqrt 81) + , test "negate 42" <| \() -> Expect.equal -42 (negate 42) + , test "negate -42" <| \() -> Expect.equal 42 (negate -42) + , test "negate 0" <| \() -> Expect.equal 0 (negate 0) + , test "abs -25" <| \() -> Expect.equal 25 (abs -25) + , test "abs 76" <| \() -> Expect.equal 76 (abs 76) + , test "logBase 10 100" <| \() -> Expect.equal 2 (logBase 10 100) + , test "logBase 2 256" <| \() -> Expect.equal 8 (logBase 2 256) + , test "e" <| \() -> Expect.lessThan 0.01 (abs (2.72 - e)) + ] + + booleanTests = + describe "Boolean Tests" + [ test "False && False" <| \() -> Expect.equal False (False && False) + , test "False && True" <| \() -> Expect.equal False (False && True) + , test "True && False" <| \() -> Expect.equal False (True && False) + , test "True && True" <| \() -> Expect.equal True (True && True) + , test "False || False" <| \() -> Expect.equal False (False || False) + , test "False || True" <| \() -> Expect.equal True (False || True) + , test "True || False" <| \() -> Expect.equal True (True || False) + , test "True || True" <| \() -> Expect.equal True (True || True) + , test "xor False False" <| \() -> Expect.equal False (xor False False) + , test "xor False True" <| \() -> Expect.equal True (xor False True) + , test "xor True False" <| \() -> Expect.equal True (xor True False) + , test "xor True True" <| \() -> Expect.equal False (xor True True) + , test "not True" <| \() -> Expect.equal False (not True) + , test "not False" <| \() -> Expect.equal True (not False) + ] + + conversionTests = + describe "Conversion Tests" + [ test "round 0.6" <| \() -> Expect.equal 1 (round 0.6) + , test "round 0.4" <| \() -> Expect.equal 0 (round 0.4) + , test "round 0.5" <| \() -> Expect.equal 1 (round 0.5) + , test "truncate -2367.9267" <| \() -> Expect.equal -2367 (truncate -2367.9267) + , test "floor -2367.9267" <| \() -> Expect.equal -2368 (floor -2367.9267) + , test "ceiling 37.2" <| \() -> Expect.equal 38 (ceiling 37.2) + , test "toFloat 25" <| \() -> Expect.equal 25 (toFloat 25) + ] + + miscTests = + describe "Miscellaneous Tests" + [ test "isNaN (0/0)" <| \() -> Expect.equal True (isNaN (0 / 0)) + , test "isNaN (sqrt -1)" <| \() -> Expect.equal True (isNaN (sqrt -1)) + , test "isNaN (1/0)" <| \() -> Expect.equal False (isNaN (1 / 0)) + , test "isNaN 1" <| \() -> Expect.equal False (isNaN 1) + , test "isInfinite (0/0)" <| \() -> Expect.equal False (isInfinite (0 / 0)) + , test "isInfinite (sqrt -1)" <| \() -> Expect.equal False (isInfinite (sqrt -1)) + , test "isInfinite (1/0)" <| \() -> Expect.equal True (isInfinite (1 / 0)) + , test "isInfinite 1" <| \() -> Expect.equal False (isInfinite 1) + , test "\"hello\" ++ \"world\"" <| \() -> Expect.equal "helloworld" ("hello" ++ "world") + , test "[1, 1, 2] ++ [3, 5, 8]" <| \() -> Expect.equal [ 1, 1, 2, 3, 5, 8 ] ([ 1, 1, 2 ] ++ [ 3, 5, 8 ]) + , test "first (1, 2)" <| \() -> Expect.equal 1 (first ( 1, 2 )) + , test "second (1, 2)" <| \() -> Expect.equal 2 (second ( 1, 2 )) + ] + + higherOrderTests = + describe "Higher Order Helpers" + [ test "identity 'c'" <| \() -> Expect.equal 'c' (identity 'c') + , test "always 42 ()" <| \() -> Expect.equal 42 (always 42 ()) + , test "<|" <| \() -> Expect.equal 9 (identity <| 3 + 6) + , test "|>" <| \() -> Expect.equal 9 (3 + 6 |> identity) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , describe ">>" + [ test "with xor" <| + \() -> + (True |> xor True >> not) + |> Expect.equal True + , test "with a record accessor" <| + \() -> + [ { foo = "NaS", bar = "baz" } ] + |> List.map (.foo >> String.reverse) + |> Expect.equal [ "SaN" ] + ] + , test "flip" <| \() -> Expect.equal 10 ((flip (//)) 2 20) + , test "curry" <| \() -> Expect.equal 1 ((curry (\( a, b ) -> a + b)) -5 6) + , test "uncurry" <| \() -> Expect.equal 1 ((uncurry (+)) ( -5, 6 )) + ] + in + describe "Basics" + [ comparison + , toStringTests + , trigTests + , basicMathTests + , booleanTests + , miscTests + , higherOrderTests + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm new file mode 100644 index 0000000..844ebba --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm @@ -0,0 +1,51 @@ +module Test.Bitwise exposing (tests) + +import Basics exposing (..) +import Bitwise +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Bitwise" + [ describe "and" + [ test "and with 32 bit integers" <| \() -> Expect.equal 1 (Bitwise.and 5 3) + , test "and with 0 as first argument" <| \() -> Expect.equal 0 (Bitwise.and 0 1450) + , test "and with 0 as second argument" <| \() -> Expect.equal 0 (Bitwise.and 274 0) + , test "and with -1 as first argument" <| \() -> Expect.equal 2671 (Bitwise.and -1 2671) + , test "and with -1 as second argument" <| \() -> Expect.equal 96 (Bitwise.and 96 -1) + ] + , describe "or" + [ test "or with 32 bit integers" <| \() -> Expect.equal 15 (Bitwise.or 9 14) + , test "or with 0 as first argument" <| \() -> Expect.equal 843 (Bitwise.or 0 843) + , test "or with 0 as second argument" <| \() -> Expect.equal 19 (Bitwise.or 19 0) + , test "or with -1 as first argument" <| \() -> Expect.equal -1 (Bitwise.or -1 2360) + , test "or with -1 as second argument" <| \() -> Expect.equal -1 (Bitwise.or 3 -1) + ] + , describe "xor" + [ test "xor with 32 bit integers" <| \() -> Expect.equal 604 (Bitwise.xor 580 24) + , test "xor with 0 as first argument" <| \() -> Expect.equal 56 (Bitwise.xor 0 56) + , test "xor with 0 as second argument" <| \() -> Expect.equal -268 (Bitwise.xor -268 0) + , test "xor with -1 as first argument" <| \() -> Expect.equal -25 (Bitwise.xor -1 24) + , test "xor with -1 as second argument" <| \() -> Expect.equal 25601 (Bitwise.xor -25602 -1) + ] + , describe "complement" + [ test "complement a positive" <| \() -> Expect.equal -9 (Bitwise.complement 8) + , test "complement a negative" <| \() -> Expect.equal 278 (Bitwise.complement -279) + ] + , describe "shiftLeftBy" + [ test "8 |> shiftLeftBy 1 == 16" <| \() -> Expect.equal 16 (8 |> Bitwise.shiftLeftBy 1) + , test "8 |> shiftLeftby 2 == 32" <| \() -> Expect.equal 32 (8 |> Bitwise.shiftLeftBy 2) + ] + , describe "shiftRightBy" + [ test "32 |> shiftRight 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightBy 1) + , test "32 |> shiftRight 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightBy 2) + , test "-32 |> shiftRight 1 == -16" <| \() -> Expect.equal -16 (-32 |> Bitwise.shiftRightBy 1) + ] + , describe "shiftRightZfBy" + [ test "32 |> shiftRightZfBy 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightZfBy 1) + , test "32 |> shiftRightZfBy 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightZfBy 2) + , test "-32 |> shiftRightZfBy 1 == 2147483632" <| \() -> Expect.equal 2147483632 (-32 |> Bitwise.shiftRightZfBy 1) + ] + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm new file mode 100644 index 0000000..598aae3 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm @@ -0,0 +1,113 @@ +module Test.Char exposing (tests) + +import Basics exposing (..) +import Char exposing (..) +import List +import Test exposing (..) +import Expect + + +lower = + [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] + + +upper = + [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] + + +dec = + [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] + + +oct = + List.take 8 dec + + +hexLower = + List.take 6 lower + + +hexUpper = + List.take 6 upper + + +hex = + List.append hexLower hexUpper |> List.append dec + + +lowerCodes = + List.range 97 (97 + List.length lower - 1) + + +upperCodes = + List.range 65 (65 + List.length upper - 1) + + +decCodes = + List.range 48 (48 + List.length dec - 1) + + +oneOf : List a -> a -> Bool +oneOf = + flip List.member + + +tests : Test +tests = + describe "Char" + [ describe "toCode" + [ test "a-z" <| \() -> Expect.equal (lowerCodes) (List.map toCode lower) + , test "A-Z" <| \() -> Expect.equal (upperCodes) (List.map toCode upper) + , test "0-9" <| \() -> Expect.equal (decCodes) (List.map toCode dec) + ] + , describe "fromCode" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map fromCode lowerCodes) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map fromCode upperCodes) + , test "0-9" <| \() -> Expect.equal (dec) (List.map fromCode decCodes) + ] + , describe "toLocaleLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLocaleLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLocaleLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleLower dec) + ] + , describe "toLocaleUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleUpper dec) + ] + , describe "toLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLower dec) + ] + , describe "toUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toUpper dec) + ] + , describe "isLower" + [ test "a-z" <| \() -> Expect.equal (True) (List.all isLower lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isLower upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isLower dec) + ] + , describe "isUpper" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isUpper lower) + , test "A-Z" <| \() -> Expect.equal (True) (List.all isUpper upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isUpper dec) + ] + , describe "isDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isDigit dec) + ] + , describe "isHexDigit" + [ test "a-z" <| \() -> Expect.equal (List.map (oneOf hex) lower) (List.map isHexDigit lower) + , test "A-Z" <| \() -> Expect.equal (List.map (oneOf hex) upper) (List.map isHexDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isHexDigit dec) + ] + , describe "isOctDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isOctDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isOctDigit upper) + , test "0-9" <| \() -> Expect.equal (List.map (oneOf oct) dec) (List.map isOctDigit dec) + ] + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm new file mode 100644 index 0000000..4a89c63 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm @@ -0,0 +1,109 @@ +module Test.CodeGen exposing (tests) + +import Basics exposing (..) +import Test exposing (..) +import Expect +import Maybe +import Maybe exposing (..) + + +type Wrapper a + = Wrapper a + + +caseUnderscore : Maybe number -> number +caseUnderscore m_ = + case m_ of + Just x -> + x + + Nothing -> + 0 + + +patternUnderscore : number +patternUnderscore = + case Just 42 of + Just x_ -> + x_ + + Nothing -> + 0 + + +letQualified : number +letQualified = + let + (Wrapper x) = + Wrapper 42 + in + x + + +caseQualified : number +caseQualified = + case Just 42 of + Maybe.Just x -> + x + + Nothing -> + 0 + + +caseScope : String +caseScope = + case "Not this one!" of + string -> + case "Hi" of + string -> + string + + +tests : Test +tests = + let + -- We don't strictly speaking need annotations in this let-expression, + -- but having these here exercises the parser to avoid regressions like + -- https://github.com/elm-lang/elm-compiler/issues/1535 + underscores : Test + underscores = + describe "Underscores" + [ test "case" <| \() -> Expect.equal 42 (caseUnderscore (Just 42)) + , test "pattern" <| \() -> Expect.equal 42 patternUnderscore + ] + + qualifiedPatterns : Test + qualifiedPatterns = + describe "Qualified Patterns" + [ test "let" <| \() -> Expect.equal 42 letQualified + , test "case" <| \() -> Expect.equal 42 caseQualified + ] + + scope : Test + scope = + describe "Scoping" + [ test "case" <| \() -> Expect.equal "Hi" caseScope ] + + hex : Test + hex = + describe "Hex" + [ test "0xFFFFFFFF" <| + \() -> + 0xFFFFFFFF + |> Expect.equal 4294967295 + , test "0xD066F00D" <| + \() -> + 0xD066F00D + |> Expect.equal 3496407053 + , test "0x00" <| + \() -> + 0x00 + |> Expect.equal 0 + ] + in + describe "CodeGen" + [ underscores + , qualifiedPatterns + , scope + , hex + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm new file mode 100644 index 0000000..372b2c9 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm @@ -0,0 +1,107 @@ +module Test.Dict exposing (tests) + +import Basics exposing (..) +import Dict +import List +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +animals : Dict.Dict String String +animals = + Dict.fromList [ ( "Tom", "cat" ), ( "Jerry", "mouse" ) ] + + +tests : Test +tests = + let + buildTests = + describe "build Tests" + [ test "empty" <| \() -> Expect.equal (Dict.fromList []) (Dict.empty) + , test "singleton" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.singleton "k" "v") + , test "insert" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.insert "k" "v" Dict.empty) + , test "insert replace" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.insert "k" "vv" (Dict.singleton "k" "v")) + , test "update" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.update "k" (\v -> Just "vv") (Dict.singleton "k" "v")) + , test "update Nothing" <| \() -> Expect.equal Dict.empty (Dict.update "k" (\v -> Nothing) (Dict.singleton "k" "v")) + , test "remove" <| \() -> Expect.equal Dict.empty (Dict.remove "k" (Dict.singleton "k" "v")) + , test "remove not found" <| \() -> Expect.equal (Dict.singleton "k" "v") (Dict.remove "kk" (Dict.singleton "k" "v")) + ] + + queryTests = + describe "query Tests" + [ test "member 1" <| \() -> Expect.equal True (Dict.member "Tom" animals) + , test "member 2" <| \() -> Expect.equal False (Dict.member "Spike" animals) + , test "get 1" <| \() -> Expect.equal (Just "cat") (Dict.get "Tom" animals) + , test "get 2" <| \() -> Expect.equal Nothing (Dict.get "Spike" animals) + , test "size of empty dictionary" <| \() -> Expect.equal 0 (Dict.size Dict.empty) + , test "size of example dictionary" <| \() -> Expect.equal 2 (Dict.size animals) + ] + + combineTests = + describe "combine Tests" + [ test "union" <| \() -> Expect.equal animals (Dict.union (Dict.singleton "Jerry" "mouse") (Dict.singleton "Tom" "cat")) + , test "union collison" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.union (Dict.singleton "Tom" "cat") (Dict.singleton "Tom" "mouse")) + , test "intersect" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.intersect animals (Dict.singleton "Tom" "cat")) + , test "diff" <| \() -> Expect.equal (Dict.singleton "Jerry" "mouse") (Dict.diff animals (Dict.singleton "Tom" "cat")) + ] + + transformTests = + describe "transform Tests" + [ test "filter" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals) + , test "partition" <| \() -> Expect.equal ( Dict.singleton "Tom" "cat", Dict.singleton "Jerry" "mouse" ) (Dict.partition (\k v -> k == "Tom") animals) + ] + + mergeTests = + let + insertBoth key leftVal rightVal dict = + Dict.insert key (leftVal ++ rightVal) dict + + s1 = + Dict.empty |> Dict.insert "u1" [ 1 ] + + s2 = + Dict.empty |> Dict.insert "u2" [ 2 ] + + s23 = + Dict.empty |> Dict.insert "u2" [ 3 ] + + b1 = + List.map (\i -> ( i, [ i ] )) (List.range 1 10) |> Dict.fromList + + b2 = + List.map (\i -> ( i, [ i ] )) (List.range 5 15) |> Dict.fromList + + bExpected = + [ ( 1, [ 1 ] ), ( 2, [ 2 ] ), ( 3, [ 3 ] ), ( 4, [ 4 ] ), ( 5, [ 5, 5 ] ), ( 6, [ 6, 6 ] ), ( 7, [ 7, 7 ] ), ( 8, [ 8, 8 ] ), ( 9, [ 9, 9 ] ), ( 10, [ 10, 10 ] ), ( 11, [ 11 ] ), ( 12, [ 12 ] ), ( 13, [ 13 ] ), ( 14, [ 14 ] ), ( 15, [ 15 ] ) ] + in + describe "merge Tests" + [ test "merge empties" <| + \() -> + Expect.equal (Dict.empty) + (Dict.merge Dict.insert insertBoth Dict.insert Dict.empty Dict.empty Dict.empty) + , test "merge singletons in order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s1 s2 Dict.empty) |> Dict.toList) + , test "merge singletons out of order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s1 Dict.empty) |> Dict.toList) + , test "merge with duplicate key" <| + \() -> + Expect.equal [ ( "u2", [ 2, 3 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s23 Dict.empty) |> Dict.toList) + , test "partially overlapping" <| + \() -> + Expect.equal bExpected + ((Dict.merge Dict.insert insertBoth Dict.insert b1 b2 Dict.empty) |> Dict.toList) + ] + in + describe "Dict Tests" + [ buildTests + , queryTests + , combineTests + , transformTests + , mergeTests + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm new file mode 100644 index 0000000..1737477 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm @@ -0,0 +1,34 @@ +module Test.Equality exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +type Different + = A String + | B (List Int) + + +tests : Test +tests = + let + diffTests = + describe "ADT equality" + [ test "As eq" <| \() -> Expect.equal True (A "a" == A "a") + , test "Bs eq" <| \() -> Expect.equal True (B [ 1 ] == B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (A "a" /= B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (B [ 1 ] /= A "a") + ] + + recordTests = + describe "Record equality" + [ test "empty same" <| \() -> Expect.equal True ({} == {}) + , test "ctor same" <| \() -> Expect.equal True ({ field = Just 3 } == { field = Just 3 }) + , test "ctor same, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } == { ctor = Just 3 }) + , test "ctor diff" <| \() -> Expect.equal True ({ field = Just 3 } /= { field = Nothing }) + , test "ctor diff, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } /= { ctor = Nothing }) + ] + in + describe "Equality Tests" [ diffTests, recordTests ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm new file mode 100644 index 0000000..614a1dd --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm @@ -0,0 +1,84 @@ +module Test.Json exposing (tests) + +import Basics exposing (..) +import Result exposing (..) +import Json.Decode as Json +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Json decode" + [ intTests + , customTests + ] + + +intTests : Test +intTests = + let + testInt val str = + case Json.decodeString Json.int str of + Ok _ -> + Expect.equal val True + + Err _ -> + Expect.equal val False + in + describe "Json decode int" + [ test "whole int" <| \() -> testInt True "4" + , test "-whole int" <| \() -> testInt True "-4" + , test "whole float" <| \() -> testInt True "4.0" + , test "-whole float" <| \() -> testInt True "-4.0" + , test "large int" <| \() -> testInt True "1801439850948" + , test "-large int" <| \() -> testInt True "-1801439850948" + , test "float" <| \() -> testInt False "4.2" + , test "-float" <| \() -> testInt False "-4.2" + , test "Infinity" <| \() -> testInt False "Infinity" + , test "-Infinity" <| \() -> testInt False "-Infinity" + , test "NaN" <| \() -> testInt False "NaN" + , test "-NaN" <| \() -> testInt False "-NaN" + , test "true" <| \() -> testInt False "true" + , test "false" <| \() -> testInt False "false" + , test "string" <| \() -> testInt False "\"string\"" + , test "object" <| \() -> testInt False "{}" + , test "null" <| \() -> testInt False "null" + , test "undefined" <| \() -> testInt False "undefined" + , test "Decoder expects object finds array, was crashing runtime." <| + \() -> + Expect.equal + (Err "Expecting an object but instead got: []") + (Json.decodeString (Json.dict Json.float) "[]") + ] + + +customTests : Test +customTests = + let + jsonString = + """{ "foo": "bar" }""" + + customErrorMessage = + "I want to see this message!" + + myDecoder = + Json.field "foo" Json.string |> Json.andThen (\_ -> Json.fail customErrorMessage) + + assertion = + case Json.decodeString myDecoder jsonString of + Ok _ -> + Expect.fail "expected `customDecoder` to produce a value of type Err, but got Ok" + + Err message -> + if String.contains customErrorMessage message then + Expect.pass + else + Expect.fail <| + "expected `customDecoder` to preserve user's error message '" + ++ customErrorMessage + ++ "', but instead got: " + ++ message + in + test "customDecoder preserves user error messages" <| \() -> assertion diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm new file mode 100644 index 0000000..ed26f0f --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm @@ -0,0 +1,160 @@ +module Test.List exposing (tests) + +import Test exposing (..) +import Expect +import Basics exposing (..) +import Maybe exposing (Maybe(Nothing, Just)) +import List exposing (..) + + +tests : Test +tests = + describe "List Tests" + [ testListOfN 0 + , testListOfN 1 + , testListOfN 2 + , testListOfN 5000 + ] + + +testListOfN : Int -> Test +testListOfN n = + let + xs = + List.range 1 n + + xsOpp = + List.range -n -1 + + xsNeg = + foldl (::) [] xsOpp + + -- assume foldl and (::) work + zs = + List.range 0 n + + sumSeq k = + k * (k + 1) // 2 + + xsSum = + sumSeq n + + mid = + n // 2 + in + describe (toString n ++ " elements") + [ describe "foldl" + [ test "order" <| \() -> Expect.equal (n) (foldl (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "foldr" + [ test "order" <| \() -> Expect.equal (min 1 n) (foldr (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "map" + [ test "identity" <| \() -> Expect.equal (xs) (map identity xs) + , test "linear" <| \() -> Expect.equal (List.range 2 (n + 1)) (map ((+) 1) xs) + ] + , test "isEmpty" <| \() -> Expect.equal (n == 0) (isEmpty xs) + , test "length" <| \() -> Expect.equal (n) (length xs) + , test "reverse" <| \() -> Expect.equal (xsOpp) (reverse xsNeg) + , describe "member" + [ test "positive" <| \() -> Expect.equal (True) (member n zs) + , test "negative" <| \() -> Expect.equal (False) (member (n + 1) xs) + ] + , test "head" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (head xs) + else + Expect.equal (Just 1) (head xs) + , describe "List.filter" + [ test "none" <| \() -> Expect.equal ([]) (List.filter (\x -> x > n) xs) + , test "one" <| \() -> Expect.equal ([ n ]) (List.filter (\z -> z == n) zs) + , test "all" <| \() -> Expect.equal (xs) (List.filter (\x -> x <= n) xs) + ] + , describe "take" + [ test "none" <| \() -> Expect.equal ([]) (take 0 xs) + , test "some" <| \() -> Expect.equal (List.range 0 (n - 1)) (take n zs) + , test "all" <| \() -> Expect.equal (xs) (take n xs) + , test "all+" <| \() -> Expect.equal (xs) (take (n + 1) xs) + ] + , describe "drop" + [ test "none" <| \() -> Expect.equal (xs) (drop 0 xs) + , test "some" <| \() -> Expect.equal ([ n ]) (drop n zs) + , test "all" <| \() -> Expect.equal ([]) (drop n xs) + , test "all+" <| \() -> Expect.equal ([]) (drop (n + 1) xs) + ] + , test "repeat" <| \() -> Expect.equal (map (\x -> -1) xs) (repeat n -1) + , test "append" <| \() -> Expect.equal (xsSum * 2) (append xs xs |> foldl (+) 0) + , test "(::)" <| \() -> Expect.equal (append [ -1 ] xs) (-1 :: xs) + , test "List.concat" <| \() -> Expect.equal (append xs (append zs xs)) (List.concat [ xs, zs, xs ]) + , test "intersperse" <| + \() -> + Expect.equal + ( min -(n - 1) 0, xsSum ) + (intersperse -1 xs |> foldl (\x ( c1, c2 ) -> ( c2, c1 + x )) ( 0, 0 )) + , describe "partition" + [ test "left" <| \() -> Expect.equal ( xs, [] ) (partition (\x -> x > 0) xs) + , test "right" <| \() -> Expect.equal ( [], xs ) (partition (\x -> x < 0) xs) + , test "split" <| \() -> Expect.equal ( List.range (mid + 1) n, List.range 1 mid ) (partition (\x -> x > mid) xs) + ] + , describe "map2" + [ test "same length" <| \() -> Expect.equal (map ((*) 2) xs) (map2 (+) xs xs) + , test "long first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) zs xs) + , test "short first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) xs zs) + ] + , test "unzip" <| \() -> Expect.equal ( xsNeg, xs ) (map (\x -> ( -x, x )) xs |> unzip) + , describe "filterMap" + [ test "none" <| \() -> Expect.equal ([]) (filterMap (\x -> Nothing) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (filterMap (\x -> Just -x) xs) + , let + halve x = + if x % 2 == 0 then + Just (x // 2) + else + Nothing + in + test "some" <| \() -> Expect.equal (List.range 1 mid) (filterMap halve xs) + ] + , describe "concatMap" + [ test "none" <| \() -> Expect.equal ([]) (concatMap (\x -> []) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (concatMap (\x -> [ -x ]) xs) + ] + , test "indexedMap" <| \() -> Expect.equal (map2 (,) zs xsNeg) (indexedMap (\i x -> ( i, -x )) xs) + , test "sum" <| \() -> Expect.equal (xsSum) (sum xs) + , test "product" <| \() -> Expect.equal (0) (product zs) + , test "maximum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (maximum xs) + else + Expect.equal (Just n) (maximum xs) + , test "minimum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (minimum xs) + else + Expect.equal (Just 1) (minimum xs) + , describe "all" + [ test "false" <| \() -> Expect.equal (False) (all (\z -> z < n) zs) + , test "true" <| \() -> Expect.equal (True) (all (\x -> x <= n) xs) + ] + , describe "any" + [ test "false" <| \() -> Expect.equal (False) (any (\x -> x > n) xs) + , test "true" <| \() -> Expect.equal (True) (any (\z -> z >= n) zs) + ] + , describe "sort" + [ test "sorted" <| \() -> Expect.equal (xs) (sort xs) + , test "unsorted" <| \() -> Expect.equal (xsOpp) (sort xsNeg) + ] + , describe "sortBy" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsOpp) + ] + , describe "sortWith" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsOpp) + ] + , test "scanl" <| \() -> Expect.equal (0 :: map sumSeq xs) (scanl (+) 0 xs) + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm new file mode 100644 index 0000000..dfa8e5e --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm @@ -0,0 +1,169 @@ +module Test.Maybe exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + +tests : Test +tests = + describe "Maybe Tests" + + [ describe "Common Helpers Tests" + + [ describe "withDefault Tests" + [ test "no default used" <| + \() -> Expect.equal 0 (Maybe.withDefault 5 (Just 0)) + , test "default used" <| + \() -> Expect.equal 5 (Maybe.withDefault 5 (Nothing)) + ] + + , describe "map Tests" + ( let f = (\n -> n + 1) in + [ test "on Just" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map f (Just 0)) + , test "on Nothing" <| + \() -> + Expect.equal + Nothing + (Maybe.map f Nothing) + ] + ) + + , describe "map2 Tests" + ( let f = (+) in + [ test "on (Just, Just)" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map2 f (Just 0) (Just 1)) + , test "on (Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f (Just 0) Nothing) + , test "on (Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f Nothing (Just 0)) + ] + ) + + , describe "map3 Tests" + ( let f = (\a b c -> a + b + c) in + [ test "on (Just, Just, Just)" <| + \() -> + Expect.equal + (Just 3) + (Maybe.map3 f (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) (Just 1) Nothing) + , test "on (Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) Nothing (Just 1)) + , test "on (Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f Nothing (Just 1) (Just 1)) + ] + ) + + , describe "map4 Tests" + ( let f = (\a b c d -> a + b + c + d) in + [ test "on (Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 4) + (Maybe.map4 f (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f Nothing (Just 1) (Just 1) (Just 1)) + ] + ) + + , describe "map5 Tests" + ( let f = (\a b c d e -> a + b + c + d + e) in + [ test "on (Just, Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 5) + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Just, Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) Nothing (Just 1) (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f Nothing (Just 1) (Just 1) (Just 1) (Just 1)) + ] + ) + + ] + + , describe "Chaining Maybes Tests" + + [ describe "andThen Tests" + [ test "succeeding chain" <| + \() -> + Expect.equal + (Just 1) + (Maybe.andThen (\a -> Just a) (Just 1)) + , test "failing chain (original Maybe failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Just a) Nothing) + , test "failing chain (chained function failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Nothing) (Just 1)) + ] + ] + + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm new file mode 100644 index 0000000..478d44b --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm @@ -0,0 +1,57 @@ +module Test.Regex exposing (tests) + +import Basics exposing (..) +import Regex exposing (..) +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "split All" <| \() -> Expect.equal [ "a", "b" ] (split All (regex ",") "a,b") + , test "split" <| \() -> Expect.equal [ "a", "b,c" ] (split (AtMost 1) (regex ",") "a,b,c") + , test "split idempotent" <| + \() -> + let + findComma = + regex "," + in + Expect.equal + (split (AtMost 1) findComma "a,b,c,d,e") + (split (AtMost 1) findComma "a,b,c,d,e") + , test "find All" <| + \() -> + Expect.equal + ([ Match "a" [] 0 1, Match "b" [] 1 2 ]) + (find All (regex ".") "ab") + , test "find All" <| + \() -> + Expect.equal + ([ Match "" [] 0 1 ]) + (find All (regex ".*") "") + , test "replace AtMost 0" <| + \() -> + Expect.equal "The quick brown fox" + (replace (AtMost 0) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 1" <| + \() -> + Expect.equal "Th quick brown fox" + (replace (AtMost 1) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 2" <| + \() -> + Expect.equal "Th qick brown fox" + (replace (AtMost 2) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace All" <| + \() -> + Expect.equal "Th qck brwn fx" + (replace All (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace using index" <| + \() -> + Expect.equal "a1b3c" + (replace All (regex ",") (\match -> toString match.index) "a,b,c") + ] + in + describe "Regex" [ simpleTests ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm new file mode 100644 index 0000000..6679e7e --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm @@ -0,0 +1,70 @@ +module Test.Result exposing (tests) + +import Basics exposing (..) +import Result +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +isEven n = + if n % 2 == 0 then + Ok n + else + Err "number is odd" + + +add3 a b c = + a + b + c + + +add4 a b c d = + a + b + c + d + + +add5 a b c d e = + a + b + c + d + e + + +tests : Test +tests = + let + mapTests = + describe "map Tests" + [ test "map Ok" <| \() -> Expect.equal (Ok 3) (Result.map ((+) 1) (Ok 2)) + , test "map Err" <| \() -> Expect.equal (Err "error") (Result.map ((+) 1) (Err "error")) + ] + + mapNTests = + describe "mapN Tests" + [ test "map2 Ok" <| \() -> Expect.equal (Ok 3) (Result.map2 (+) (Ok 1) (Ok 2)) + , test "map2 Err" <| \() -> Expect.equal (Err "x") (Result.map2 (+) (Ok 1) (Err "x")) + , test "map3 Ok" <| \() -> Expect.equal (Ok 6) (Result.map3 add3 (Ok 1) (Ok 2) (Ok 3)) + , test "map3 Err" <| \() -> Expect.equal (Err "x") (Result.map3 add3 (Ok 1) (Ok 2) (Err "x")) + , test "map4 Ok" <| \() -> Expect.equal (Ok 10) (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Ok 4)) + , test "map4 Err" <| \() -> Expect.equal (Err "x") (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Err "x")) + , test "map5 Ok" <| \() -> Expect.equal (Ok 15) (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Ok 5)) + , test "map5 Err" <| \() -> Expect.equal (Err "x") (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Err "x")) + ] + + andThenTests = + describe "andThen Tests" + [ test "andThen Ok" <| \() -> Expect.equal (Ok 42) ((String.toInt "42") |> Result.andThen isEven) + , test "andThen first Err" <| + \() -> + Expect.equal + (Err "could not convert string '4.2' to an Int") + (String.toInt "4.2" |> Result.andThen isEven) + , test "andThen second Err" <| + \() -> + Expect.equal + (Err "number is odd") + (String.toInt "41" |> Result.andThen isEven) + ] + in + describe "Result Tests" + [ mapTests + , mapNTests + , andThenTests + ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm new file mode 100644 index 0000000..e98caaa --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm @@ -0,0 +1,52 @@ +module Test.Set exposing (tests) + +import Basics exposing (..) +import Set +import Set exposing (Set) +import List +import Test exposing (..) +import Expect + + +set : Set Int +set = + Set.fromList <| List.range 1 100 + + +setPart1 : Set Int +setPart1 = + Set.fromList <| List.range 1 50 + + +setPart2 : Set Int +setPart2 = + Set.fromList <| List.range 51 100 + + +pred : Int -> Bool +pred x = + x <= 50 + + +tests : Test +tests = + let + queryTests = + describe "query Tests" + [ test "size of set of 100 elements" <| + \() -> Expect.equal 100 (Set.size set) + ] + + filterTests = + describe "filter Tests" + [ test "Simple filter" <| + \() -> Expect.equal setPart1 <| Set.filter pred set + ] + + partitionTests = + describe "partition Tests" + [ test "Simple partition" <| + \() -> Expect.equal ( setPart1, setPart2 ) <| Set.partition pred set + ] + in + describe "Set Tests" [ queryTests, partitionTests, filterTests ] diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm new file mode 100644 index 0000000..f682775 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm @@ -0,0 +1,110 @@ +module Test.String exposing (tests) + +import Basics exposing (..) +import List +import Maybe exposing (..) +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "is empty" <| \() -> Expect.equal True (String.isEmpty "") + , test "is not empty" <| \() -> Expect.equal True (not (String.isEmpty ("the world"))) + , test "length" <| \() -> Expect.equal 11 (String.length "innumerable") + , test "endsWith" <| \() -> Expect.equal True <| String.endsWith "ship" "spaceship" + , test "reverse" <| \() -> Expect.equal "desserts" (String.reverse "stressed") + , test "repeat" <| \() -> Expect.equal "hahaha" (String.repeat 3 "ha") + , test "indexes" <| \() -> Expect.equal [ 0, 2 ] (String.indexes "a" "aha") + , test "empty indexes" <| \() -> Expect.equal [] (String.indexes "" "aha") + ] + + combiningTests = + describe "Combining Strings" + [ test "uncons non-empty" <| \() -> Expect.equal (Just ( 'a', "bc" )) (String.uncons "abc") + , test "uncons empty" <| \() -> Expect.equal Nothing (String.uncons "") + , test "append 1" <| \() -> Expect.equal "butterfly" (String.append "butter" "fly") + , test "append 2" <| \() -> Expect.equal "butter" (String.append "butter" "") + , test "append 3" <| \() -> Expect.equal "butter" (String.append "" "butter") + , test "concat" <| \() -> Expect.equal "nevertheless" (String.concat [ "never", "the", "less" ]) + , test "split commas" <| \() -> Expect.equal [ "cat", "dog", "cow" ] (String.split "," "cat,dog,cow") + , test "split slashes" <| \() -> Expect.equal [ "home", "steve", "Desktop", "" ] (String.split "/" "home/steve/Desktop/") + , test "join spaces" <| \() -> Expect.equal "cat dog cow" (String.join " " [ "cat", "dog", "cow" ]) + , test "join slashes" <| \() -> Expect.equal "home/steve/Desktop" (String.join "/" [ "home", "steve", "Desktop" ]) + , test "slice 1" <| \() -> Expect.equal "c" (String.slice 2 3 "abcd") + , test "slice 2" <| \() -> Expect.equal "abc" (String.slice 0 3 "abcd") + , test "slice 3" <| \() -> Expect.equal "abc" (String.slice 0 -1 "abcd") + , test "slice 4" <| \() -> Expect.equal "cd" (String.slice -2 4 "abcd") + ] + + intTests = + describe "String.toInt" + [ goodInt "1234" 1234 + , goodInt "+1234" 1234 + , goodInt "-1234" -1234 + , badInt "1.34" + , badInt "1e31" + , badInt "123a" + , goodInt "0123" 123 + , goodInt "0x001A" 26 + , goodInt "0x001a" 26 + , goodInt "0xBEEF" 48879 + , badInt "0x12.0" + , badInt "0x12an" + ] + + floatTests = + describe "String.toFloat" + [ goodFloat "123" 123 + , goodFloat "3.14" 3.14 + , goodFloat "+3.14" 3.14 + , goodFloat "-3.14" -3.14 + , goodFloat "0.12" 0.12 + , goodFloat ".12" 0.12 + , goodFloat "1e-42" 1e-42 + , goodFloat "6.022e23" 6.022e23 + , goodFloat "6.022E23" 6.022e23 + , goodFloat "6.022e+23" 6.022e23 + , badFloat "6.022e" + , badFloat "6.022n" + , badFloat "6.022.31" + ] + in + describe "String" [ simpleTests, combiningTests, intTests, floatTests ] + + + +-- NUMBER HELPERS + + +goodInt : String -> Int -> Test +goodInt str int = + test str <| \_ -> + Expect.equal (Ok int) (String.toInt str) + + +badInt : String -> Test +badInt str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to an Int")) + (String.toInt str) + + +goodFloat : String -> Float -> Test +goodFloat str float = + test str <| \_ -> + Expect.equal (Ok float) (String.toFloat str) + + +badFloat : String -> Test +badFloat str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to a Float")) + (String.toFloat str) diff --git a/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json b/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json new file mode 100644 index 0000000..e27cfa4 --- /dev/null +++ b/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "1.1.1", + "summary": "Tests for Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [ ], + "native-modules": true, + "dependencies": { + "elm-community/elm-test": "3.1.0 <= v < 4.0.0", + "rtfeldman/node-test-runner": "3.0.0 <= v < 4.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore b/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore new file mode 100644 index 0000000..e185314 --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore @@ -0,0 +1 @@ +elm-stuff \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE b/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json b/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json new file mode 100644 index 0000000..952aed5 --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "summary": "Fast HTML, rendered with virtual DOM diffing", + "repository": "https://github.com/elm-lang/html.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Html", + "Html.Attributes", + "Html.Events", + "Html.Keyed", + "Html.Lazy" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/virtual-dom": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm new file mode 100644 index 0000000..b872a3b --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm @@ -0,0 +1,923 @@ +module Html exposing + ( Html, Attribute + , text, node, map + , beginnerProgram, program, programWithFlags + , h1, h2, h3, h4, h5, h6 + , div, p, hr, pre, blockquote + , span, a, code, em, strong, i, b, u, sub, sup, br + , ol, ul, li, dl, dt, dd + , img, iframe, canvas, math + , form, input, textarea, button, select, option + , section, nav, article, aside, header, footer, address, main_, body + , figure, figcaption + , table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + , fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + , audio, video, source, track + , embed, object, param + , ins, del + , small, cite, dfn, abbr, time, var, samp, kbd, s, q + , mark, ruby, rt, rp, bdi, bdo, wbr + , details, summary, menuitem, menu + ) + +{-| This file is organized roughly in order of popularity. The tags which you'd +expect to use frequently will be closer to the top. + +# Primitives +@docs Html, Attribute, text, node, map + +# Programs +@docs beginnerProgram, program, programWithFlags + +# Tags + +## Headers +@docs h1, h2, h3, h4, h5, h6 + +## Grouping Content +@docs div, p, hr, pre, blockquote + +## Text +@docs span, a, code, em, strong, i, b, u, sub, sup, br + +## Lists +@docs ol, ul, li, dl, dt, dd + +## Emdedded Content +@docs img, iframe, canvas, math + +## Inputs +@docs form, input, textarea, button, select, option + +## Sections +@docs section, nav, article, aside, header, footer, address, main_, body + +## Figures +@docs figure, figcaption + +## Tables +@docs table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + + +## Less Common Elements + +### Less Common Inputs +@docs fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + +### Audio and Video +@docs audio, video, source, track + +### Embedded Objects +@docs embed, object, param + +### Text Edits +@docs ins, del + +### Semantic Text +@docs small, cite, dfn, abbr, time, var, samp, kbd, s, q + +### Less Common Text Tags +@docs mark, ruby, rt, rp, bdi, bdo, wbr + +## Interactive Elements +@docs details, summary, menuitem, menu + +-} + +import VirtualDom + + + +-- CORE TYPES + + +{-| The core building block used to build up HTML. Here we create an `Html` +value with no attributes and one child: + + hello : Html msg + hello = + div [] [ text "Hello!" ] +-} +type alias Html msg = VirtualDom.Node msg + + +{-| Set attributes on your `Html`. Learn more in the +[`Html.Attributes`](Html-Attributes) module. +-} +type alias Attribute msg = VirtualDom.Property msg + + + +-- PRIMITIVES + + +{-| General way to create HTML nodes. It is used to define all of the helper +functions in this library. + + div : List (Attribute msg) -> List (Html msg) -> Html msg + div attributes children = + node "div" attributes children + +You can use this to create custom nodes if you need to create something that +is not covered by the helper functions in this library. +-} +node : String -> List (Attribute msg) -> List (Html msg) -> Html msg +node = + VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Html msg +text = + VirtualDom.text + + + +-- NESTING VIEWS + + +{-| Transform the messages produced by some `Html`. In the following example, +we have `viewButton` that produces `()` messages, and we transform those values +into `Msg` values in `view`. + + type Msg = Left | Right + + view : model -> Html Msg + view model = + div [] + [ map (\_ -> Left) (viewButton "Left") + , map (\_ -> Right) (viewButton "Right") + ] + + viewButton : String -> Html () + viewButton name = + button [ onClick () ] [ text name ] + +This should not come in handy too often. Definitely read [this][reuse] before +deciding if this is what you want. + +[reuse]: https://guide.elm-lang.org/reuse/ +-} +map : (a -> msg) -> Html a -> Html msg +map = + VirtualDom.map + + + +-- CREATING PROGRAMS + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +The additional context is very worthwhile! (Honestly, it is best to just read +that guide from front to back instead of muddling around and reading it +piecemeal.) + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +beginnerProgram + : { model : model + , view : model -> Html msg + , update : msg -> model -> model + } + -> Program Never model msg +beginnerProgram {model, view, update} = + program + { init = model ! [] + , update = \msg model -> update msg model ! [] + , view = view + , subscriptions = \_ -> Sub.none + } + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +Commands and subscriptions make way more sense when you work up to them +gradually and see them in context with examples. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program Never model msg +program = + VirtualDom.program + + +{-| Create a [`Program`][program] that describes how your whole app works. + +It works just like `program` but you can provide “flags” from +JavaScript to configure your application. Read more about that [here][]. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[here]: https://guide.elm-lang.org/interop/javascript.html +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program flags model msg +programWithFlags = + VirtualDom.programWithFlags + + + +-- SECTIONS + + +{-| Represents the content of an HTML document. There is only one `body` +element in a document. +-} +body : List (Attribute msg) -> List (Html msg) -> Html msg +body = + node "body" + + +{-| Defines a section in a document. +-} +section : List (Attribute msg) -> List (Html msg) -> Html msg +section = + node "section" + + +{-| Defines a section that contains only navigation links. +-} +nav : List (Attribute msg) -> List (Html msg) -> Html msg +nav = + node "nav" + + +{-| Defines self-contained content that could exist independently of the rest +of the content. +-} +article : List (Attribute msg) -> List (Html msg) -> Html msg +article = + node "article" + + +{-| Defines some content loosely related to the page content. If it is removed, +the remaining content still makes sense. +-} +aside : List (Attribute msg) -> List (Html msg) -> Html msg +aside = + node "aside" + + +{-|-} +h1 : List (Attribute msg) -> List (Html msg) -> Html msg +h1 = + node "h1" + + +{-|-} +h2 : List (Attribute msg) -> List (Html msg) -> Html msg +h2 = + node "h2" + + +{-|-} +h3 : List (Attribute msg) -> List (Html msg) -> Html msg +h3 = + node "h3" + + +{-|-} +h4 : List (Attribute msg) -> List (Html msg) -> Html msg +h4 = + node "h4" + + +{-|-} +h5 : List (Attribute msg) -> List (Html msg) -> Html msg +h5 = + node "h5" + + +{-|-} +h6 : List (Attribute msg) -> List (Html msg) -> Html msg +h6 = + node "h6" + + +{-| Defines the header of a page or section. It often contains a logo, the +title of the web site, and a navigational table of content. +-} +header : List (Attribute msg) -> List (Html msg) -> Html msg +header = + node "header" + + +{-| Defines the footer for a page or section. It often contains a copyright +notice, some links to legal information, or addresses to give feedback. +-} +footer : List (Attribute msg) -> List (Html msg) -> Html msg +footer = + node "footer" + + +{-| Defines a section containing contact information. -} +address : List (Attribute msg) -> List (Html msg) -> Html msg +address = + node "address" + + +{-| Defines the main or important content in the document. There is only one +`main` element in the document. +-} +main_ : List (Attribute msg) -> List (Html msg) -> Html msg +main_ = + node "main" + + +-- GROUPING CONTENT + +{-| Defines a portion that should be displayed as a paragraph. -} +p : List (Attribute msg) -> List (Html msg) -> Html msg +p = + node "p" + + +{-| Represents a thematic break between paragraphs of a section or article or +any longer content. +-} +hr : List (Attribute msg) -> List (Html msg) -> Html msg +hr = + node "hr" + + +{-| Indicates that its content is preformatted and that this format must be +preserved. +-} +pre : List (Attribute msg) -> List (Html msg) -> Html msg +pre = + node "pre" + + +{-| Represents a content that is quoted from another source. -} +blockquote : List (Attribute msg) -> List (Html msg) -> Html msg +blockquote = + node "blockquote" + + +{-| Defines an ordered list of items. -} +ol : List (Attribute msg) -> List (Html msg) -> Html msg +ol = + node "ol" + + +{-| Defines an unordered list of items. -} +ul : List (Attribute msg) -> List (Html msg) -> Html msg +ul = + node "ul" + + +{-| Defines a item of an enumeration list. -} +li : List (Attribute msg) -> List (Html msg) -> Html msg +li = + node "li" + + +{-| Defines a definition list, that is, a list of terms and their associated +definitions. +-} +dl : List (Attribute msg) -> List (Html msg) -> Html msg +dl = + node "dl" + + +{-| Represents a term defined by the next `dd`. -} +dt : List (Attribute msg) -> List (Html msg) -> Html msg +dt = + node "dt" + + +{-| Represents the definition of the terms immediately listed before it. -} +dd : List (Attribute msg) -> List (Html msg) -> Html msg +dd = + node "dd" + + +{-| Represents a figure illustrated as part of the document. -} +figure : List (Attribute msg) -> List (Html msg) -> Html msg +figure = + node "figure" + + +{-| Represents the legend of a figure. -} +figcaption : List (Attribute msg) -> List (Html msg) -> Html msg +figcaption = + node "figcaption" + + +{-| Represents a generic container with no special meaning. -} +div : List (Attribute msg) -> List (Html msg) -> Html msg +div = + node "div" + + +-- TEXT LEVEL SEMANTIC + +{-| Represents a hyperlink, linking to another resource. -} +a : List (Attribute msg) -> List (Html msg) -> Html msg +a = + node "a" + + +{-| Represents emphasized text, like a stress accent. -} +em : List (Attribute msg) -> List (Html msg) -> Html msg +em = + node "em" + + +{-| Represents especially important text. -} +strong : List (Attribute msg) -> List (Html msg) -> Html msg +strong = + node "strong" + + +{-| Represents a side comment, that is, text like a disclaimer or a +copyright, which is not essential to the comprehension of the document. +-} +small : List (Attribute msg) -> List (Html msg) -> Html msg +small = + node "small" + + +{-| Represents content that is no longer accurate or relevant. -} +s : List (Attribute msg) -> List (Html msg) -> Html msg +s = + node "s" + + +{-| Represents the title of a work. -} +cite : List (Attribute msg) -> List (Html msg) -> Html msg +cite = + node "cite" + + +{-| Represents an inline quotation. -} +q : List (Attribute msg) -> List (Html msg) -> Html msg +q = + node "q" + + +{-| Represents a term whose definition is contained in its nearest ancestor +content. +-} +dfn : List (Attribute msg) -> List (Html msg) -> Html msg +dfn = + node "dfn" + + +{-| Represents an abbreviation or an acronym; the expansion of the +abbreviation can be represented in the title attribute. +-} +abbr : List (Attribute msg) -> List (Html msg) -> Html msg +abbr = + node "abbr" + + +{-| Represents a date and time value; the machine-readable equivalent can be +represented in the datetime attribute. +-} +time : List (Attribute msg) -> List (Html msg) -> Html msg +time = + node "time" + + +{-| Represents computer code. -} +code : List (Attribute msg) -> List (Html msg) -> Html msg +code = + node "code" + + +{-| Represents a variable. Specific cases where it should be used include an +actual mathematical expression or programming context, an identifier +representing a constant, a symbol identifying a physical quantity, a function +parameter, or a mere placeholder in prose. +-} +var : List (Attribute msg) -> List (Html msg) -> Html msg +var = + node "var" + + +{-| Represents the output of a program or a computer. -} +samp : List (Attribute msg) -> List (Html msg) -> Html msg +samp = + node "samp" + + +{-| Represents user input, often from the keyboard, but not necessarily; it +may represent other input, like transcribed voice commands. +-} +kbd : List (Attribute msg) -> List (Html msg) -> Html msg +kbd = + node "kbd" + + +{-| Represent a subscript. -} +sub : List (Attribute msg) -> List (Html msg) -> Html msg +sub = + node "sub" + + +{-| Represent a superscript. -} +sup : List (Attribute msg) -> List (Html msg) -> Html msg +sup = + node "sup" + + +{-| Represents some text in an alternate voice or mood, or at least of +different quality, such as a taxonomic designation, a technical term, an +idiomatic phrase, a thought, or a ship name. +-} +i : List (Attribute msg) -> List (Html msg) -> Html msg +i = + node "i" + + +{-| Represents a text which to which attention is drawn for utilitarian +purposes. It doesn't convey extra importance and doesn't imply an alternate +voice. +-} +b : List (Attribute msg) -> List (Html msg) -> Html msg +b = + node "b" + + +{-| Represents a non-textual annoatation for which the conventional +presentation is underlining, such labeling the text as being misspelt or +labeling a proper name in Chinese text. +-} +u : List (Attribute msg) -> List (Html msg) -> Html msg +u = + node "u" + + +{-| Represents text highlighted for reference purposes, that is for its +relevance in another context. +-} +mark : List (Attribute msg) -> List (Html msg) -> Html msg +mark = + node "mark" + + +{-| Represents content to be marked with ruby annotations, short runs of text +presented alongside the text. This is often used in conjunction with East Asian +language where the annotations act as a guide for pronunciation, like the +Japanese furigana. +-} +ruby : List (Attribute msg) -> List (Html msg) -> Html msg +ruby = + node "ruby" + + +{-| Represents the text of a ruby annotation. -} +rt : List (Attribute msg) -> List (Html msg) -> Html msg +rt = + node "rt" + + +{-| Represents parenthesis around a ruby annotation, used to display the +annotation in an alternate way by browsers not supporting the standard display +for annotations. +-} +rp : List (Attribute msg) -> List (Html msg) -> Html msg +rp = + node "rp" + + +{-| Represents text that must be isolated from its surrounding for +bidirectional text formatting. It allows embedding a span of text with a +different, or unknown, directionality. +-} +bdi : List (Attribute msg) -> List (Html msg) -> Html msg +bdi = + node "bdi" + + +{-| Represents the directionality of its children, in order to explicitly +override the Unicode bidirectional algorithm. +-} +bdo : List (Attribute msg) -> List (Html msg) -> Html msg +bdo = + node "bdo" + + +{-| Represents text with no specific meaning. This has to be used when no other +text-semantic element conveys an adequate meaning, which, in this case, is +often brought by global attributes like `class`, `lang`, or `dir`. +-} +span : List (Attribute msg) -> List (Html msg) -> Html msg +span = + node "span" + + +{-| Represents a line break. -} +br : List (Attribute msg) -> List (Html msg) -> Html msg +br = + node "br" + + +{-| Represents a line break opportunity, that is a suggested point for +wrapping text in order to improve readability of text split on several lines. +-} +wbr : List (Attribute msg) -> List (Html msg) -> Html msg +wbr = + node "wbr" + + +-- EDITS + +{-| Defines an addition to the document. -} +ins : List (Attribute msg) -> List (Html msg) -> Html msg +ins = + node "ins" + + +{-| Defines a removal from the document. -} +del : List (Attribute msg) -> List (Html msg) -> Html msg +del = + node "del" + + +-- EMBEDDED CONTENT + +{-| Represents an image. -} +img : List (Attribute msg) -> List (Html msg) -> Html msg +img = + node "img" + + +{-| Embedded an HTML document. -} +iframe : List (Attribute msg) -> List (Html msg) -> Html msg +iframe = + node "iframe" + + +{-| Represents a integration point for an external, often non-HTML, +application or interactive content. +-} +embed : List (Attribute msg) -> List (Html msg) -> Html msg +embed = + node "embed" + + +{-| Represents an external resource, which is treated as an image, an HTML +sub-document, or an external resource to be processed by a plug-in. +-} +object : List (Attribute msg) -> List (Html msg) -> Html msg +object = + node "object" + + +{-| Defines parameters for use by plug-ins invoked by `object` elements. -} +param : List (Attribute msg) -> List (Html msg) -> Html msg +param = + node "param" + + +{-| Represents a video, the associated audio and captions, and controls. -} +video : List (Attribute msg) -> List (Html msg) -> Html msg +video = + node "video" + + +{-| Represents a sound or audio stream. -} +audio : List (Attribute msg) -> List (Html msg) -> Html msg +audio = + node "audio" + + +{-| Allows authors to specify alternative media resources for media elements +like `video` or `audio`. +-} +source : List (Attribute msg) -> List (Html msg) -> Html msg +source = + node "source" + + +{-| Allows authors to specify timed text track for media elements like `video` +or `audio`. +-} +track : List (Attribute msg) -> List (Html msg) -> Html msg +track = + node "track" + + +{-| Represents a bitmap area for graphics rendering. -} +canvas : List (Attribute msg) -> List (Html msg) -> Html msg +canvas = + node "canvas" + + +{-| Defines a mathematical formula. -} +math : List (Attribute msg) -> List (Html msg) -> Html msg +math = + node "math" + + +-- TABULAR DATA + +{-| Represents data with more than one dimension. -} +table : List (Attribute msg) -> List (Html msg) -> Html msg +table = + node "table" + + +{-| Represents the title of a table. -} +caption : List (Attribute msg) -> List (Html msg) -> Html msg +caption = + node "caption" + + +{-| Represents a set of one or more columns of a table. -} +colgroup : List (Attribute msg) -> List (Html msg) -> Html msg +colgroup = + node "colgroup" + + +{-| Represents a column of a table. -} +col : List (Attribute msg) -> List (Html msg) -> Html msg +col = + node "col" + + +{-| Represents the block of rows that describes the concrete data of a table. +-} +tbody : List (Attribute msg) -> List (Html msg) -> Html msg +tbody = + node "tbody" + + +{-| Represents the block of rows that describes the column labels of a table. +-} +thead : List (Attribute msg) -> List (Html msg) -> Html msg +thead = + node "thead" + + +{-| Represents the block of rows that describes the column summaries of a table. +-} +tfoot : List (Attribute msg) -> List (Html msg) -> Html msg +tfoot = + node "tfoot" + + +{-| Represents a row of cells in a table. -} +tr : List (Attribute msg) -> List (Html msg) -> Html msg +tr = + node "tr" + + +{-| Represents a data cell in a table. -} +td : List (Attribute msg) -> List (Html msg) -> Html msg +td = + node "td" + + +{-| Represents a header cell in a table. -} +th : List (Attribute msg) -> List (Html msg) -> Html msg +th = + node "th" + + +-- FORMS + +{-| Represents a form, consisting of controls, that can be submitted to a +server for processing. +-} +form : List (Attribute msg) -> List (Html msg) -> Html msg +form = + node "form" + + +{-| Represents a set of controls. -} +fieldset : List (Attribute msg) -> List (Html msg) -> Html msg +fieldset = + node "fieldset" + + +{-| Represents the caption for a `fieldset`. -} +legend : List (Attribute msg) -> List (Html msg) -> Html msg +legend = + node "legend" + + +{-| Represents the caption of a form control. -} +label : List (Attribute msg) -> List (Html msg) -> Html msg +label = + node "label" + + +{-| Represents a typed data field allowing the user to edit the data. -} +input : List (Attribute msg) -> List (Html msg) -> Html msg +input = + node "input" + + +{-| Represents a button. -} +button : List (Attribute msg) -> List (Html msg) -> Html msg +button = + node "button" + + +{-| Represents a control allowing selection among a set of options. -} +select : List (Attribute msg) -> List (Html msg) -> Html msg +select = + node "select" + + +{-| Represents a set of predefined options for other controls. -} +datalist : List (Attribute msg) -> List (Html msg) -> Html msg +datalist = + node "datalist" + + +{-| Represents a set of options, logically grouped. -} +optgroup : List (Attribute msg) -> List (Html msg) -> Html msg +optgroup = + node "optgroup" + + +{-| Represents an option in a `select` element or a suggestion of a `datalist` +element. +-} +option : List (Attribute msg) -> List (Html msg) -> Html msg +option = + node "option" + + +{-| Represents a multiline text edit control. -} +textarea : List (Attribute msg) -> List (Html msg) -> Html msg +textarea = + node "textarea" + + +{-| Represents a key-pair generator control. -} +keygen : List (Attribute msg) -> List (Html msg) -> Html msg +keygen = + node "keygen" + + +{-| Represents the result of a calculation. -} +output : List (Attribute msg) -> List (Html msg) -> Html msg +output = + node "output" + + +{-| Represents the completion progress of a task. -} +progress : List (Attribute msg) -> List (Html msg) -> Html msg +progress = + node "progress" + + +{-| Represents a scalar measurement (or a fractional value), within a known +range. +-} +meter : List (Attribute msg) -> List (Html msg) -> Html msg +meter = + node "meter" + + +-- INTERACTIVE ELEMENTS + +{-| Represents a widget from which the user can obtain additional information +or controls. +-} +details : List (Attribute msg) -> List (Html msg) -> Html msg +details = + node "details" + + +{-| Represents a summary, caption, or legend for a given `details`. -} +summary : List (Attribute msg) -> List (Html msg) -> Html msg +summary = + node "summary" + + +{-| Represents a command that the user can invoke. -} +menuitem : List (Attribute msg) -> List (Html msg) -> Html msg +menuitem = + node "menuitem" + + +{-| Represents a list of commands. -} +menu : List (Attribute msg) -> List (Html msg) -> Html msg +menu = + node "menu" + diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm new file mode 100644 index 0000000..4cdba44 --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm @@ -0,0 +1,1009 @@ +module Html.Attributes exposing + ( style, property, attribute, map + , class, classList, id, title, hidden + , type_, value, defaultValue, checked, placeholder, selected + , accept, acceptCharset, action, autocomplete, autofocus + , disabled, enctype, formaction, list, maxlength, minlength, method, multiple + , name, novalidate, pattern, readonly, required, size, for, form + , max, min, step + , cols, rows, wrap + , href, target, download, downloadAs, hreflang, media, ping, rel + , ismap, usemap, shape, coords + , src, height, width, alt + , autoplay, controls, loop, preload, poster, default, kind, srclang + , sandbox, seamless, srcdoc + , reversed, start + , align, colspan, rowspan, headers, scope + , async, charset, content, defer, httpEquiv, language, scoped + , accesskey, contenteditable, contextmenu, dir, draggable, dropzone + , itemprop, lang, spellcheck, tabindex + , challenge, keytype + , cite, datetime, pubdate, manifest + ) + +{-| Helper functions for HTML attributes. They are organized roughly by +category. Each attribute is labeled with the HTML tags it can be used with, so +just search the page for `video` if you want video stuff. + +If you cannot find what you are looking for, go to the [Custom +Attributes](#custom-attributes) section to learn how to create new helpers. + +# Primitives +@docs style, property, attribute, map + +# Super Common Attributes +@docs class, classList, id, title, hidden + +# Inputs +@docs type_, value, defaultValue, checked, placeholder, selected + +## Input Helpers +@docs accept, acceptCharset, action, autocomplete, autofocus, + disabled, enctype, formaction, list, maxlength, minlength, method, multiple, + name, novalidate, pattern, readonly, required, size, for, form + +## Input Ranges +@docs max, min, step + +## Input Text Areas +@docs cols, rows, wrap + + +# Links and Areas +@docs href, target, download, downloadAs, hreflang, media, ping, rel + +## Maps +@docs ismap, usemap, shape, coords + + +# Embedded Content +@docs src, height, width, alt + +## Audio and Video +@docs autoplay, controls, loop, preload, poster, default, kind, srclang + +## iframes +@docs sandbox, seamless, srcdoc + +# Ordered Lists +@docs reversed, start + +# Tables +@docs align, colspan, rowspan, headers, scope + +# Header Stuff +@docs async, charset, content, defer, httpEquiv, language, scoped + +# Less Common Global Attributes +Attributes that can be attached to any HTML tag but are less commonly used. +@docs accesskey, contenteditable, contextmenu, dir, draggable, dropzone, + itemprop, lang, spellcheck, tabindex + +# Key Generation +@docs challenge, keytype + +# Miscellaneous +@docs cite, datetime, pubdate, manifest + +-} + +import Html exposing (Attribute) +import Json.Encode as Json +import VirtualDom + + +-- This library does not include low, high, or optimum because the idea of a +-- `meter` is just too crazy. + + + +-- PRIMITIVES + + +{-| Specify a list of styles. + + myStyle : Attribute msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Html msg + greeting = + div [ myStyle ] [ text "Hello!" ] + +There is no `Html.Styles` module because best practices for working with HTML +suggest that this should primarily be specified in CSS files. So the general +recommendation is to use this function lightly. +-} +style : List (String, String) -> Attribute msg +style = + VirtualDom.style + + +{-| This function makes it easier to build a space-separated class attribute. +Each class can easily be added and removed depending on the boolean value it +is paired with. For example, maybe we want a way to view notices: + + viewNotice : Notice -> Html msg + viewNotice notice = + div + [ classList + [ ("notice", True) + , ("notice-important", notice.isImportant) + , ("notice-seen", notice.isSeen) + ] + ] + [ text notice.content ] +-} +classList : List (String, Bool) -> Attribute msg +classList list = + list + |> List.filter Tuple.second + |> List.map Tuple.first + |> String.join " " + |> class + + + +-- CUSTOM ATTRIBUTES + + +{-| Create *properties*, like saying `domNode.className = 'greeting'` in +JavaScript. + + import Json.Encode as Encode + + class : String -> Attribute msg + class name = + property "className" (Encode.string name) + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +property : String -> Json.Value -> Attribute msg +property = + VirtualDom.property + + +stringProperty : String -> String -> Attribute msg +stringProperty name string = + property name (Json.string string) + + +boolProperty : String -> Bool -> Attribute msg +boolProperty name bool = + property name (Json.bool bool) + + +{-| Create *attributes*, like saying `domNode.setAttribute('class', 'greeting')` +in JavaScript. + + class : String -> Attribute msg + class name = + attribute "class" name + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +attribute : String -> String -> Attribute msg +attribute = + VirtualDom.attribute + + +{-| Transform the messages produced by an `Attribute`. +-} +map : (a -> msg) -> Attribute a -> Attribute msg +map = + VirtualDom.mapProperty + + + +-- GLOBAL ATTRIBUTES + + +{-| Often used with CSS to style elements with common properties. -} +class : String -> Attribute msg +class name = + stringProperty "className" name + + +{-| Indicates the relevance of an element. -} +hidden : Bool -> Attribute msg +hidden bool = + boolProperty "hidden" bool + + +{-| Often used with CSS to style a specific element. The value of this +attribute must be unique. +-} +id : String -> Attribute msg +id name = + stringProperty "id" name + + +{-| Text to be displayed in a tooltip when hovering over the element. -} +title : String -> Attribute msg +title name = + stringProperty "title" name + + + +-- LESS COMMON GLOBAL ATTRIBUTES + + +{-| Defines a keyboard shortcut to activate or add focus to the element. -} +accesskey : Char -> Attribute msg +accesskey char = + stringProperty "accessKey" (String.fromChar char) + + +{-| Indicates whether the element's content is editable. -} +contenteditable : Bool -> Attribute msg +contenteditable bool = + boolProperty "contentEditable" bool + + +{-| Defines the ID of a `menu` element which will serve as the element's +context menu. +-} +contextmenu : String -> Attribute msg +contextmenu value = + attribute "contextmenu" value + + +{-| Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl +(Right-To-Left). +-} +dir : String -> Attribute msg +dir value = + stringProperty "dir" value + + +{-| Defines whether the element can be dragged. -} +draggable : String -> Attribute msg +draggable value = + attribute "draggable" value + + +{-| Indicates that the element accept the dropping of content on it. -} +dropzone : String -> Attribute msg +dropzone value = + stringProperty "dropzone" value + + +{-|-} +itemprop : String -> Attribute msg +itemprop value = + attribute "itemprop" value + + +{-| Defines the language used in the element. -} +lang : String -> Attribute msg +lang value = + stringProperty "lang" value + + +{-| Indicates whether spell checking is allowed for the element. -} +spellcheck : Bool -> Attribute msg +spellcheck bool = + boolProperty "spellcheck" bool + + +{-| Overrides the browser's default tab order and follows the one specified +instead. +-} +tabindex : Int -> Attribute msg +tabindex n = + attribute "tabIndex" (toString n) + + + +-- HEADER STUFF + + +{-| Indicates that the `script` should be executed asynchronously. -} +async : Bool -> Attribute msg +async bool = + boolProperty "async" bool + + +{-| Declares the character encoding of the page or script. Common values include: + + * UTF-8 - Character encoding for Unicode + * ISO-8859-1 - Character encoding for the Latin alphabet + +For `meta` and `script`. +-} +charset : String -> Attribute msg +charset value = + attribute "charset" value + + +{-| A value associated with http-equiv or name depending on the context. For +`meta`. +-} +content : String -> Attribute msg +content value = + stringProperty "content" value + + +{-| Indicates that a `script` should be executed after the page has been +parsed. +-} +defer : Bool -> Attribute msg +defer bool = + boolProperty "defer" bool + + +{-| This attribute is an indicator that is paired with the `content` attribute, +indicating what that content means. `httpEquiv` can take on three different +values: content-type, default-style, or refresh. For `meta`. +-} +httpEquiv : String -> Attribute msg +httpEquiv value = + stringProperty "httpEquiv" value + + +{-| Defines the script language used in a `script`. -} +language : String -> Attribute msg +language value = + stringProperty "language" value + + +{-| Indicates that a `style` should only apply to its parent and all of the +parents children. +-} +scoped : Bool -> Attribute msg +scoped bool = + boolProperty "scoped" bool + + + +-- EMBEDDED CONTENT + + +{-| The URL of the embeddable content. For `audio`, `embed`, `iframe`, `img`, +`input`, `script`, `source`, `track`, and `video`. +-} +src : String -> Attribute msg +src value = + stringProperty "src" value + + +{-| Declare the height of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +height : Int -> Attribute msg +height value = + attribute "height" (toString value) + + +{-| Declare the width of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +width : Int -> Attribute msg +width value = + attribute "width" (toString value) + + +{-| Alternative text in case an image can't be displayed. Works with `img`, +`area`, and `input`. +-} +alt : String -> Attribute msg +alt value = + stringProperty "alt" value + + + +-- AUDIO and VIDEO + + +{-| The `audio` or `video` should play as soon as possible. -} +autoplay : Bool -> Attribute msg +autoplay bool = + boolProperty "autoplay" bool + + +{-| Indicates whether the browser should show playback controls for the `audio` +or `video`. +-} +controls : Bool -> Attribute msg +controls bool = + boolProperty "controls" bool + + +{-| Indicates whether the `audio` or `video` should start playing from the +start when it's finished. +-} +loop : Bool -> Attribute msg +loop bool = + boolProperty "loop" bool + + +{-| Control how much of an `audio` or `video` resource should be preloaded. -} +preload : String -> Attribute msg +preload value = + stringProperty "preload" value + + +{-| A URL indicating a poster frame to show until the user plays or seeks the +`video`. +-} +poster : String -> Attribute msg +poster value = + stringProperty "poster" value + + +{-| Indicates that the `track` should be enabled unless the user's preferences +indicate something different. +-} +default : Bool -> Attribute msg +default bool = + boolProperty "default" bool + + +{-| Specifies the kind of text `track`. -} +kind : String -> Attribute msg +kind value = + stringProperty "kind" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| Specifies a user-readable title of the text `track`. -} +label : String -> Attribute msg +label value = + stringProperty "label" value +--} + +{-| A two letter language code indicating the language of the `track` text data. +-} +srclang : String -> Attribute msg +srclang value = + stringProperty "srclang" value + + + +-- IFRAMES + + +{-| A space separated list of security restrictions you'd like to lift for an +`iframe`. +-} +sandbox : String -> Attribute msg +sandbox value = + stringProperty "sandbox" value + + +{-| Make an `iframe` look like part of the containing document. -} +seamless : Bool -> Attribute msg +seamless bool = + boolProperty "seamless" bool + + +{-| An HTML document that will be displayed as the body of an `iframe`. It will +override the content of the `src` attribute if it has been specified. +-} +srcdoc : String -> Attribute msg +srcdoc value = + stringProperty "srcdoc" value + + + +-- INPUT + + +{-| Defines the type of a `button`, `input`, `embed`, `object`, `script`, +`source`, `style`, or `menu`. +-} +type_ : String -> Attribute msg +type_ value = + stringProperty "type" value + + +{-| Defines a default value which will be displayed in a `button`, `option`, +`input`, `li`, `meter`, `progress`, or `param`. +-} +value : String -> Attribute msg +value value = + stringProperty "value" value + + +{-| Defines an initial value which will be displayed in an `input` when that +`input` is added to the DOM. Unlike `value`, altering `defaultValue` after the +`input` element has been added to the DOM has no effect. +-} +defaultValue : String -> Attribute msg +defaultValue value = + stringProperty "defaultValue" value + + +{-| Indicates whether an `input` of type checkbox is checked. -} +checked : Bool -> Attribute msg +checked bool = + boolProperty "checked" bool + + +{-| Provides a hint to the user of what can be entered into an `input` or +`textarea`. +-} +placeholder : String -> Attribute msg +placeholder value = + stringProperty "placeholder" value + + +{-| Defines which `option` will be selected on page load. -} +selected : Bool -> Attribute msg +selected bool = + boolProperty "selected" bool + + + +-- INPUT HELPERS + + +{-| List of types the server accepts, typically a file type. +For `form` and `input`. +-} +accept : String -> Attribute msg +accept value = + stringProperty "accept" value + + +{-| List of supported charsets in a `form`. +-} +acceptCharset : String -> Attribute msg +acceptCharset value = + stringProperty "acceptCharset" value + + +{-| The URI of a program that processes the information submitted via a `form`. +-} +action : String -> Attribute msg +action value = + stringProperty "action" value + + +{-| Indicates whether a `form` or an `input` can have their values automatically +completed by the browser. +-} +autocomplete : Bool -> Attribute msg +autocomplete bool = + stringProperty "autocomplete" (if bool then "on" else "off") + + +{-| The element should be automatically focused after the page loaded. +For `button`, `input`, `keygen`, `select`, and `textarea`. +-} +autofocus : Bool -> Attribute msg +autofocus bool = + boolProperty "autofocus" bool + + +{-| Indicates whether the user can interact with a `button`, `fieldset`, +`input`, `keygen`, `optgroup`, `option`, `select` or `textarea`. +-} +disabled : Bool -> Attribute msg +disabled bool = + boolProperty "disabled" bool + + +{-| How `form` data should be encoded when submitted with the POST method. +Options include: application/x-www-form-urlencoded, multipart/form-data, and +text/plain. +-} +enctype : String -> Attribute msg +enctype value = + stringProperty "enctype" value + + +{-| Indicates the action of an `input` or `button`. This overrides the action +defined in the surrounding `form`. +-} +formaction : String -> Attribute msg +formaction value = + attribute "formAction" value + + +{-| Associates an `input` with a `datalist` tag. The datalist gives some +pre-defined options to suggest to the user as they interact with an input. +The value of the list attribute must match the id of a `datalist` node. +For `input`. +-} +list : String -> Attribute msg +list value = + attribute "list" value + + +{-| Defines the minimum number of characters allowed in an `input` or +`textarea`. +-} +minlength : Int -> Attribute msg +minlength n = + attribute "minLength" (toString n) + + +{-| Defines the maximum number of characters allowed in an `input` or +`textarea`. +-} +maxlength : Int -> Attribute msg +maxlength n = + attribute "maxlength" (toString n) + + +{-| Defines which HTTP method to use when submitting a `form`. Can be GET +(default) or POST. +-} +method : String -> Attribute msg +method value = + stringProperty "method" value + + +{-| Indicates whether multiple values can be entered in an `input` of type +email or file. Can also indicate that you can `select` many options. +-} +multiple : Bool -> Attribute msg +multiple bool = + boolProperty "multiple" bool + + +{-| Name of the element. For example used by the server to identify the fields +in form submits. For `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, +`object`, `output`, `select`, `textarea`, `map`, `meta`, and `param`. +-} +name : String -> Attribute msg +name value = + stringProperty "name" value + + +{-| This attribute indicates that a `form` shouldn't be validated when +submitted. +-} +novalidate : Bool -> Attribute msg +novalidate bool = + boolProperty "noValidate" bool + + +{-| Defines a regular expression which an `input`'s value will be validated +against. +-} +pattern : String -> Attribute msg +pattern value = + stringProperty "pattern" value + + +{-| Indicates whether an `input` or `textarea` can be edited. -} +readonly : Bool -> Attribute msg +readonly bool = + boolProperty "readOnly" bool + + +{-| Indicates whether this element is required to fill out or not. +For `input`, `select`, and `textarea`. +-} +required : Bool -> Attribute msg +required bool = + boolProperty "required" bool + + +{-| For `input` specifies the width of an input in characters. + +For `select` specifies the number of visible options in a drop-down list. +-} +size : Int -> Attribute msg +size n = + attribute "size" (toString n) + + +{-| The element ID described by this `label` or the element IDs that are used +for an `output`. +-} +for : String -> Attribute msg +for value = + stringProperty "htmlFor" value + + +{-| Indicates the element ID of the `form` that owns this particular `button`, +`fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, +`progress`, `select`, or `textarea`. +-} +form : String -> Attribute msg +form value = + attribute "form" value + + + +-- RANGES + + +{-| Indicates the maximum value allowed. When using an input of type number or +date, the max value must be a number or date. For `input`, `meter`, and `progress`. +-} +max : String -> Attribute msg +max value = + stringProperty "max" value + + +{-| Indicates the minimum value allowed. When using an input of type number or +date, the min value must be a number or date. For `input` and `meter`. +-} +min : String -> Attribute msg +min value = + stringProperty "min" value + + +{-| Add a step size to an `input`. Use `step "any"` to allow any floating-point +number to be used in the input. +-} +step : String -> Attribute msg +step n = + stringProperty "step" n + + +-------------------------- + + +{-| Defines the number of columns in a `textarea`. -} +cols : Int -> Attribute msg +cols n = + attribute "cols" (toString n) + + +{-| Defines the number of rows in a `textarea`. -} +rows : Int -> Attribute msg +rows n = + attribute "rows" (toString n) + + +{-| Indicates whether the text should be wrapped in a `textarea`. Possible +values are "hard" and "soft". +-} +wrap : String -> Attribute msg +wrap value = + stringProperty "wrap" value + + + +-- MAPS + + +{-| When an `img` is a descendent of an `a` tag, the `ismap` attribute +indicates that the click location should be added to the parent `a`'s href as +a query string. +-} +ismap : Bool -> Attribute msg +ismap value = + boolProperty "isMap" value + + +{-| Specify the hash name reference of a `map` that should be used for an `img` +or `object`. A hash name reference is a hash symbol followed by the element's name or id. +E.g. `"#planet-map"`. +-} +usemap : String -> Attribute msg +usemap value = + stringProperty "useMap" value + + +{-| Declare the shape of the clickable area in an `a` or `area`. Valid values +include: default, rect, circle, poly. This attribute can be paired with +`coords` to create more particular shapes. +-} +shape : String -> Attribute msg +shape value = + stringProperty "shape" value + + +{-| A set of values specifying the coordinates of the hot-spot region in an +`area`. Needs to be paired with a `shape` attribute to be meaningful. +-} +coords : String -> Attribute msg +coords value = + stringProperty "coords" value + + + +-- KEY GEN + + +{-| A challenge string that is submitted along with the public key in a `keygen`. +-} +challenge : String -> Attribute msg +challenge value = + attribute "challenge" value + + +{-| Specifies the type of key generated by a `keygen`. Possible values are: +rsa, dsa, and ec. +-} +keytype : String -> Attribute msg +keytype value = + stringProperty "keytype" value + + + +-- REAL STUFF + + +{-| Specifies the horizontal alignment of a `caption`, `col`, `colgroup`, +`hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, or +`tr`. +-} +align : String -> Attribute msg +align value = + stringProperty "align" value + + +{-| Contains a URI which points to the source of the quote or change in a +`blockquote`, `del`, `ins`, or `q`. +-} +cite : String -> Attribute msg +cite value = + stringProperty "cite" value + + + + +-- LINKS AND AREAS + + +{-| The URL of a linked resource, such as `a`, `area`, `base`, or `link`. -} +href : String -> Attribute msg +href value = + stringProperty "href" value + + +{-| Specify where the results of clicking an `a`, `area`, `base`, or `form` +should appear. Possible special values include: + + * _blank — a new window or tab + * _self — the same frame (this is default) + * _parent — the parent frame + * _top — the full body of the window + +You can also give the name of any `frame` you have created. +-} +target : String -> Attribute msg +target value = + stringProperty "target" value + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly. +-} +download : Bool -> Attribute msg +download bool = + boolProperty "download" bool + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly, and that the downloaded resource with have the given filename. +-} +downloadAs : String -> Attribute msg +downloadAs value = + stringProperty "download" value + + +{-| Two-letter language code of the linked resource of an `a`, `area`, or `link`. +-} +hreflang : String -> Attribute msg +hreflang value = + stringProperty "hreflang" value + + +{-| Specifies a hint of the target media of a `a`, `area`, `link`, `source`, +or `style`. +-} +media : String -> Attribute msg +media value = + attribute "media" value + + +{-| Specify a URL to send a short POST request to when the user clicks on an +`a` or `area`. Useful for monitoring and tracking. +-} +ping : String -> Attribute msg +ping value = + stringProperty "ping" value + + +{-| Specifies the relationship of the target object to the link object. +For `a`, `area`, `link`. +-} +rel : String -> Attribute msg +rel value = + attribute "rel" value + + + +-- CRAZY STUFF + + +{-| Indicates the date and time associated with the element. +For `del`, `ins`, `time`. +-} +datetime : String -> Attribute msg +datetime value = + attribute "datetime" value + + +{-| Indicates whether this date and time is the date of the nearest `article` +ancestor element. For `time`. +-} +pubdate : String -> Attribute msg +pubdate value = + attribute "pubdate" value + + + +-- ORDERED LISTS + + +{-| Indicates whether an ordered list `ol` should be displayed in a descending +order instead of a ascending. +-} +reversed : Bool -> Attribute msg +reversed bool = + boolProperty "reversed" bool + + +{-| Defines the first number of an ordered list if you want it to be something +besides 1. +-} +start : Int -> Attribute msg +start n = + stringProperty "start" (toString n) + + + +-- TABLES + + +{-| The colspan attribute defines the number of columns a cell should span. +For `td` and `th`. +-} +colspan : Int -> Attribute msg +colspan n = + attribute "colspan" (toString n) + + +{-| A space separated list of element IDs indicating which `th` elements are +headers for this cell. For `td` and `th`. +-} +headers : String -> Attribute msg +headers value = + stringProperty "headers" value + + +{-| Defines the number of rows a table cell should span over. +For `td` and `th`. +-} +rowspan : Int -> Attribute msg +rowspan n = + attribute "rowspan" (toString n) + + +{-| Specifies the scope of a header cell `th`. Possible values are: col, row, +colgroup, rowgroup. +-} +scope : String -> Attribute msg +scope value = + stringProperty "scope" value + + +{-| Specifies the URL of the cache manifest for an `html` tag. -} +manifest : String -> Attribute msg +manifest value = + attribute "manifest" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| The number of columns a `col` or `colgroup` should span. -} +span : Int -> Attribute msg +span n = + stringProperty "span" (toString n) +--} diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm new file mode 100644 index 0000000..ff5c1fe --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm @@ -0,0 +1,269 @@ +module Html.Events exposing + ( onClick, onDoubleClick + , onMouseDown, onMouseUp + , onMouseEnter, onMouseLeave + , onMouseOver, onMouseOut + , onInput, onCheck, onSubmit + , onBlur, onFocus + , on, onWithOptions, Options, defaultOptions + , targetValue, targetChecked, keyCode + ) + +{-| +It is often helpful to create an [Union Type][] so you can have many different kinds +of events as seen in the [TodoMVC][] example. + +[Union Type]: http://elm-lang.org/learn/Union-Types.elm +[TodoMVC]: https://github.com/evancz/elm-todomvc/blob/master/Todo.elm + +# Mouse Helpers +@docs onClick, onDoubleClick, + onMouseDown, onMouseUp, + onMouseEnter, onMouseLeave, + onMouseOver, onMouseOut + +# Form Helpers +@docs onInput, onCheck, onSubmit + +# Focus Helpers +@docs onBlur, onFocus + +# Custom Event Handlers +@docs on, onWithOptions, Options, defaultOptions + +# Custom Decoders +@docs targetValue, targetChecked, keyCode +-} + +import Html exposing (Attribute) +import Json.Decode as Json +import VirtualDom + + + +-- MOUSE EVENTS + + +{-|-} +onClick : msg -> Attribute msg +onClick msg = + on "click" (Json.succeed msg) + + +{-|-} +onDoubleClick : msg -> Attribute msg +onDoubleClick msg = + on "dblclick" (Json.succeed msg) + + +{-|-} +onMouseDown : msg -> Attribute msg +onMouseDown msg = + on "mousedown" (Json.succeed msg) + + +{-|-} +onMouseUp : msg -> Attribute msg +onMouseUp msg = + on "mouseup" (Json.succeed msg) + + +{-|-} +onMouseEnter : msg -> Attribute msg +onMouseEnter msg = + on "mouseenter" (Json.succeed msg) + + +{-|-} +onMouseLeave : msg -> Attribute msg +onMouseLeave msg = + on "mouseleave" (Json.succeed msg) + + +{-|-} +onMouseOver : msg -> Attribute msg +onMouseOver msg = + on "mouseover" (Json.succeed msg) + + +{-|-} +onMouseOut : msg -> Attribute msg +onMouseOut msg = + on "mouseout" (Json.succeed msg) + + + +-- FORM EVENTS + + +{-| Capture [input](https://developer.mozilla.org/en-US/docs/Web/Events/input) +events for things like text fields or text areas. + +It grabs the **string** value at `event.target.value`, so it will not work if +you need some other type of information. For example, if you want to track +inputs on a range slider, make a custom handler with [`on`](#on). + +For more details on how `onInput` works, check out [targetValue](#targetValue). +-} +onInput : (String -> msg) -> Attribute msg +onInput tagger = + on "input" (Json.map tagger targetValue) + + +{-| Capture [change](https://developer.mozilla.org/en-US/docs/Web/Events/change) +events on checkboxes. It will grab the boolean value from `event.target.checked` +on any input event. + +Check out [targetChecked](#targetChecked) for more details on how this works. +-} +onCheck : (Bool -> msg) -> Attribute msg +onCheck tagger = + on "change" (Json.map tagger targetChecked) + + +{-| Capture a [submit](https://developer.mozilla.org/en-US/docs/Web/Events/submit) +event with [`preventDefault`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) +in order to prevent the form from changing the page’s location. If you need +different behavior, use `onWithOptions` to create a customized version of +`onSubmit`. +-} +onSubmit : msg -> Attribute msg +onSubmit msg = + onWithOptions "submit" onSubmitOptions (Json.succeed msg) + + +onSubmitOptions : Options +onSubmitOptions = + { defaultOptions | preventDefault = True } + + +-- FOCUS EVENTS + + +{-|-} +onBlur : msg -> Attribute msg +onBlur msg = + on "blur" (Json.succeed msg) + + +{-|-} +onFocus : msg -> Attribute msg +onFocus msg = + on "focus" (Json.succeed msg) + + + +-- CUSTOM EVENTS + + +{-| Create a custom event listener. Normally this will not be necessary, but +you have the power! Here is how `onClick` is defined for example: + + import Json.Decode as Json + + onClick : msg -> Attribute msg + onClick message = + on "click" (Json.succeed message) + +The first argument is the event name in the same format as with JavaScript's +[`addEventListener`][aEL] function. + +The second argument is a JSON decoder. Read more about these [here][decoder]. +When an event occurs, the decoder tries to turn the event object into an Elm +value. If successful, the value is routed to your `update` function. In the +case of `onClick` we always just succeed with the given `message`. + +If this is confusing, work through the [Elm Architecture Tutorial][tutorial]. +It really does help! + +[aEL]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener +[decoder]: http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode +[tutorial]: https://github.com/evancz/elm-architecture-tutorial/ +-} +on : String -> Json.Decoder msg -> Attribute msg +on = + VirtualDom.on + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Attribute msg +onWithOptions = + VirtualDom.onWithOptions + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + VirtualDom.defaultOptions + + + +-- COMMON DECODERS + + +{-| A `Json.Decoder` for grabbing `event.target.value`. We use this to define +`onInput` as follows: + + import Json.Decode as Json + + onInput : (String -> msg) -> Attribute msg + onInput tagger = + on "input" (Json.map tagger targetValue) + +You probably will never need this, but hopefully it gives some insights into +how to make custom event handlers. +-} +targetValue : Json.Decoder String +targetValue = + Json.at ["target", "value"] Json.string + + +{-| A `Json.Decoder` for grabbing `event.target.checked`. We use this to define +`onCheck` as follows: + + import Json.Decode as Json + + onCheck : (Bool -> msg) -> Attribute msg + onCheck tagger = + on "input" (Json.map tagger targetChecked) +-} +targetChecked : Json.Decoder Bool +targetChecked = + Json.at ["target", "checked"] Json.bool + + +{-| A `Json.Decoder` for grabbing `event.keyCode`. This helps you define +keyboard listeners like this: + + import Json.Decode as Json + + onKeyUp : (Int -> msg) -> Attribute msg + onKeyUp tagger = + on "keyup" (Json.map tagger keyCode) + +**Note:** It looks like the spec is moving away from `event.keyCode` and +towards `event.key`. Once this is supported in more browsers, we may add +helpers here for `onKeyUp`, `onKeyDown`, `onKeyPress`, etc. +-} +keyCode : Json.Decoder Int +keyCode = + Json.field "keyCode" Json.int diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm new file mode 100644 index 0000000..debd710 --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm @@ -0,0 +1,48 @@ +module Html.Keyed exposing + ( node + , ol + , ul + ) +{-| A keyed node helps optimize cases where children are getting added, moved, +removed, etc. Common examples include: + + - The user can delete items from a list. + - The user can create new items in a list. + - You can sort a list based on name or date or whatever. + +When you use a keyed node, every child is paired with a string identifier. This +makes it possible for the underlying diffing algorithm to reuse nodes more +efficiently. + +# Keyed Nodes +@docs node + +# Commonly Keyed Nodes +@docs ol, ul +-} + + +import Html exposing (Attribute, Html) +import VirtualDom + + +{-| Works just like `Html.node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +node : String -> List (Attribute msg) -> List ( String, Html msg ) -> Html msg +node = + VirtualDom.keyedNode + + +{-|-} +ol : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ol = + node "ol" + + +{-|-} +ul : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ul = + node "ul" diff --git a/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm new file mode 100644 index 0000000..f027ffc --- /dev/null +++ b/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm @@ -0,0 +1,48 @@ +module Html.Lazy exposing + ( lazy, lazy2, lazy3 + ) + +{-| Since all Elm functions are pure we have a guarantee that the same input +will always result in the same output. This module gives us tools to be lazy +about building `Html` that utilize this fact. + +Rather than immediately applying functions to their arguments, the `lazy` +functions just bundle the function and arguments up for later. When diffing +the old and new virtual DOM, it checks to see if all the arguments are equal. +If so, it skips calling the function! + +This is a really cheap test and often makes things a lot faster, but definitely +benchmark to be sure! + +@docs lazy, lazy2, lazy3 +-} + +import Html exposing (Html) +import VirtualDom + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Html msg) -> a -> Html msg +lazy = + VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Html msg) -> a -> b -> Html msg +lazy2 = + VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg +lazy3 = + VirtualDom.lazy3 diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore b/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore new file mode 100644 index 0000000..e185314 --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore @@ -0,0 +1 @@ +elm-stuff \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE b/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE new file mode 100644 index 0000000..737f64b --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json b/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json new file mode 100644 index 0000000..7c6b4ae --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "Make HTTP requests (download progress, rate-limit, debounce, throttle)", + "repository": "https://github.com/elm-lang/http.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Http", + "Http.Progress" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm new file mode 100644 index 0000000..d3ccf27 --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm @@ -0,0 +1,411 @@ +module Http exposing + ( Request, send, Error(..) + , getString, get + , post + , request + , Header, header + , Body, emptyBody, jsonBody, stringBody, multipartBody, Part, stringPart + , Expect, expectString, expectJson, expectStringResponse, Response + , encodeUri, decodeUri, toTask + ) + +{-| Create and send HTTP requests. + +# Send Requests +@docs Request, send, Error + +# GET +@docs getString, get + +# POST +@docs post + +# Custom Requests +@docs request + +## Headers +@docs Header, header + +## Request Bodies +@docs Body, emptyBody, jsonBody, stringBody, multipartBody, Part, stringPart + +## Responses +@docs Expect, expectString, expectJson, expectStringResponse, Response + +# Low-Level +@docs encodeUri, decodeUri, toTask + +-} + +import Dict exposing (Dict) +import Http.Internal +import Json.Decode as Decode +import Json.Encode as Encode +import Maybe exposing (Maybe(..)) +import Native.Http +import Platform.Cmd as Cmd exposing (Cmd) +import Result exposing (Result(..)) +import Task exposing (Task) +import Time exposing (Time) + + + +-- REQUESTS + + +{-| Describes an HTTP request. +-} +type alias Request a = + Http.Internal.Request a + + +{-| Send a `Request`. We could get the text of “War and Peace” like this: + + import Http + + type Msg = Click | NewBook (Result Http.Error String) + + update : Msg -> Model -> Model + update msg model = + case msg of + Click -> + ( model, getWarAndPeace ) + + NewBook (Ok book) -> + ... + + NewBook (Err _) -> + ... + + getWarAndPeace : Cmd Msg + getWarAndPeace = + Http.send NewBook <| + Http.getString "https://example.com/books/war-and-peace.md" +-} +send : (Result Error a -> msg) -> Request a -> Cmd msg +send resultToMessage request = + Task.attempt resultToMessage (toTask request) + + +{-| Convert a `Request` into a `Task`. This is only really useful if you want +to chain together a bunch of requests (or any other tasks) in a single command. +-} +toTask : Request a -> Task Error a +toTask (Http.Internal.Request request) = + Native.Http.toTask request Nothing + + +{-| A `Request` can fail in a couple ways: + + - `BadUrl` means you did not provide a valid URL. + - `Timeout` means it took too long to get a response. + - `NetworkError` means the user turned off their wifi, went in a cave, etc. + - `BadStatus` means you got a response back, but the [status code][sc] + indicates failure. + - `BadPayload` means you got a response back with a nice status code, but + the body of the response was something unexpected. The `String` in this + case is a debugging message that explains what went wrong with your JSON + decoder or whatever. + +[sc]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +-} +type Error + = BadUrl String + | Timeout + | NetworkError + | BadStatus (Response String) + | BadPayload String (Response String) + + + +-- GET + + +{-| Create a `GET` request and interpret the response body as a `String`. + + import Http + + getWarAndPeace : Http.Request String + getWarAndPeace = + Http.getString "https://example.com/books/war-and-peace" +-} +getString : String -> Request String +getString url = + request + { method = "GET" + , headers = [] + , url = url + , body = emptyBody + , expect = expectString + , timeout = Nothing + , withCredentials = False + } + + +{-| Create a `GET` request and try to decode the response body from JSON to +some Elm value. + + import Http + import Json.Decode exposing (list, string) + + getBooks : Http.Request (List String) + getBooks = + Http.get "https://example.com/books" (list string) + +You can learn more about how JSON decoders work [here][] in the guide. + +[here]: https://guide.elm-lang.org/interop/json.html +-} +get : String -> Decode.Decoder a -> Request a +get url decoder = + request + { method = "GET" + , headers = [] + , url = url + , body = emptyBody + , expect = expectJson decoder + , timeout = Nothing + , withCredentials = False + } + + + +-- POST + + +{-| Create a `POST` request and try to decode the response body from JSON to +an Elm value. For example, if we want to send a POST without any data in the +request body, it would be like this: + + import Http + import Json.Decode exposing (list, string) + + postBooks : Http.Request (List String) + postBooks = + Http.post "https://example.com/books" Http.emptyBody (list string) + +See [`jsonBody`](#jsonBody) to learn how to have a more interesting request +body. And check out [this section][here] of the guide to learn more about +JSON decoders. + +[here]: https://guide.elm-lang.org/interop/json.html + +-} +post : String -> Body -> Decode.Decoder a -> Request a +post url body decoder = + request + { method = "POST" + , headers = [] + , url = url + , body = body + , expect = expectJson decoder + , timeout = Nothing + , withCredentials = False + } + + + +-- CUSTOM REQUESTS + + +{-| Create a custom request. For example, a custom PUT request would look like +this: + + put : String -> Body -> Request () + put url body = + request + { method = "PUT" + , headers = [] + , url = url + , body = body + , expect = expectStringResponse (\_ -> Ok ()) + , timeout = Nothing + , withCredentials = False + } +-} +request + : { method : String + , headers : List Header + , url : String + , body : Body + , expect : Expect a + , timeout : Maybe Time + , withCredentials : Bool + } + -> Request a +request = + Http.Internal.Request + + + +-- HEADERS + + +{-| An HTTP header for configuring requests. See a bunch of common headers +[here][]. + +[here]: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields +-} +type alias Header = Http.Internal.Header + + +{-| Create a `Header`. + + header "If-Modified-Since" "Sat 29 Oct 1994 19:43:31 GMT" + header "Max-Forwards" "10" + header "X-Requested-With" "XMLHttpRequest" + +**Note:** In the future, we may split this out into an `Http.Headers` module +and provide helpers for cases that are common on the client-side. If this +sounds nice to you, open an issue [here][] describing the helper you want and +why you need it. + +[here]: https://github.com/elm-lang/http/issues +-} +header : String -> String -> Header +header = + Http.Internal.Header + + + +-- BODY + + +{-| Represents the body of a `Request`. +-} +type alias Body = Http.Internal.Body + + +{-| Create an empty body for your `Request`. This is useful for GET requests +and POST requests where you are not sending any data. +-} +emptyBody : Body +emptyBody = + Http.Internal.EmptyBody + + +{-| Put some JSON value in the body of your `Request`. This will automatically +add the `Content-Type: application/json` header. +-} +jsonBody : Encode.Value -> Body +jsonBody value = + Http.Internal.StringBody "application/json" (Encode.encode 0 value) + + +{-| Put some string in the body of your `Request`. Defining `jsonBody` looks +like this: + + import Json.Encode as Encode + + jsonBody : Encode.Value -> Body + jsonBody value = + stringBody "application/json" (Encode.encode 0 value) + +Notice that the first argument is a [MIME type][mime] so we know to add +`Content-Type: application/json` to our request headers. Make sure your +MIME type matches your data. Some servers are strict about this! + +[mime]: https://en.wikipedia.org/wiki/Media_type +-} +stringBody : String -> String -> Body +stringBody = + Http.Internal.StringBody + + +{-| Create multi-part bodies for your `Request`, automatically adding the +`Content-Type: multipart/form-data` header. +-} +multipartBody : List Part -> Body +multipartBody = + Native.Http.multipart + + +{-| Contents of a multi-part body. Right now it only supports strings, but we +will support blobs and files when we get an API for them in Elm. +-} +type Part + = StringPart String String + + +{-| A named chunk of string data. + + body = + multipartBody + [ stringPart "user" "tom" + , stringPart "payload" "42" + ] +-} +stringPart : String -> String -> Part +stringPart = + StringPart + + + +-- RESPONSES + + +{-| Logic for interpreting a response body. +-} +type alias Expect a = + Http.Internal.Expect a + + +{-| Expect the response body to be a `String`. +-} +expectString : Expect String +expectString = + expectStringResponse (\response -> Ok response.body) + + +{-| Expect the response body to be JSON. You provide a `Decoder` to turn that +JSON into an Elm value. If the body cannot be parsed as JSON or if the JSON +does not match the decoder, the request will resolve to a `BadPayload` error. +-} +expectJson : Decode.Decoder a -> Expect a +expectJson decoder = + expectStringResponse (\response -> Decode.decodeString decoder response.body) + + +{-| Maybe you want the whole `Response`: status code, headers, body, etc. This +lets you get all of that information. From there you can use functions like +`Json.Decode.decodeString` to interpret it as JSON or whatever else you want. +-} +expectStringResponse : (Response String -> Result String a) -> Expect a +expectStringResponse = + Native.Http.expectStringResponse + + +{-| The response from a `Request`. +-} +type alias Response body = + { url : String + , status : { code : Int, message : String } + , headers : Dict String String + , body : body + } + + + +-- LOW-LEVEL + + +{-| Use this to escape query parameters. Converts characters like `/` to `%2F` +so that it does not clash with normal URL + +It work just like `encodeURIComponent` in JavaScript. +-} +encodeUri : String -> String +encodeUri = + Native.Http.encodeUri + + +{-| Use this to unescape query parameters. It converts things like `%2F` to +`/`. It can fail in some cases. For example, there is no way to unescape `%` +because it could never appear alone in a properly escaped string. + +It works just like `decodeURIComponent` in JavaScript. +-} +decodeUri : String -> Maybe String +decodeUri = + Native.Http.decodeUri + diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm new file mode 100644 index 0000000..b547302 --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm @@ -0,0 +1,45 @@ +module Http.Internal exposing + ( Request(..) + , RawRequest + , Expect + , Body(..) + , Header(..) + , map + ) + + +import Native.Http +import Time exposing (Time) + + + +type Request a = Request (RawRequest a) + + +type alias RawRequest a = + { method : String + , headers : List Header + , url : String + , body : Body + , expect : Expect a + , timeout : Maybe Time + , withCredentials : Bool + } + + +type Expect a = Expect + + +type Body + = EmptyBody + | StringBody String String + | FormDataBody + + + +type Header = Header String String + + +map : (a -> b) -> RawRequest a -> RawRequest b +map func request = + { request | expect = Native.Http.mapExpect func request.expect } diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm new file mode 100644 index 0000000..c0b2a78 --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm @@ -0,0 +1,200 @@ +effect module Http.Progress where { subscription = MySub } exposing + ( Progress(..) + , track + ) + +{-| Track the progress of an HTTP request. This can be useful if you are +requesting a large amount of data and want to show the user a progress bar +or something. + +Here is an example usage: [demo][] and [code][]. + +[demo]: https://hirafuji.com.br/elm/http-progress-example/ +[code]: https://gist.github.com/pablohirafuji/fa373d07c42016756d5bca28962008c4 + +**Note:** If you stop tracking progress, you cancel the request. + +# Progress +@docs Progress, track + +-} + + +import Dict +import Http +import Http.Internal exposing ( Request(Request) ) +import Task exposing (Task) +import Platform exposing (Router) +import Process + + + +-- PROGRESS + + +{-| The progress of an HTTP request. + +You start with `None`. As data starts to come in, you will see `Some`. The +`bytesExpected` field will match the `Content-Length` header, indicating how +long the response body is in bytes (8-bits). The `bytes` field indicates how +many bytes have been loaded so far, so if you want progress as a percentage, +you would say: + + Some { bytes, bytesExpected } -> + toFloat bytes / toFloat bytesExpected + +You will end up with `Fail` or `Done` depending on the success of the request. +-} +type Progress data + = None + | Some { bytes : Int, bytesExpected : Int} + | Fail Http.Error + | Done data + + + +-- TRACK + + +{-| Create a subscription that tracks the progress of an HTTP request. + +See it in action in this example: [demo][] and [code][]. + +[demo]: https://hirafuji.com.br/elm/http-progress-example/ +[code]: https://gist.github.com/pablohirafuji/fa373d07c42016756d5bca28962008c4 +-} +track : String -> (Progress data -> msg) -> Http.Request data -> Sub msg +track id toMessage (Request request) = + subscription <| Track id <| + { request = Http.Internal.map (Done >> toMessage) request + , toProgress = Some >> toMessage + , toError = Fail >> toMessage + } + + +type alias TrackedRequest msg = + { request : Http.Internal.RawRequest msg + , toProgress : { bytes : Int, bytesExpected : Int } -> msg + , toError : Http.Error -> msg + } + + +map : (a -> b) -> TrackedRequest a -> TrackedRequest b +map func { request, toProgress, toError } = + { request = Http.Internal.map func request + , toProgress = toProgress >> func + , toError = toError >> func + } + + + +-- SUBSCRIPTIONS + + +type MySub msg = + Track String (TrackedRequest msg) + + +subMap : (a -> b) -> MySub a -> MySub b +subMap func (Track id trackedRequest) = + Track id (map func trackedRequest) + + + +-- EFFECT MANAGER + + +type alias State = + Dict.Dict String Process.Id + + +init : Task Never State +init = + Task.succeed Dict.empty + + + +-- APP MESSAGES + + +onEffects : Platform.Router msg Never -> List (MySub msg) -> State -> Task Never State +onEffects router subs state = + let + subDict = + collectSubs subs + + leftStep id process (dead, ongoing, new) = + ( Process.kill process :: dead + , ongoing + , new + ) + + bothStep id process _ (dead, ongoing, new) = + ( dead + , Dict.insert id process ongoing + , new + ) + + rightStep id trackedRequest (dead, ongoing, new) = + ( dead + , ongoing + , (id, trackedRequest) :: new + ) + + (dead, ongoing, new) = + Dict.merge leftStep bothStep rightStep state subDict ([], Dict.empty, []) + in + Task.sequence dead + |> Task.andThen (\_ -> spawnRequests router new ongoing) + + +spawnRequests : Router msg Never -> List (String, TrackedRequest msg) -> State -> Task Never State +spawnRequests router trackedRequests state = + case trackedRequests of + [] -> + Task.succeed state + + (id, trackedRequest) :: others -> + Process.spawn (toTask router trackedRequest) + |> Task.andThen (\process -> spawnRequests router others (Dict.insert id process state)) + + +toTask : Router msg Never -> TrackedRequest msg -> Task Never () +toTask router { request, toProgress, toError } = + Native.Http.toTask request (Just (Platform.sendToApp router << toProgress)) + |> Task.andThen (Platform.sendToApp router) + |> Task.onError (Platform.sendToApp router << toError) + + + +-- COLLECT SUBS AS DICT + + +type alias SubDict msg = + Dict.Dict String (TrackedRequest msg) + + +collectSubs : List (MySub msg) -> SubDict msg +collectSubs subs = + List.foldl addSub Dict.empty subs + + +addSub : MySub msg -> SubDict msg -> SubDict msg +addSub (Track id trackedRequest) subDict = + let + request = + trackedRequest.request + + uid = + id ++ request.method ++ request.url + in + Dict.insert uid trackedRequest subDict + + + +-- SELF MESSAGES + + +onSelfMsg : Platform.Router msg Never -> Never -> State -> Task Never State +onSelfMsg router _ state = + Task.succeed state diff --git a/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js b/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js new file mode 100644 index 0000000..9f14772 --- /dev/null +++ b/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js @@ -0,0 +1,238 @@ +var _elm_lang$http$Native_Http = function() { + + +// ENCODING AND DECODING + +function encodeUri(string) +{ + return encodeURIComponent(string); +} + +function decodeUri(string) +{ + try + { + return _elm_lang$core$Maybe$Just(decodeURIComponent(string)); + } + catch(e) + { + return _elm_lang$core$Maybe$Nothing; + } +} + + +// SEND REQUEST + +function toTask(request, maybeProgress) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var xhr = new XMLHttpRequest(); + + configureProgress(xhr, maybeProgress); + + xhr.addEventListener('error', function() { + callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'NetworkError' })); + }); + xhr.addEventListener('timeout', function() { + callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'Timeout' })); + }); + xhr.addEventListener('load', function() { + callback(handleResponse(xhr, request.expect.responseToResult)); + }); + + try + { + xhr.open(request.method, request.url, true); + } + catch (e) + { + return callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'BadUrl', _0: request.url })); + } + + configureRequest(xhr, request); + send(xhr, request.body); + + return function() { xhr.abort(); }; + }); +} + +function configureProgress(xhr, maybeProgress) +{ + if (maybeProgress.ctor === 'Nothing') + { + return; + } + + xhr.addEventListener('progress', function(event) { + if (!event.lengthComputable) + { + return; + } + _elm_lang$core$Native_Scheduler.rawSpawn(maybeProgress._0({ + bytes: event.loaded, + bytesExpected: event.total + })); + }); +} + +function configureRequest(xhr, request) +{ + function setHeader(pair) + { + xhr.setRequestHeader(pair._0, pair._1); + } + + A2(_elm_lang$core$List$map, setHeader, request.headers); + xhr.responseType = request.expect.responseType; + xhr.withCredentials = request.withCredentials; + + if (request.timeout.ctor === 'Just') + { + xhr.timeout = request.timeout._0; + } +} + +function send(xhr, body) +{ + switch (body.ctor) + { + case 'EmptyBody': + xhr.send(); + return; + + case 'StringBody': + xhr.setRequestHeader('Content-Type', body._0); + xhr.send(body._1); + return; + + case 'FormDataBody': + xhr.send(body._0); + return; + } +} + + +// RESPONSES + +function handleResponse(xhr, responseToResult) +{ + var response = toResponse(xhr); + + if (xhr.status < 200 || 300 <= xhr.status) + { + response.body = xhr.responseText; + return _elm_lang$core$Native_Scheduler.fail({ + ctor: 'BadStatus', + _0: response + }); + } + + var result = responseToResult(response); + + if (result.ctor === 'Ok') + { + return _elm_lang$core$Native_Scheduler.succeed(result._0); + } + else + { + response.body = xhr.responseText; + return _elm_lang$core$Native_Scheduler.fail({ + ctor: 'BadPayload', + _0: result._0, + _1: response + }); + } +} + +function toResponse(xhr) +{ + return { + status: { code: xhr.status, message: xhr.statusText }, + headers: parseHeaders(xhr.getAllResponseHeaders()), + url: xhr.responseURL, + body: xhr.response + }; +} + +function parseHeaders(rawHeaders) +{ + var headers = _elm_lang$core$Dict$empty; + + if (!rawHeaders) + { + return headers; + } + + var headerPairs = rawHeaders.split('\u000d\u000a'); + for (var i = headerPairs.length; i--; ) + { + var headerPair = headerPairs[i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) + { + var key = headerPair.substring(0, index); + var value = headerPair.substring(index + 2); + + headers = A3(_elm_lang$core$Dict$update, key, function(oldValue) { + if (oldValue.ctor === 'Just') + { + return _elm_lang$core$Maybe$Just(value + ', ' + oldValue._0); + } + return _elm_lang$core$Maybe$Just(value); + }, headers); + } + } + + return headers; +} + + +// EXPECTORS + +function expectStringResponse(responseToResult) +{ + return { + responseType: 'text', + responseToResult: responseToResult + }; +} + +function mapExpect(func, expect) +{ + return { + responseType: expect.responseType, + responseToResult: function(response) { + var convertedResponse = expect.responseToResult(response); + return A2(_elm_lang$core$Result$map, func, convertedResponse); + } + }; +} + + +// BODY + +function multipart(parts) +{ + var formData = new FormData(); + + while (parts.ctor !== '[]') + { + var part = parts._0; + formData.append(part._0, part._1); + parts = parts._1; + } + + return { ctor: 'FormDataBody', _0: formData }; +} + +return { + toTask: F2(toTask), + expectStringResponse: expectStringResponse, + mapExpect: F2(mapExpect), + multipart: multipart, + encodeUri: encodeUri, + decodeUri: decodeUri +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore new file mode 100644 index 0000000..f6a4e83 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore @@ -0,0 +1,3 @@ +node_modules +elm-stuff +tests/build diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE new file mode 100644 index 0000000..0edfd04 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json new file mode 100644 index 0000000..353986f --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.4", + "summary": "Core virtual DOM implementation, basis for HTML and SVG libraries", + "repository": "https://github.com/elm-lang/virtual-dom.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "VirtualDom" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js new file mode 100644 index 0000000..729f171 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js @@ -0,0 +1,280 @@ +var _elm_lang$virtual_dom$Native_Debug = function() { + + +// IMPORT / EXPORT + +function unsafeCoerce(value) +{ + return value; +} + +var upload = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + var element = document.createElement('input'); + element.setAttribute('type', 'file'); + element.setAttribute('accept', 'text/json'); + element.style.display = 'none'; + element.addEventListener('change', function(event) + { + var fileReader = new FileReader(); + fileReader.onload = function(e) + { + callback(_elm_lang$core$Native_Scheduler.succeed(e.target.result)); + }; + fileReader.readAsText(event.target.files[0]); + document.body.removeChild(element); + }); + document.body.appendChild(element); + element.click(); +}); + +function download(historyLength, json) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var fileName = 'history-' + historyLength + '.txt'; + var jsonString = JSON.stringify(json); + var mime = 'text/plain;charset=utf-8'; + var done = _elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0); + + // for IE10+ + if (navigator.msSaveBlob) + { + navigator.msSaveBlob(new Blob([jsonString], {type: mime}), fileName); + return callback(done); + } + + // for HTML5 + var element = document.createElement('a'); + element.setAttribute('href', 'data:' + mime + ',' + encodeURIComponent(jsonString)); + element.setAttribute('download', fileName); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + callback(done); + }); +} + + +// POPOUT + +function messageToString(value) +{ + switch (typeof value) + { + case 'boolean': + return value ? 'True' : 'False'; + case 'number': + return value + ''; + case 'string': + return '"' + addSlashes(value, false) + '"'; + } + if (value instanceof String) + { + return '\'' + addSlashes(value, true) + '\''; + } + if (typeof value !== 'object' || value === null || !('ctor' in value)) + { + return '…'; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Tupl' || ctorStarter === '_Task') + { + return '…' + } + if (['_Array', '', '_Process', '::', '[]', 'Set_elm_builtin', 'RBNode_elm_builtin', 'RBEmpty_elm_builtin'].indexOf(value.ctor) >= 0) + { + return '…'; + } + + var keys = Object.keys(value); + switch (keys.length) + { + case 1: + return value.ctor; + case 2: + return value.ctor + ' ' + messageToString(value._0); + default: + return value.ctor + ' … ' + messageToString(value[keys[keys.length - 1]]); + } +} + + +function primitive(str) +{ + return { ctor: 'Primitive', _0: str }; +} + + +function init(value) +{ + var type = typeof value; + + if (type === 'boolean') + { + return { + ctor: 'Constructor', + _0: _elm_lang$core$Maybe$Just(value ? 'True' : 'False'), + _1: true, + _2: _elm_lang$core$Native_List.Nil + }; + } + + if (type === 'number') + { + return primitive(value + ''); + } + + if (type === 'string') + { + return { ctor: 'S', _0: '"' + addSlashes(value, false) + '"' }; + } + + if (value instanceof String) + { + return { ctor: 'S', _0: "'" + addSlashes(value, true) + "'" }; + } + + if (value instanceof Date) + { + return primitive('<' + value.toString() + '>'); + } + + if (value === null) + { + return primitive('XXX'); + } + + if (type === 'object' && 'ctor' in value) + { + var ctor = value.ctor; + + if (ctor === '::' || ctor === '[]') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ListSeq'}, + _1: true, + _2: A2(_elm_lang$core$List$map, init, value) + }; + } + + if (ctor === 'Set_elm_builtin') + { + return { + ctor: 'Sequence', + _0: {ctor: 'SetSeq'}, + _1: true, + _2: A3(_elm_lang$core$Set$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === 'RBNode_elm_builtin' || ctor == 'RBEmpty_elm_builtin') + { + return { + ctor: 'Dictionary', + _0: true, + _1: A3(_elm_lang$core$Dict$foldr, initKeyValueCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === '_Array') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ArraySeq'}, + _1: true, + _2: A3(_elm_lang$core$Array$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Task') + { + return primitive(''); + } + + if (ctor === '') + { + return primitive(ctor); + } + + if (ctor === '_Process') + { + return primitive(''); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i in value) + { + if (i === 'ctor') continue; + list = _elm_lang$core$Native_List.Cons(init(value[i]), list); + } + return { + ctor: 'Constructor', + _0: ctorStarter === '_Tupl' ? _elm_lang$core$Maybe$Nothing : _elm_lang$core$Maybe$Just(ctor), + _1: true, + _2: _elm_lang$core$List$reverse(list) + }; + } + + if (type === 'object') + { + var dict = _elm_lang$core$Dict$empty; + for (var i in value) + { + dict = A3(_elm_lang$core$Dict$insert, i, init(value[i]), dict); + } + return { ctor: 'Record', _0: true, _1: dict }; + } + + return primitive('XXX'); +} + +var initCons = F2(initConsHelp); + +function initConsHelp(value, list) +{ + return _elm_lang$core$Native_List.Cons(init(value), list); +} + +var initKeyValueCons = F3(initKeyValueConsHelp); + +function initKeyValueConsHelp(key, value, list) +{ + return _elm_lang$core$Native_List.Cons( + _elm_lang$core$Native_Utils.Tuple2(init(key), init(value)), + list + ); +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + upload: upload, + download: F2(download), + unsafeCoerce: unsafeCoerce, + messageToString: messageToString, + init: init +} + +}(); diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js new file mode 100644 index 0000000..98d4750 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js @@ -0,0 +1,1881 @@ +var _elm_lang$virtual_dom$VirtualDom_Debug$wrap; +var _elm_lang$virtual_dom$VirtualDom_Debug$wrapWithFlags; + +var _elm_lang$virtual_dom$Native_VirtualDom = function() { + +var STYLE_KEY = 'STYLE'; +var EVENT_KEY = 'EVENT'; +var ATTR_KEY = 'ATTR'; +var ATTR_NS_KEY = 'ATTR_NS'; + +var localDoc = typeof document !== 'undefined' ? document : {}; + + +//////////// VIRTUAL DOM NODES //////////// + + +function text(string) +{ + return { + type: 'text', + text: string + }; +} + + +function node(tag) +{ + return F2(function(factList, kidList) { + return nodeHelp(tag, factList, kidList); + }); +} + + +function nodeHelp(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function keyedNode(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid._1.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'keyed-node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function custom(factList, model, impl) +{ + var facts = organizeFacts(factList).facts; + + return { + type: 'custom', + facts: facts, + model: model, + impl: impl + }; +} + + +function map(tagger, node) +{ + return { + type: 'tagger', + tagger: tagger, + node: node, + descendantsCount: 1 + (node.descendantsCount || 0) + }; +} + + +function thunk(func, args, thunk) +{ + return { + type: 'thunk', + func: func, + args: args, + thunk: thunk, + node: undefined + }; +} + +function lazy(fn, a) +{ + return thunk(fn, [a], function() { + return fn(a); + }); +} + +function lazy2(fn, a, b) +{ + return thunk(fn, [a,b], function() { + return A2(fn, a, b); + }); +} + +function lazy3(fn, a, b, c) +{ + return thunk(fn, [a,b,c], function() { + return A3(fn, a, b, c); + }); +} + + + +// FACTS + + +function organizeFacts(factList) +{ + var namespace, facts = {}; + + while (factList.ctor !== '[]') + { + var entry = factList._0; + var key = entry.key; + + if (key === ATTR_KEY || key === ATTR_NS_KEY || key === EVENT_KEY) + { + var subFacts = facts[key] || {}; + subFacts[entry.realKey] = entry.value; + facts[key] = subFacts; + } + else if (key === STYLE_KEY) + { + var styles = facts[key] || {}; + var styleList = entry.value; + while (styleList.ctor !== '[]') + { + var style = styleList._0; + styles[style._0] = style._1; + styleList = styleList._1; + } + facts[key] = styles; + } + else if (key === 'namespace') + { + namespace = entry.value; + } + else if (key === 'className') + { + var classes = facts[key]; + facts[key] = typeof classes === 'undefined' + ? entry.value + : classes + ' ' + entry.value; + } + else + { + facts[key] = entry.value; + } + factList = factList._1; + } + + return { + facts: facts, + namespace: namespace + }; +} + + + +//////////// PROPERTIES AND ATTRIBUTES //////////// + + +function style(value) +{ + return { + key: STYLE_KEY, + value: value + }; +} + + +function property(key, value) +{ + return { + key: key, + value: value + }; +} + + +function attribute(key, value) +{ + return { + key: ATTR_KEY, + realKey: key, + value: value + }; +} + + +function attributeNS(namespace, key, value) +{ + return { + key: ATTR_NS_KEY, + realKey: key, + value: { + value: value, + namespace: namespace + } + }; +} + + +function on(name, options, decoder) +{ + return { + key: EVENT_KEY, + realKey: name, + value: { + options: options, + decoder: decoder + } + }; +} + + +function equalEvents(a, b) +{ + if (a.options !== b.options) + { + if (a.options.stopPropagation !== b.options.stopPropagation || a.options.preventDefault !== b.options.preventDefault) + { + return false; + } + } + return _elm_lang$core$Native_Json.equality(a.decoder, b.decoder); +} + + +function mapProperty(func, property) +{ + if (property.key !== EVENT_KEY) + { + return property; + } + return on( + property.realKey, + property.value.options, + A2(_elm_lang$core$Json_Decode$map, func, property.value.decoder) + ); +} + + +//////////// RENDER //////////// + + +function render(vNode, eventNode) +{ + switch (vNode.type) + { + case 'thunk': + if (!vNode.node) + { + vNode.node = vNode.thunk(); + } + return render(vNode.node, eventNode); + + case 'tagger': + var subNode = vNode.node; + var tagger = vNode.tagger; + + while (subNode.type === 'tagger') + { + typeof tagger !== 'object' + ? tagger = [tagger, subNode.tagger] + : tagger.push(subNode.tagger); + + subNode = subNode.node; + } + + var subEventRoot = { tagger: tagger, parent: eventNode }; + var domNode = render(subNode, subEventRoot); + domNode.elm_event_node_ref = subEventRoot; + return domNode; + + case 'text': + return localDoc.createTextNode(vNode.text); + + case 'node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i], eventNode)); + } + + return domNode; + + case 'keyed-node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i]._1, eventNode)); + } + + return domNode; + + case 'custom': + var domNode = vNode.impl.render(vNode.model); + applyFacts(domNode, eventNode, vNode.facts); + return domNode; + } +} + + + +//////////// APPLY FACTS //////////// + + +function applyFacts(domNode, eventNode, facts) +{ + for (var key in facts) + { + var value = facts[key]; + + switch (key) + { + case STYLE_KEY: + applyStyles(domNode, value); + break; + + case EVENT_KEY: + applyEvents(domNode, eventNode, value); + break; + + case ATTR_KEY: + applyAttrs(domNode, value); + break; + + case ATTR_NS_KEY: + applyAttrsNS(domNode, value); + break; + + case 'value': + if (domNode[key] !== value) + { + domNode[key] = value; + } + break; + + default: + domNode[key] = value; + break; + } + } +} + +function applyStyles(domNode, styles) +{ + var domNodeStyle = domNode.style; + + for (var key in styles) + { + domNodeStyle[key] = styles[key]; + } +} + +function applyEvents(domNode, eventNode, events) +{ + var allHandlers = domNode.elm_handlers || {}; + + for (var key in events) + { + var handler = allHandlers[key]; + var value = events[key]; + + if (typeof value === 'undefined') + { + domNode.removeEventListener(key, handler); + allHandlers[key] = undefined; + } + else if (typeof handler === 'undefined') + { + var handler = makeEventHandler(eventNode, value); + domNode.addEventListener(key, handler); + allHandlers[key] = handler; + } + else + { + handler.info = value; + } + } + + domNode.elm_handlers = allHandlers; +} + +function makeEventHandler(eventNode, info) +{ + function eventHandler(event) + { + var info = eventHandler.info; + + var value = A2(_elm_lang$core$Native_Json.run, info.decoder, event); + + if (value.ctor === 'Ok') + { + var options = info.options; + if (options.stopPropagation) + { + event.stopPropagation(); + } + if (options.preventDefault) + { + event.preventDefault(); + } + + var message = value._0; + + var currentEventNode = eventNode; + while (currentEventNode) + { + var tagger = currentEventNode.tagger; + if (typeof tagger === 'function') + { + message = tagger(message); + } + else + { + for (var i = tagger.length; i--; ) + { + message = tagger[i](message); + } + } + currentEventNode = currentEventNode.parent; + } + } + }; + + eventHandler.info = info; + + return eventHandler; +} + +function applyAttrs(domNode, attrs) +{ + for (var key in attrs) + { + var value = attrs[key]; + if (typeof value === 'undefined') + { + domNode.removeAttribute(key); + } + else + { + domNode.setAttribute(key, value); + } + } +} + +function applyAttrsNS(domNode, nsAttrs) +{ + for (var key in nsAttrs) + { + var pair = nsAttrs[key]; + var namespace = pair.namespace; + var value = pair.value; + + if (typeof value === 'undefined') + { + domNode.removeAttributeNS(namespace, key); + } + else + { + domNode.setAttributeNS(namespace, key, value); + } + } +} + + + +//////////// DIFF //////////// + + +function diff(a, b) +{ + var patches = []; + diffHelp(a, b, patches, 0); + return patches; +} + + +function makePatch(type, index, data) +{ + return { + index: index, + type: type, + data: data, + domNode: undefined, + eventNode: undefined + }; +} + + +function diffHelp(a, b, patches, index) +{ + if (a === b) + { + return; + } + + var aType = a.type; + var bType = b.type; + + // Bail if you run into different types of nodes. Implies that the + // structure has changed significantly and it's not worth a diff. + if (aType !== bType) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // Now we know that both nodes are the same type. + switch (bType) + { + case 'thunk': + var aArgs = a.args; + var bArgs = b.args; + var i = aArgs.length; + var same = a.func === b.func && i === bArgs.length; + while (same && i--) + { + same = aArgs[i] === bArgs[i]; + } + if (same) + { + b.node = a.node; + return; + } + b.node = b.thunk(); + var subPatches = []; + diffHelp(a.node, b.node, subPatches, 0); + if (subPatches.length > 0) + { + patches.push(makePatch('p-thunk', index, subPatches)); + } + return; + + case 'tagger': + // gather nested taggers + var aTaggers = a.tagger; + var bTaggers = b.tagger; + var nesting = false; + + var aSubNode = a.node; + while (aSubNode.type === 'tagger') + { + nesting = true; + + typeof aTaggers !== 'object' + ? aTaggers = [aTaggers, aSubNode.tagger] + : aTaggers.push(aSubNode.tagger); + + aSubNode = aSubNode.node; + } + + var bSubNode = b.node; + while (bSubNode.type === 'tagger') + { + nesting = true; + + typeof bTaggers !== 'object' + ? bTaggers = [bTaggers, bSubNode.tagger] + : bTaggers.push(bSubNode.tagger); + + bSubNode = bSubNode.node; + } + + // Just bail if different numbers of taggers. This implies the + // structure of the virtual DOM has changed. + if (nesting && aTaggers.length !== bTaggers.length) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // check if taggers are "the same" + if (nesting ? !pairwiseRefEqual(aTaggers, bTaggers) : aTaggers !== bTaggers) + { + patches.push(makePatch('p-tagger', index, bTaggers)); + } + + // diff everything below the taggers + diffHelp(aSubNode, bSubNode, patches, index + 1); + return; + + case 'text': + if (a.text !== b.text) + { + patches.push(makePatch('p-text', index, b.text)); + return; + } + + return; + + case 'node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffChildren(a, b, patches, index); + return; + + case 'keyed-node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffKeyedChildren(a, b, patches, index); + return; + + case 'custom': + if (a.impl !== b.impl) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + var patch = b.impl.diff(a,b); + if (patch) + { + patches.push(makePatch('p-custom', index, patch)); + return; + } + + return; + } +} + + +// assumes the incoming arrays are the same length +function pairwiseRefEqual(as, bs) +{ + for (var i = 0; i < as.length; i++) + { + if (as[i] !== bs[i]) + { + return false; + } + } + + return true; +} + + +// TODO Instead of creating a new diff object, it's possible to just test if +// there *is* a diff. During the actual patch, do the diff again and make the +// modifications directly. This way, there's no new allocations. Worth it? +function diffFacts(a, b, category) +{ + var diff; + + // look for changes and removals + for (var aKey in a) + { + if (aKey === STYLE_KEY || aKey === EVENT_KEY || aKey === ATTR_KEY || aKey === ATTR_NS_KEY) + { + var subDiff = diffFacts(a[aKey], b[aKey] || {}, aKey); + if (subDiff) + { + diff = diff || {}; + diff[aKey] = subDiff; + } + continue; + } + + // remove if not in the new facts + if (!(aKey in b)) + { + diff = diff || {}; + diff[aKey] = + (typeof category === 'undefined') + ? (typeof a[aKey] === 'string' ? '' : null) + : + (category === STYLE_KEY) + ? '' + : + (category === EVENT_KEY || category === ATTR_KEY) + ? undefined + : + { namespace: a[aKey].namespace, value: undefined }; + + continue; + } + + var aValue = a[aKey]; + var bValue = b[aKey]; + + // reference equal, so don't worry about it + if (aValue === bValue && aKey !== 'value' + || category === EVENT_KEY && equalEvents(aValue, bValue)) + { + continue; + } + + diff = diff || {}; + diff[aKey] = bValue; + } + + // add new stuff + for (var bKey in b) + { + if (!(bKey in a)) + { + diff = diff || {}; + diff[bKey] = b[bKey]; + } + } + + return diff; +} + + +function diffChildren(aParent, bParent, patches, rootIndex) +{ + var aChildren = aParent.children; + var bChildren = bParent.children; + + var aLen = aChildren.length; + var bLen = bChildren.length; + + // FIGURE OUT IF THERE ARE INSERTS OR REMOVALS + + if (aLen > bLen) + { + patches.push(makePatch('p-remove-last', rootIndex, aLen - bLen)); + } + else if (aLen < bLen) + { + patches.push(makePatch('p-append', rootIndex, bChildren.slice(aLen))); + } + + // PAIRWISE DIFF EVERYTHING ELSE + + var index = rootIndex; + var minLen = aLen < bLen ? aLen : bLen; + for (var i = 0; i < minLen; i++) + { + index++; + var aChild = aChildren[i]; + diffHelp(aChild, bChildren[i], patches, index); + index += aChild.descendantsCount || 0; + } +} + + + +//////////// KEYED DIFF //////////// + + +function diffKeyedChildren(aParent, bParent, patches, rootIndex) +{ + var localPatches = []; + + var changes = {}; // Dict String Entry + var inserts = []; // Array { index : Int, entry : Entry } + // type Entry = { tag : String, vnode : VNode, index : Int, data : _ } + + var aChildren = aParent.children; + var bChildren = bParent.children; + var aLen = aChildren.length; + var bLen = bChildren.length; + var aIndex = 0; + var bIndex = 0; + + var index = rootIndex; + + while (aIndex < aLen && bIndex < bLen) + { + var a = aChildren[aIndex]; + var b = bChildren[bIndex]; + + var aKey = a._0; + var bKey = b._0; + var aNode = a._1; + var bNode = b._1; + + // check if keys match + + if (aKey === bKey) + { + index++; + diffHelp(aNode, bNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex++; + bIndex++; + continue; + } + + // look ahead 1 to detect insertions and removals. + + var aLookAhead = aIndex + 1 < aLen; + var bLookAhead = bIndex + 1 < bLen; + + if (aLookAhead) + { + var aNext = aChildren[aIndex + 1]; + var aNextKey = aNext._0; + var aNextNode = aNext._1; + var oldMatch = bKey === aNextKey; + } + + if (bLookAhead) + { + var bNext = bChildren[bIndex + 1]; + var bNextKey = bNext._0; + var bNextNode = bNext._1; + var newMatch = aKey === bNextKey; + } + + + // swap a and b + if (aLookAhead && bLookAhead && newMatch && oldMatch) + { + index++; + diffHelp(aNode, bNextNode, localPatches, index); + insertNode(changes, localPatches, aKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + removeNode(changes, localPatches, aKey, aNextNode, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + // insert b + if (bLookAhead && newMatch) + { + index++; + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + diffHelp(aNode, bNextNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex += 1; + bIndex += 2; + continue; + } + + // remove a + if (aLookAhead && oldMatch) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 1; + continue; + } + + // remove a, insert b + if (aLookAhead && bLookAhead && aNextKey === bNextKey) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNextNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + break; + } + + // eat up any remaining nodes with removeNode and insertNode + + while (aIndex < aLen) + { + index++; + var a = aChildren[aIndex]; + var aNode = a._1; + removeNode(changes, localPatches, a._0, aNode, index); + index += aNode.descendantsCount || 0; + aIndex++; + } + + var endInserts; + while (bIndex < bLen) + { + endInserts = endInserts || []; + var b = bChildren[bIndex]; + insertNode(changes, localPatches, b._0, b._1, undefined, endInserts); + bIndex++; + } + + if (localPatches.length > 0 || inserts.length > 0 || typeof endInserts !== 'undefined') + { + patches.push(makePatch('p-reorder', rootIndex, { + patches: localPatches, + inserts: inserts, + endInserts: endInserts + })); + } +} + + + +//////////// CHANGES FROM KEYED DIFF //////////// + + +var POSTFIX = '_elmW6BL'; + + +function insertNode(changes, localPatches, key, vnode, bIndex, inserts) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + entry = { + tag: 'insert', + vnode: vnode, + index: bIndex, + data: undefined + }; + + inserts.push({ index: bIndex, entry: entry }); + changes[key] = entry; + + return; + } + + // this key was removed earlier, a match! + if (entry.tag === 'remove') + { + inserts.push({ index: bIndex, entry: entry }); + + entry.tag = 'move'; + var subPatches = []; + diffHelp(entry.vnode, vnode, subPatches, entry.index); + entry.index = bIndex; + entry.data.data = { + patches: subPatches, + entry: entry + }; + + return; + } + + // this key has already been inserted or moved, a duplicate! + insertNode(changes, localPatches, key + POSTFIX, vnode, bIndex, inserts); +} + + +function removeNode(changes, localPatches, key, vnode, index) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + var patch = makePatch('p-remove', index, undefined); + localPatches.push(patch); + + changes[key] = { + tag: 'remove', + vnode: vnode, + index: index, + data: patch + }; + + return; + } + + // this key was inserted earlier, a match! + if (entry.tag === 'insert') + { + entry.tag = 'move'; + var subPatches = []; + diffHelp(vnode, entry.vnode, subPatches, index); + + var patch = makePatch('p-remove', index, { + patches: subPatches, + entry: entry + }); + localPatches.push(patch); + + return; + } + + // this key has already been removed or moved, a duplicate! + removeNode(changes, localPatches, key + POSTFIX, vnode, index); +} + + + +//////////// ADD DOM NODES //////////// +// +// Each DOM node has an "index" assigned in order of traversal. It is important +// to minimize our crawl over the actual DOM, so these indexes (along with the +// descendantsCount of virtual nodes) let us skip touching entire subtrees of +// the DOM if we know there are no patches there. + + +function addDomNodes(domNode, vNode, patches, eventNode) +{ + addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.descendantsCount, eventNode); +} + + +// assumes `patches` is non-empty and indexes increase monotonically. +function addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode) +{ + var patch = patches[i]; + var index = patch.index; + + while (index === low) + { + var patchType = patch.type; + + if (patchType === 'p-thunk') + { + addDomNodes(domNode, vNode.node, patch.data, eventNode); + } + else if (patchType === 'p-reorder') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var subPatches = patch.data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + else if (patchType === 'p-remove') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var data = patch.data; + if (typeof data !== 'undefined') + { + data.entry.data = domNode; + var subPatches = data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + } + else + { + patch.domNode = domNode; + patch.eventNode = eventNode; + } + + i++; + + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + + switch (vNode.type) + { + case 'tagger': + var subNode = vNode.node; + + while (subNode.type === "tagger") + { + subNode = subNode.node; + } + + return addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref); + + case 'node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'keyed-node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]._1; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'text': + case 'thunk': + throw new Error('should never traverse `text` or `thunk` nodes like this'); + } +} + + + +//////////// APPLY PATCHES //////////// + + +function applyPatches(rootDomNode, oldVirtualNode, patches, eventNode) +{ + if (patches.length === 0) + { + return rootDomNode; + } + + addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode); + return applyPatchesHelp(rootDomNode, patches); +} + +function applyPatchesHelp(rootDomNode, patches) +{ + for (var i = 0; i < patches.length; i++) + { + var patch = patches[i]; + var localDomNode = patch.domNode + var newNode = applyPatch(localDomNode, patch); + if (localDomNode === rootDomNode) + { + rootDomNode = newNode; + } + } + return rootDomNode; +} + +function applyPatch(domNode, patch) +{ + switch (patch.type) + { + case 'p-redraw': + return applyPatchRedraw(domNode, patch.data, patch.eventNode); + + case 'p-facts': + applyFacts(domNode, patch.eventNode, patch.data); + return domNode; + + case 'p-text': + domNode.replaceData(0, domNode.length, patch.data); + return domNode; + + case 'p-thunk': + return applyPatchesHelp(domNode, patch.data); + + case 'p-tagger': + if (typeof domNode.elm_event_node_ref !== 'undefined') + { + domNode.elm_event_node_ref.tagger = patch.data; + } + else + { + domNode.elm_event_node_ref = { tagger: patch.data, parent: patch.eventNode }; + } + return domNode; + + case 'p-remove-last': + var i = patch.data; + while (i--) + { + domNode.removeChild(domNode.lastChild); + } + return domNode; + + case 'p-append': + var newNodes = patch.data; + for (var i = 0; i < newNodes.length; i++) + { + domNode.appendChild(render(newNodes[i], patch.eventNode)); + } + return domNode; + + case 'p-remove': + var data = patch.data; + if (typeof data === 'undefined') + { + domNode.parentNode.removeChild(domNode); + return domNode; + } + var entry = data.entry; + if (typeof entry.index !== 'undefined') + { + domNode.parentNode.removeChild(domNode); + } + entry.data = applyPatchesHelp(domNode, data.patches); + return domNode; + + case 'p-reorder': + return applyPatchReorder(domNode, patch); + + case 'p-custom': + var impl = patch.data; + return impl.applyPatch(domNode, impl.data); + + default: + throw new Error('Ran into an unknown patch!'); + } +} + + +function applyPatchRedraw(domNode, vNode, eventNode) +{ + var parentNode = domNode.parentNode; + var newNode = render(vNode, eventNode); + + if (typeof newNode.elm_event_node_ref === 'undefined') + { + newNode.elm_event_node_ref = domNode.elm_event_node_ref; + } + + if (parentNode && newNode !== domNode) + { + parentNode.replaceChild(newNode, domNode); + } + return newNode; +} + + +function applyPatchReorder(domNode, patch) +{ + var data = patch.data; + + // remove end inserts + var frag = applyPatchReorderEndInsertsHelp(data.endInserts, patch); + + // removals + domNode = applyPatchesHelp(domNode, data.patches); + + // inserts + var inserts = data.inserts; + for (var i = 0; i < inserts.length; i++) + { + var insert = inserts[i]; + var entry = insert.entry; + var node = entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode); + domNode.insertBefore(node, domNode.childNodes[insert.index]); + } + + // add end inserts + if (typeof frag !== 'undefined') + { + domNode.appendChild(frag); + } + + return domNode; +} + + +function applyPatchReorderEndInsertsHelp(endInserts, patch) +{ + if (typeof endInserts === 'undefined') + { + return; + } + + var frag = localDoc.createDocumentFragment(); + for (var i = 0; i < endInserts.length; i++) + { + var insert = endInserts[i]; + var entry = insert.entry; + frag.appendChild(entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode) + ); + } + return frag; +} + + +// PROGRAMS + +var program = makeProgram(checkNoFlags); +var programWithFlags = makeProgram(checkYesFlags); + +function makeProgram(flagChecker) +{ + return F2(function(debugWrap, impl) + { + return function(flagDecoder) + { + return function(object, moduleName, debugMetadata) + { + var checker = flagChecker(flagDecoder, moduleName); + if (typeof debugMetadata === 'undefined') + { + normalSetup(impl, object, moduleName, checker); + } + else + { + debugSetup(A2(debugWrap, debugMetadata, impl), object, moduleName, checker); + } + }; + }; + }); +} + +function staticProgram(vNode) +{ + var nothing = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + _elm_lang$core$Platform_Cmd$none + ); + return A2(program, _elm_lang$virtual_dom$VirtualDom_Debug$wrap, { + init: nothing, + view: function() { return vNode; }, + update: F2(function() { return nothing; }), + subscriptions: function() { return _elm_lang$core$Platform_Sub$none; } + })(); +} + + +// FLAG CHECKERS + +function checkNoFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flags === 'undefined') + { + return init; + } + + var errorMessage = + 'The `' + moduleName + '` module does not need flags.\n' + + 'Initialize it with no arguments and you should be all set!'; + + crash(errorMessage, domNode); + }; +} + +function checkYesFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flagDecoder === 'undefined') + { + var errorMessage = + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + + crash(errorMessage, domNode); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Ok') + { + return init(result._0); + } + + var errorMessage = + 'Trying to initialize the `' + moduleName + '` module with an unexpected flag.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0; + + crash(errorMessage, domNode); + }; +} + +function crash(errorMessage, domNode) +{ + if (domNode) + { + domNode.innerHTML = + '
' + + '

Oops! Something went wrong when starting your Elm program.

' + + '
' + errorMessage + '
' + + '
'; + } + + throw new Error(errorMessage); +} + + +// NORMAL SETUP + +function normalSetup(impl, object, moduleName, flagChecker) +{ + object['embed'] = function embed(node, flags) + { + while (node.lastChild) + { + node.removeChild(node.lastChild); + } + + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update, + impl.subscriptions, + normalRenderer(node, impl.view) + ); + }; + + object['fullscreen'] = function fullscreen(flags) + { + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update, + impl.subscriptions, + normalRenderer(document.body, impl.view) + ); + }; +} + +function normalRenderer(parentNode, view) +{ + return function(tagger, initialModel) + { + var eventNode = { tagger: tagger, parent: undefined }; + var initialVirtualNode = view(initialModel); + var domNode = render(initialVirtualNode, eventNode); + parentNode.appendChild(domNode); + return makeStepper(domNode, view, initialVirtualNode, eventNode); + }; +} + + +// STEPPER + +var rAF = + typeof requestAnimationFrame !== 'undefined' + ? requestAnimationFrame + : function(callback) { setTimeout(callback, 1000 / 60); }; + +function makeStepper(domNode, view, initialVirtualNode, eventNode) +{ + var state = 'NO_REQUEST'; + var currNode = initialVirtualNode; + var nextModel; + + function updateIfNeeded() + { + switch (state) + { + case 'NO_REQUEST': + throw new Error( + 'Unexpected draw callback.\n' + + 'Please report this to .' + ); + + case 'PENDING_REQUEST': + rAF(updateIfNeeded); + state = 'EXTRA_REQUEST'; + + var nextNode = view(nextModel); + var patches = diff(currNode, nextNode); + domNode = applyPatches(domNode, currNode, patches, eventNode); + currNode = nextNode; + + return; + + case 'EXTRA_REQUEST': + state = 'NO_REQUEST'; + return; + } + } + + return function stepper(model) + { + if (state === 'NO_REQUEST') + { + rAF(updateIfNeeded); + } + state = 'PENDING_REQUEST'; + nextModel = model; + }; +} + + +// DEBUG SETUP + +function debugSetup(impl, object, moduleName, flagChecker) +{ + object['fullscreen'] = function fullscreen(flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, document.body, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; + + object['embed'] = function fullscreen(node, flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, node, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; +} + +function scrollTask(popoutRef) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var doc = popoutRef.doc; + if (doc) + { + var msgs = doc.getElementsByClassName('debugger-sidebar-messages')[0]; + if (msgs) + { + msgs.scrollTop = msgs.scrollHeight; + } + } + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + + +function debugRenderer(moduleName, parentNode, popoutRef, view, viewIn, viewOut) +{ + return function(tagger, initialModel) + { + var appEventNode = { tagger: tagger, parent: undefined }; + var eventNode = { tagger: tagger, parent: undefined }; + + // make normal stepper + var appVirtualNode = view(initialModel); + var appNode = render(appVirtualNode, appEventNode); + parentNode.appendChild(appNode); + var appStepper = makeStepper(appNode, view, appVirtualNode, appEventNode); + + // make overlay stepper + var overVirtualNode = viewIn(initialModel)._1; + var overNode = render(overVirtualNode, eventNode); + parentNode.appendChild(overNode); + var wrappedViewIn = wrapViewIn(appEventNode, overNode, viewIn); + var overStepper = makeStepper(overNode, wrappedViewIn, overVirtualNode, eventNode); + + // make debugger stepper + var debugStepper = makeDebugStepper(initialModel, viewOut, eventNode, parentNode, moduleName, popoutRef); + + return function stepper(model) + { + appStepper(model); + overStepper(model); + debugStepper(model); + } + }; +} + +function makeDebugStepper(initialModel, view, eventNode, parentNode, moduleName, popoutRef) +{ + var curr; + var domNode; + + return function stepper(model) + { + if (!model.isDebuggerOpen) + { + return; + } + + if (!popoutRef.doc) + { + curr = view(model); + domNode = openDebugWindow(moduleName, popoutRef, curr, eventNode); + return; + } + + // switch to document of popout + localDoc = popoutRef.doc; + + var next = view(model); + var patches = diff(curr, next); + domNode = applyPatches(domNode, curr, patches, eventNode); + curr = next; + + // switch back to normal document + localDoc = document; + }; +} + +function openDebugWindow(moduleName, popoutRef, virtualNode, eventNode) +{ + var w = 900; + var h = 360; + var x = screen.width - w; + var y = screen.height - h; + var debugWindow = window.open('', '', 'width=' + w + ',height=' + h + ',left=' + x + ',top=' + y); + + // switch to window document + localDoc = debugWindow.document; + + popoutRef.doc = localDoc; + localDoc.title = 'Debugger - ' + moduleName; + localDoc.body.style.margin = '0'; + localDoc.body.style.padding = '0'; + var domNode = render(virtualNode, eventNode); + localDoc.body.appendChild(domNode); + + localDoc.addEventListener('keydown', function(event) { + if (event.metaKey && event.which === 82) + { + window.location.reload(); + } + if (event.which === 38) + { + eventNode.tagger({ ctor: 'Up' }); + event.preventDefault(); + } + if (event.which === 40) + { + eventNode.tagger({ ctor: 'Down' }); + event.preventDefault(); + } + }); + + function close() + { + popoutRef.doc = undefined; + debugWindow.close(); + } + window.addEventListener('unload', close); + debugWindow.addEventListener('unload', function() { + popoutRef.doc = undefined; + window.removeEventListener('unload', close); + eventNode.tagger({ ctor: 'Close' }); + }); + + // switch back to the normal document + localDoc = document; + + return domNode; +} + + +// BLOCK EVENTS + +function wrapViewIn(appEventNode, overlayNode, viewIn) +{ + var ignorer = makeIgnorer(overlayNode); + var blocking = 'Normal'; + var overflow; + + var normalTagger = appEventNode.tagger; + var blockTagger = function() {}; + + return function(model) + { + var tuple = viewIn(model); + var newBlocking = tuple._0.ctor; + appEventNode.tagger = newBlocking === 'Normal' ? normalTagger : blockTagger; + if (blocking !== newBlocking) + { + traverse('removeEventListener', ignorer, blocking); + traverse('addEventListener', ignorer, newBlocking); + + if (blocking === 'Normal') + { + overflow = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + } + + if (newBlocking === 'Normal') + { + document.body.style.overflow = overflow; + } + + blocking = newBlocking; + } + return tuple._1; + } +} + +function traverse(verbEventListener, ignorer, blocking) +{ + switch(blocking) + { + case 'Normal': + return; + + case 'Pause': + return traverseHelp(verbEventListener, ignorer, mostEvents); + + case 'Message': + return traverseHelp(verbEventListener, ignorer, allEvents); + } +} + +function traverseHelp(verbEventListener, handler, eventNames) +{ + for (var i = 0; i < eventNames.length; i++) + { + document.body[verbEventListener](eventNames[i], handler, true); + } +} + +function makeIgnorer(overlayNode) +{ + return function(event) + { + if (event.type === 'keydown' && event.metaKey && event.which === 82) + { + return; + } + + var isScroll = event.type === 'scroll' || event.type === 'wheel'; + + var node = event.target; + while (node !== null) + { + if (node.className === 'elm-overlay-message-details' && isScroll) + { + return; + } + + if (node === overlayNode && !isScroll) + { + return; + } + node = node.parentNode; + } + + event.stopPropagation(); + event.preventDefault(); + } +} + +var mostEvents = [ + 'click', 'dblclick', 'mousemove', + 'mouseup', 'mousedown', 'mouseenter', 'mouseleave', + 'touchstart', 'touchend', 'touchcancel', 'touchmove', + 'pointerdown', 'pointerup', 'pointerover', 'pointerout', + 'pointerenter', 'pointerleave', 'pointermove', 'pointercancel', + 'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave', 'drop', + 'keyup', 'keydown', 'keypress', + 'input', 'change', + 'focus', 'blur' +]; + +var allEvents = mostEvents.concat('wheel', 'scroll'); + + +return { + node: node, + text: text, + custom: custom, + map: F2(map), + + on: F3(on), + style: style, + property: F2(property), + attribute: F2(attribute), + attributeNS: F3(attributeNS), + mapProperty: F2(mapProperty), + + lazy: F2(lazy), + lazy2: F3(lazy2), + lazy3: F4(lazy3), + keyedNode: F3(keyedNode), + + program: program, + programWithFlags: programWithFlags, + staticProgram: staticProgram +}; + +}(); diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm new file mode 100644 index 0000000..ac28926 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm @@ -0,0 +1,331 @@ +module VirtualDom exposing + ( Node + , text, node + , Property, property, attribute, attributeNS, mapProperty + , style + , on, onWithOptions, Options, defaultOptions + , map + , lazy, lazy2, lazy3 + , keyedNode + , program, programWithFlags + ) + +{-| API to the core diffing algorithm. Can serve as a foundation for libraries +that expose more helper functions for HTML or SVG. + +# Create +@docs Node, text, node + +# Declare Properties and Attributes +@docs Property, property, attribute, attributeNS, mapProperty + +# Styles +@docs style + +# Events +@docs on, onWithOptions, Options, defaultOptions + +# Routing Messages +@docs map + +# Optimizations +@docs lazy, lazy2, lazy3, keyedNode + +# Programs +@docs program, programWithFlags + +-} + +import Json.Decode as Json +import Native.VirtualDom +import VirtualDom.Debug as Debug + + +{-| An immutable chunk of data representing a DOM node. This can be HTML or SVG. +-} +type Node msg = Node + + +{-| Create a DOM node with a tag name, a list of HTML properties that can +include styles and event listeners, a list of CSS properties like `color`, and +a list of child nodes. + + import Json.Encode as Json + + hello : Node msg + hello = + node "div" [] [ text "Hello!" ] + + greeting : Node msg + greeting = + node "div" + [ property "id" (Json.string "greeting") ] + [ text "Hello!" ] +-} +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Node msg +text = + Native.VirtualDom.text + + +{-| This function is useful when nesting components with [the Elm +Architecture](https://github.com/evancz/elm-architecture-tutorial/). It lets +you transform the messages produced by a subtree. + +Say you have a node named `button` that produces `()` values when it is +clicked. To get your model updating properly, you will probably want to tag +this `()` value like this: + + type Msg = Click | ... + + update msg model = + case msg of + Click -> + ... + + view model = + map (\_ -> Click) button + +So now all the events produced by `button` will be transformed to be of type +`Msg` so they can be handled by your update function! +-} +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + + +-- PROPERTIES + + +{-| When using HTML and JS, there are two ways to specify parts of a DOM node. + + 1. Attributes — You can set things in HTML itself. So the `class` + in `
` is called an *attribute*. + + 2. Properties — You can also set things in JS. So the `className` + in `div.className = 'greeting'` is called a *property*. + +So the `class` attribute corresponds to the `className` property. At first +glance, perhaps this distinction is defensible, but it gets much crazier. +*There is not always a one-to-one mapping between attributes and properties!* +Yes, that is a true fact. Sometimes an attribute exists, but there is no +corresponding property. Sometimes changing an attribute does not change the +underlying property. For example, as of this writing, the `webkit-playsinline` +attribute can be used in HTML, but there is no corresponding property! +-} +type Property msg = Property + + +{-| Create arbitrary *properties*. + + import JavaScript.Encode as Json + + greeting : Html + greeting = + node "div" [ property "className" (Json.string "greeting") ] [ + text "Hello!" + ] + +Notice that you must give the *property* name, so we use `className` as it +would be in JavaScript, not `class` as it would appear in HTML. +-} +property : String -> Json.Value -> Property msg +property = + Native.VirtualDom.property + + +{-| Create arbitrary HTML *attributes*. Maps onto JavaScript’s `setAttribute` +function under the hood. + + greeting : Html + greeting = + node "div" [ attribute "class" "greeting" ] [ + text "Hello!" + ] + +Notice that you must give the *attribute* name, so we use `class` as it would +be in HTML, not `className` as it would appear in JS. +-} +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +{-| Would you believe that there is another way to do this?! This corresponds +to JavaScript's `setAttributeNS` function under the hood. It is doing pretty +much the same thing as `attribute` but you are able to have "namespaced" +attributes. This is used in some SVG stuff at least. +-} +attributeNS : String -> String -> String -> Property msg +attributeNS = + Native.VirtualDom.attributeNS + + +{-| Transform the messages produced by a `Property`. +-} +mapProperty : (a -> b) -> Property a -> Property b +mapProperty = + Native.VirtualDom.mapProperty + + +{-| Specify a list of styles. + + myStyle : Property msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Node msg + greeting = + node "div" [ myStyle ] [ text "Hello!" ] + +-} +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + + +-- EVENTS + + +{-| Create a custom event listener. + + import Json.Decode as Json + + onClick : msg -> Property msg + onClick msg = + on "click" (Json.succeed msg) + +You first specify the name of the event in the same format as with JavaScript’s +`addEventListener`. Next you give a JSON decoder, which lets you pull +information out of the event object. If the decoder succeeds, it will produce +a message and route it to your `update` function. +-} +on : String -> Json.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + + +-- OPTIMIZATION + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +{-| Works just like `node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + + + +-- PROGRAMS + + +{-| Check out the docs for [`Html.App.program`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#program +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program Never model msg +program impl = + Native.VirtualDom.program Debug.wrap impl + + +{-| Check out the docs for [`Html.App.programWithFlags`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#programWithFlags +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program flags model msg +programWithFlags impl = + Native.VirtualDom.programWithFlags Debug.wrapWithFlags impl + diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm new file mode 100644 index 0000000..ba7afe5 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm @@ -0,0 +1,567 @@ +module VirtualDom.Debug exposing (wrap, wrapWithFlags) + +import Json.Decode as Decode +import Json.Encode as Encode +import Task exposing (Task) +import Native.Debug +import Native.VirtualDom +import VirtualDom.Expando as Expando exposing (Expando) +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.History as History exposing (History) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Overlay as Overlay +import VirtualDom.Report as Report + + + +-- WRAP PROGRAMS + + +wrap metadata { init, update, subscriptions, view } = + { init = wrapInit metadata init + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + +wrapWithFlags metadata { init, update, subscriptions, view } = + { init = \flags -> wrapInit metadata (init flags) + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + + +-- MODEL + + +type alias Model model msg = + { history : History model msg + , state : State model + , expando : Expando + , metadata : Result Metadata.Error Metadata + , overlay : Overlay.State + , isDebuggerOpen : Bool + } + + +type State model + = Running model + | Paused Int model model + + +wrapInit : Encode.Value -> ( model, Cmd msg ) -> ( Model model msg, Cmd (Msg msg) ) +wrapInit metadata ( userModel, userCommands ) = + { history = History.empty userModel + , state = Running userModel + , expando = Expando.init userModel + , metadata = Metadata.decode metadata + , overlay = Overlay.none + , isDebuggerOpen = False + } + ! [ Cmd.map UserMsg userCommands ] + + + +-- UPDATE + + +type Msg msg + = NoOp + | UserMsg msg + | ExpandoMsg Expando.Msg + | Resume + | Jump Int + | Open + | Close + | Up + | Down + | Import + | Export + | Upload String + | OverlayMsg Overlay.Msg + + +type alias UserUpdate model msg = + msg -> model -> ( model, Cmd msg ) + + +wrapUpdate + : UserUpdate model msg + -> Task Never () + -> Msg msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +wrapUpdate userUpdate scrollTask msg model = + case msg of + NoOp -> + model ! [] + + UserMsg userMsg -> + updateUserMsg userUpdate scrollTask userMsg model + + ExpandoMsg eMsg -> + { model + | expando = Expando.update eMsg model.expando + } + ! [] + + Resume -> + case model.state of + Running _ -> + model ! [] + + Paused _ _ userModel -> + { model + | state = Running userModel + , expando = Expando.merge userModel model.expando + } + ! [ runIf model.isDebuggerOpen scrollTask ] + + Jump index -> + let + (indexModel, indexMsg) = + History.get userUpdate index model.history + in + { model + | state = Paused index indexModel (getLatestModel model.state) + , expando = Expando.merge indexModel model.expando + } + ! [] + + Open -> + { model | isDebuggerOpen = True } ! [] + + Close -> + { model | isDebuggerOpen = False } ! [] + + Up -> + let + index = + case model.state of + Paused index _ _ -> + index + + Running _ -> + History.size model.history + in + if index > 0 then + wrapUpdate userUpdate scrollTask (Jump (index - 1)) model + else + model ! [] + + Down -> + case model.state of + Running _ -> + model ! [] + + Paused index _ userModel -> + if index == History.size model.history - 1 then + wrapUpdate userUpdate scrollTask Resume model + else + wrapUpdate userUpdate scrollTask (Jump (index + 1)) model + + Import -> + withGoodMetadata model <| \_ -> + model ! [ upload ] + + Export -> + withGoodMetadata model <| \metadata -> + model ! [ download metadata model.history ] + + Upload jsonString -> + withGoodMetadata model <| \metadata -> + case Overlay.assessImport metadata jsonString of + Err newOverlay -> + { model | overlay = newOverlay } ! [] + + Ok rawHistory -> + loadNewHistory rawHistory userUpdate model + + OverlayMsg overlayMsg -> + case Overlay.close overlayMsg model.overlay of + Nothing -> + { model | overlay = Overlay.none } ! [] + + Just rawHistory -> + loadNewHistory rawHistory userUpdate model + + + +-- COMMANDS + + +upload : Cmd (Msg msg) +upload = + Task.perform Upload Native.Debug.upload + + +download : Metadata -> History model msg -> Cmd (Msg msg) +download metadata history = + let + historyLength = + History.size history + + json = + Encode.object + [ ("metadata", Metadata.encode metadata) + , ("history", History.encode history) + ] + in + Task.perform (\_ -> NoOp) (Native.Debug.download historyLength json) + + + +-- UPDATE OVERLAY + + +withGoodMetadata + : Model model msg + -> (Metadata -> (Model model msg, Cmd (Msg msg))) + -> (Model model msg, Cmd (Msg msg)) +withGoodMetadata model func = + case model.metadata of + Ok metadata -> + func metadata + + Err error -> + { model | overlay = Overlay.badMetadata error } ! [] + + +loadNewHistory + : Encode.Value + -> UserUpdate model msg + -> Model model msg + -> ( Model model msg, Cmd (Msg msg) ) +loadNewHistory rawHistory userUpdate model = + let + initialUserModel = + History.initialModel model.history + + pureUserUpdate msg userModel = + Tuple.first (userUpdate msg userModel) + + decoder = + History.decoder initialUserModel pureUserUpdate + in + case Decode.decodeValue decoder rawHistory of + Err _ -> + { model | overlay = Overlay.corruptImport } ! [] + + Ok (latestUserModel, newHistory) -> + { model + | history = newHistory + , state = Running latestUserModel + , expando = Expando.init latestUserModel + , overlay = Overlay.none + } + ! [] + + + +-- UPDATE - USER MESSAGES + + +updateUserMsg + : UserUpdate model msg + -> Task Never () + -> msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +updateUserMsg userUpdate scrollTask userMsg ({ history, state, expando } as model) = + let + userModel = + getLatestModel state + + newHistory = + History.add userMsg userModel history + + (newUserModel, userCmds) = + userUpdate userMsg userModel + + commands = + Cmd.map UserMsg userCmds + in + case state of + Running _ -> + { model + | history = newHistory + , state = Running newUserModel + , expando = Expando.merge newUserModel expando + } + ! [ commands, runIf model.isDebuggerOpen scrollTask ] + + Paused index indexModel _ -> + { model + | history = newHistory + , state = Paused index indexModel newUserModel + } + ! [ commands ] + + +runIf : Bool -> Task Never () -> Cmd (Msg msg) +runIf bool task = + if bool then + Task.perform (always NoOp) task + else + Cmd.none + + +getLatestModel : State model -> model +getLatestModel state = + case state of + Running model -> + model + + Paused _ _ model -> + model + + + +-- SUBSCRIPTIONS + + +wrapSubs : (model -> Sub msg) -> Model model msg -> Sub (Msg msg) +wrapSubs userSubscriptions {state} = + getLatestModel state + |> userSubscriptions + |> Sub.map UserMsg + + + +-- VIEW + + +wrapView : (model -> Node msg) -> Model model msg -> Node (Msg msg) +wrapView userView { state } = + let + currentModel = + case state of + Running model -> + model + + Paused _ oldModel _ -> + oldModel + in + VDom.map UserMsg (userView currentModel) + + + +-- SMALL DEBUG VIEW + + +viewIn : Model model msg -> ( Overlay.Block, Node (Msg msg) ) +viewIn { history, state, overlay, isDebuggerOpen } = + let + isPaused = + case state of + Running _ -> + False + + Paused _ _ _ -> + True + in + Overlay.view overlayConfig isPaused isDebuggerOpen (History.size history) overlay + + +overlayConfig : Overlay.Config (Msg msg) +overlayConfig = + { resume = Resume + , open = Open + , importHistory = Import + , exportHistory = Export + , wrap = OverlayMsg + } + + + +-- BIG DEBUG VIEW + + +viewOut : Model model msg -> Node (Msg msg) +viewOut { history, state, expando } = + VDom.div + [ VDom.id "debugger" ] + [ styles + , viewSidebar state history + , VDom.map ExpandoMsg <| + VDom.div [ VDom.id "values" ] [ Expando.view Nothing expando ] + ] + + +viewSidebar : State model -> History model msg -> Node (Msg msg) +viewSidebar state history = + let + maybeIndex = + case state of + Running _ -> + Nothing + + Paused index _ _ -> + Just index + in + VDom.div [ VDom.class "debugger-sidebar" ] + [ VDom.map Jump (History.view maybeIndex history) + , playButton maybeIndex + ] + + +playButton : Maybe Int -> Node (Msg msg) +playButton maybeIndex = + VDom.div [ VDom.class "debugger-sidebar-controls" ] + [ viewResumeButton maybeIndex + , VDom.div [ VDom.class "debugger-sidebar-controls-import-export" ] + [ button Import "Import" + , VDom.text " / " + , button Export "Export" + ] + ] + + +button msg label = + VDom.span + [ VDom.onClick msg + , VDom.style [("cursor","pointer")] + ] + [ VDom.text label ] + + +viewResumeButton maybeIndex = + case maybeIndex of + Nothing -> + VDom.text "" + + Just _ -> + resumeButton + + +resumeButton = + VDom.div + [ VDom.onClick Resume + , VDom.class "debugger-sidebar-controls-resume" + ] + [ VDom.text "Resume" + ] + + + +-- STYLE + + +styles : Node msg +styles = + VDom.node "style" [] [ VDom.text """ + +html { + overflow: hidden; + height: 100%; +} + +body { + height: 100%; + overflow: auto; +} + +#debugger { + width: 100% + height: 100%; + font-family: monospace; +} + +#values { + display: block; + float: left; + height: 100%; + width: calc(100% - 30ch); + margin: 0; + overflow: auto; + cursor: default; +} + +.debugger-sidebar { + display: block; + float: left; + width: 30ch; + height: 100%; + color: white; + background-color: rgb(61, 61, 61); +} + +.debugger-sidebar-controls { + width: 100%; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.debugger-sidebar-controls-import-export { + width: 100%; + height: 24px; + line-height: 24px; + font-size: 12px; +} + +.debugger-sidebar-controls-resume { + width: 100%; + height: 30px; + line-height: 30px; + cursor: pointer; +} + +.debugger-sidebar-controls-resume:hover { + background-color: rgb(41, 41, 41); +} + +.debugger-sidebar-messages { + width: 100%; + overflow-y: auto; + height: calc(100% - 24px); +} + +.debugger-sidebar-messages-paused { + width: 100%; + overflow-y: auto; + height: calc(100% - 54px); +} + +.messages-entry { + cursor: pointer; + width: 100%; +} + +.messages-entry:hover { + background-color: rgb(41, 41, 41); +} + +.messages-entry-selected, .messages-entry-selected:hover { + background-color: rgb(10, 10, 10); +} + +.messages-entry-content { + width: calc(100% - 7ch); + padding-top: 4px; + padding-bottom: 4px; + padding-left: 1ch; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + display: inline-block; +} + +.messages-entry-index { + color: #666; + width: 5ch; + padding-top: 4px; + padding-bottom: 4px; + padding-right: 1ch; + text-align: right; + display: block; + float: right; +} + +""" ] diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm new file mode 100644 index 0000000..88b5857 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm @@ -0,0 +1,659 @@ +module VirtualDom.Expando exposing + ( Expando + , init + , merge + , Msg, update + , view + ) + + +import Dict exposing (Dict) +import Json.Decode as Json +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node, text, div, span, class, onClick) + + + +-- MODEL + + +type Expando + = S String + | Primitive String + | Sequence SeqType Bool (List Expando) + | Dictionary Bool (List (Expando, Expando)) + | Record Bool (Dict String Expando) + | Constructor (Maybe String) Bool (List Expando) + + +type SeqType = ListSeq | SetSeq | ArraySeq + + +seqTypeToString : Int -> SeqType -> String +seqTypeToString n seqType = + case seqType of + ListSeq -> + "List(" ++ toString n ++ ")" + + SetSeq -> + "Set(" ++ toString n ++ ")" + + ArraySeq -> + "Array(" ++ toString n ++ ")" + + + +-- INITIALIZE + + +init : a -> Expando +init value = + initHelp True (Native.Debug.init value) + + +initHelp : Bool -> Expando -> Expando +initHelp isOuter expando = + case expando of + S _ -> + expando + + Primitive _ -> + expando + + Sequence seqType isClosed items -> + if isOuter then + Sequence seqType False (List.map (initHelp False) items) + else if List.length items <= 8 then + Sequence seqType False items + else + expando + + Dictionary isClosed keyValuePairs -> + if isOuter then + Dictionary False (List.map (\(k,v) -> (k, initHelp False v)) keyValuePairs) + else if List.length keyValuePairs <= 8 then + Dictionary False keyValuePairs + else + expando + + Record isClosed entries -> + if isOuter then + Record False (Dict.map (\_ v -> initHelp False v) entries) + else if Dict.size entries <= 4 then + Record False entries + else + expando + + Constructor maybeName isClosed args -> + if isOuter then + Constructor maybeName False (List.map (initHelp False) args) + else if List.length args <= 4 then + Constructor maybeName False args + else + expando + + + +-- PRESERVE OLD EXPANDO STATE (open/closed) + + +merge : a -> Expando -> Expando +merge value expando = + mergeHelp expando (Native.Debug.init value) + + +mergeHelp : Expando -> Expando -> Expando +mergeHelp old new = + case ( old, new ) of + ( _, S _ ) -> + new + + ( _, Primitive _ ) -> + new + + ( Sequence _ isClosed oldValues, Sequence seqType _ newValues ) -> + Sequence seqType isClosed (mergeListHelp oldValues newValues) + + ( Dictionary isClosed _, Dictionary _ keyValuePairs ) -> + Dictionary isClosed keyValuePairs + + ( Record isClosed oldDict, Record _ newDict ) -> + Record isClosed <| Dict.map (mergeDictHelp oldDict) newDict + + ( Constructor _ isClosed oldValues, Constructor maybeName _ newValues ) -> + Constructor maybeName isClosed (mergeListHelp oldValues newValues) + + _ -> + new + + +mergeListHelp : List Expando -> List Expando -> List Expando +mergeListHelp olds news = + case (olds, news) of + ( [], _ ) -> + news + + ( _, [] ) -> + news + + ( x :: xs, y :: ys ) -> + mergeHelp x y :: mergeListHelp xs ys + + +mergeDictHelp : Dict String Expando -> String -> Expando -> Expando +mergeDictHelp oldDict key value = + case Dict.get key oldDict of + Nothing -> + value + + Just oldValue -> + mergeHelp oldValue value + + + +-- UPDATE + + +type Msg + = Toggle + | Index Redirect Int Msg + | Field String Msg + + +type Redirect = None | Key | Value + + +update : Msg -> Expando -> Expando +update msg value = + case value of + S _ -> + Debug.crash "No messages for primitives" + + Primitive _ -> + Debug.crash "No messages for primitives" + + Sequence seqType isClosed valueList -> + case msg of + Toggle -> + Sequence seqType (not isClosed) valueList + + Index None index subMsg -> + Sequence seqType isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field on sequences" + + Dictionary isClosed keyValuePairs -> + case msg of + Toggle -> + Dictionary (not isClosed) keyValuePairs + + Index redirect index subMsg -> + case redirect of + None -> + Debug.crash "must have redirect for dictionaries" + + Key -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (update subMsg k, v)) keyValuePairs + + Value -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (k, update subMsg v)) keyValuePairs + + Field _ _ -> + Debug.crash "no field for dictionaries" + + Record isClosed valueDict -> + case msg of + Toggle -> + Record (not isClosed) valueDict + + Index _ _ _ -> + Debug.crash "No index for records" + + Field field subMsg -> + Record isClosed (Dict.update field (updateField subMsg) valueDict) + + Constructor maybeName isClosed valueList -> + case msg of + Toggle -> + Constructor maybeName (not isClosed) valueList + + Index None index subMsg -> + Constructor maybeName isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field for constructors" + + +updateIndex : Int -> (a -> a) -> List a -> List a +updateIndex n func list = + case list of + [] -> + [] + + x :: xs -> + if n <= 0 then + func x :: xs + else + x :: updateIndex (n-1) func xs + + +updateField : Msg -> Maybe Expando -> Maybe Expando +updateField msg maybeExpando = + case maybeExpando of + Nothing -> + Debug.crash "key does not exist" + + Just expando -> + Just (update msg expando) + + + +-- VIEW + + +view : Maybe String -> Expando -> Node Msg +view maybeKey expando = + case expando of + S stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [red] [text stringRep]]) + + Primitive stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [blue] [text stringRep]]) + + Sequence seqType isClosed valueList -> + viewSequence maybeKey seqType isClosed valueList + + Dictionary isClosed keyValuePairs -> + viewDictionary maybeKey isClosed keyValuePairs + + Record isClosed valueDict -> + viewRecord maybeKey isClosed valueDict + + Constructor maybeName isClosed valueList -> + viewConstructor maybeKey maybeName isClosed valueList + + + +-- VIEW SEQUENCE + + +viewSequence : Maybe String -> SeqType -> Bool -> List Expando -> Node Msg +viewSequence maybeKey seqType isClosed valueList = + let + starter = + seqTypeToString (List.length valueList) seqType + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewSequenceOpen valueList + ] + + +viewSequenceOpen : List Expando -> Node Msg +viewSequenceOpen values = + div [] (List.indexedMap viewConstructorEntry values) + + + +-- VIEW DICTIONARY + + +viewDictionary : Maybe String -> Bool -> List (Expando, Expando) -> Node Msg +viewDictionary maybeKey isClosed keyValuePairs = + let + starter = + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewDictionaryOpen keyValuePairs + ] + + +viewDictionaryOpen : List (Expando, Expando) -> Node Msg +viewDictionaryOpen keyValuePairs = + div [] (List.indexedMap viewDictionaryEntry keyValuePairs) + + +viewDictionaryEntry : Int -> (Expando, Expando) -> Node Msg +viewDictionaryEntry index (key, value) = + case key of + S stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + Primitive stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + _ -> + div [] + [ VDom.map (Index Key index) (view (Just "key") key) + , VDom.map (Index Value index) (view (Just "value") value) + ] + + + +-- VIEW RECORD + + +viewRecord : Maybe String -> Bool -> Dict String Expando -> Node Msg +viewRecord maybeKey isClosed record = + let + (start, middle, end) = + if isClosed then + ( Tuple.second (viewTinyRecord record), text "", text "" ) + else + ( [ text "{" ], viewRecordOpen record, div [leftPad (Just ())] [text "}"] ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) start) + , middle + , end + ] + + +viewRecordOpen : Dict String Expando -> Node Msg +viewRecordOpen record = + div [] (List.map viewRecordEntry (Dict.toList record)) + + +viewRecordEntry : (String, Expando) -> Node Msg +viewRecordEntry (field, value) = + VDom.map (Field field) (view (Just field) value) + + + +-- VIEW CONSTRUCTOR + + +viewConstructor : Maybe String -> Maybe String -> Bool -> List Expando -> Node Msg +viewConstructor maybeKey maybeName isClosed valueList = + let + tinyArgs = + List.map (Tuple.second << viewExtraTiny) valueList + + description = + case (maybeName, tinyArgs) of + (Nothing, []) -> + [ text "()" ] + + (Nothing, x :: xs) -> + text "( " + :: span [] x + :: List.foldr (\args rest -> text ", " :: span [] args :: rest) [text " )"] xs + + (Just name, []) -> + [ text name ] + + (Just name, x :: xs) -> + text (name ++ " ") + :: span [] x + :: List.foldr (\args rest -> text " " :: span [] args :: rest) [] xs + + (maybeIsClosed, openHtml) = + case valueList of + [] -> + ( Nothing, div [] [] ) + + [entry] -> + case entry of + S _ -> + ( Nothing, div [] [] ) + + Primitive _ -> + ( Nothing, div [] [] ) + + Sequence _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewSequenceOpen subValueList) + ) + + Dictionary _ keyValuePairs -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewDictionaryOpen keyValuePairs) + ) + + Record _ record -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewRecordOpen record) + ) + + Constructor _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewConstructorOpen subValueList) + ) + + _ -> + ( Just isClosed + , if isClosed then div [] [] else viewConstructorOpen valueList + ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey maybeIsClosed description) + , openHtml + ] + + +viewConstructorOpen : List Expando -> Node Msg +viewConstructorOpen valueList = + div [] (List.indexedMap viewConstructorEntry valueList) + + +viewConstructorEntry : Int -> Expando -> Node Msg +viewConstructorEntry index value = + VDom.map (Index None index) (view (Just (toString index)) value) + + + +-- VIEW TINY + + +viewTiny : Expando -> ( Int, List (Node msg) ) +viewTiny value = + case value of + S stringRep -> + let + str = + elideMiddle stringRep + in + ( String.length str + , [ span [red] [text str] ] + ) + + Primitive stringRep -> + ( String.length stringRep + , [ span [blue] [text stringRep] ] + ) + + Sequence seqType _ valueList -> + viewTinyHelp <| + seqTypeToString (List.length valueList) seqType + + Dictionary _ keyValuePairs -> + viewTinyHelp <| + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + + Record _ record -> + viewTinyRecord record + + Constructor maybeName _ [] -> + viewTinyHelp <| + Maybe.withDefault "Unit" maybeName + + Constructor maybeName _ valueList -> + viewTinyHelp <| + case maybeName of + Nothing -> + "Tuple(" ++ toString (List.length valueList) ++ ")" + + Just name -> + name ++ " …" + + +viewTinyHelp : String -> ( Int, List (Node msg) ) +viewTinyHelp str = + ( String.length str, [text str] ) + + +elideMiddle : String -> String +elideMiddle str = + if String.length str <= 18 then + str + + else + String.left 8 str ++ "..." ++ String.right 8 str + + + +-- VIEW TINY RECORDS + + +viewTinyRecord : Dict String Expando -> ( Int, List (Node msg) ) +viewTinyRecord record = + if Dict.isEmpty record then + ( 2, [text "{}"] ) + + else + viewTinyRecordHelp 0 "{ " (Dict.toList record) + + +viewTinyRecordHelp : Int -> String -> List (String, Expando) -> ( Int, List (Node msg) ) +viewTinyRecordHelp length starter entries = + case entries of + [] -> + ( length + 2, [ text " }" ] ) + + (field, value) :: rest -> + let + fieldLen = + String.length field + + (valueLen, valueNodes) = + viewExtraTiny value + + newLength = + length + fieldLen + valueLen + 5 + in + if newLength > 60 then + ( length + 4, [text ", … }"] ) + + else + let + ( finalLength, otherNodes ) = + viewTinyRecordHelp newLength ", " rest + in + ( finalLength + , text starter + :: span [purple] [text field] + :: text " = " + :: span [] valueNodes + :: otherNodes + ) + + +viewExtraTiny : Expando -> ( Int, List (Node msg) ) +viewExtraTiny value = + case value of + Record _ record -> + viewExtraTinyRecord 0 "{" (Dict.keys record) + + _ -> + viewTiny value + + +viewExtraTinyRecord : Int -> String -> List String -> ( Int, List (Node msg) ) +viewExtraTinyRecord length starter entries = + case entries of + [] -> + ( length + 1, [text "}"] ) + + field :: rest -> + let + nextLength = + length + String.length field + 1 + in + if nextLength > 18 then + ( length + 2, [text "…}"]) + + else + let + (finalLength, otherNodes) = + viewExtraTinyRecord nextLength "," rest + in + ( finalLength + , text starter :: span [purple] [text field] :: otherNodes + ) + + + +-- VIEW HELPERS + + +lineStarter : Maybe String -> Maybe Bool -> List (Node msg) -> List (Node msg) +lineStarter maybeKey maybeIsClosed description = + let + arrow = + case maybeIsClosed of + Nothing -> + makeArrow "" + + Just True -> + makeArrow "▸" + + Just False -> + makeArrow "▾" + in + case maybeKey of + Nothing -> + arrow :: description + + Just key -> + arrow :: span [purple] [text key] :: text " = " :: description + + +makeArrow : String -> Node msg +makeArrow arrow = + span + [ VDom.style + [ ("color", "#777") + , ("padding-left", "2ch") + , ("width", "2ch") + , ("display", "inline-block") + ] + ] + [ text arrow ] + + +leftPad : Maybe a -> VDom.Property msg +leftPad maybeKey = + case maybeKey of + Nothing -> + VDom.style [] + + Just _ -> + VDom.style [("padding-left", "4ch")] + + +red : VDom.Property msg +red = + VDom.style [("color", "rgb(196, 26, 22)")] + + +blue : VDom.Property msg +blue = + VDom.style [("color", "rgb(28, 0, 207)")] + + +purple : VDom.Property msg +purple = + VDom.style [("color", "rgb(136, 19, 145)")] diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm new file mode 100644 index 0000000..104e23b --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm @@ -0,0 +1,137 @@ +module VirtualDom.Helpers exposing + ( Node + , text, node, div, span, a, h1 + , Property, property, attribute + , class, id, href + , style + , on, onWithOptions, Options, defaultOptions + , onClick + , map + , lazy, lazy2, lazy3 + , keyedNode + ) + + +import Json.Decode as Decode +import Json.Encode as Encode +import Native.VirtualDom + + +type Node msg = Node + + +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +text : String -> Node msg +text = + Native.VirtualDom.text + + +div : List (Property msg) -> List (Node msg) -> Node msg +div = + node "div" + + +span : List (Property msg) -> List (Node msg) -> Node msg +span = + node "span" + + +a : List (Property msg) -> List (Node msg) -> Node msg +a = + node "a" + + +h1 : List (Property msg) -> List (Node msg) -> Node msg +h1 = + node "h1" + + +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + +type Property msg = Property + + +property : String -> Decode.Value -> Property msg +property = + Native.VirtualDom.property + + +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +class : String -> Property msg +class name = + property "className" (Encode.string name) + + +href : String -> Property msg +href name = + property "href" (Encode.string name) + + +id : String -> Property msg +id = + attribute "id" + + +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + +on : String -> Decode.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +onClick : msg -> Property msg +onClick msg = + on "click" (Decode.succeed msg) + + +onWithOptions : String -> Options -> Decode.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm new file mode 100644 index 0000000..bd9a28d --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm @@ -0,0 +1,290 @@ +module VirtualDom.History exposing + ( History + , empty + , size + , initialModel + , add + , get + , view + , decoder + , encode + ) + + +import Array exposing (Array) +import Json.Decode as Decode +import Json.Encode as Encode +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.Metadata as Metadata + + + +-- CONSTANTS + + +maxSnapshotSize : Int +maxSnapshotSize = + 64 + + + +-- HISTORY + + +type alias History model msg = + { snapshots : Array (Snapshot model msg) + , recent : RecentHistory model msg + , numMessages : Int + } + + +type alias RecentHistory model msg = + { model : model + , messages : List msg + , numMessages : Int + } + + +type alias Snapshot model msg = + { model : model + , messages : Array msg + } + + +empty : model -> History model msg +empty model = + History Array.empty (RecentHistory model [] 0) 0 + + +size : History model msg -> Int +size history = + history.numMessages + + +initialModel : History model msg -> model +initialModel { snapshots, recent } = + case Array.get 0 snapshots of + Just { model } -> + model + + Nothing -> + recent.model + + + +-- JSON + + +decoder : model -> (msg -> model -> model) -> Decode.Decoder (model, History model msg) +decoder initialModel update = + let + addMessage rawMsg (model, history) = + let + msg = + jsToElm rawMsg + in + (update msg model, add msg model history) + + updateModel rawMsgs = + List.foldl addMessage (initialModel, empty initialModel) rawMsgs + in + Decode.map updateModel (Decode.list Decode.value) + + +jsToElm : Encode.Value -> a +jsToElm = + Native.Debug.unsafeCoerce + + +encode : History model msg -> Encode.Value +encode { snapshots, recent } = + let + recentJson = + List.map elmToJs (List.reverse recent.messages) + in + Encode.list <| Array.foldr encodeHelp recentJson snapshots + + +encodeHelp : Snapshot model msg -> List Encode.Value -> List Encode.Value +encodeHelp snapshot allMessages = + Array.foldl (\elm msgs -> elmToJs elm :: msgs) allMessages snapshot.messages + + +elmToJs : a -> Encode.Value +elmToJs = + Native.Debug.unsafeCoerce + + + +-- ADD MESSAGES + + +add : msg -> model -> History model msg -> History model msg +add msg model { snapshots, recent, numMessages } = + case addRecent msg model recent of + (Just snapshot, newRecent) -> + History (Array.push snapshot snapshots) newRecent (numMessages + 1) + + (Nothing, newRecent) -> + History snapshots newRecent (numMessages + 1) + + +addRecent + : msg + -> model + -> RecentHistory model msg + -> ( Maybe (Snapshot model msg), RecentHistory model msg ) +addRecent msg newModel { model, messages, numMessages } = + if numMessages == maxSnapshotSize then + ( Just (Snapshot model (Array.fromList messages)) + , RecentHistory newModel [msg] 1 + ) + + else + ( Nothing + , RecentHistory model (msg :: messages) (numMessages + 1) + ) + + + +-- GET SUMMARY + + +get : (msg -> model -> (model, a)) -> Int -> History model msg -> ( model, msg ) +get update index { snapshots, recent, numMessages } = + let + snapshotMax = + numMessages - recent.numMessages + in + if index >= snapshotMax then + undone <| + List.foldr (getHelp update) (Stepping (index - snapshotMax) recent.model) recent.messages + + else + case Array.get (index // maxSnapshotSize) snapshots of + Nothing -> + Debug.crash "UI should only let you ask for real indexes!" + + Just { model, messages } -> + undone <| + Array.foldr (getHelp update) (Stepping (rem index maxSnapshotSize) model) messages + + +type GetResult model msg + = Stepping Int model + | Done msg model + + +getHelp : (msg -> model -> (model, a)) -> msg -> GetResult model msg -> GetResult model msg +getHelp update msg getResult = + case getResult of + Done _ _ -> + getResult + + Stepping n model -> + if n == 0 then + Done msg (Tuple.first (update msg model)) + + else + Stepping (n - 1) (Tuple.first (update msg model)) + + +undone : GetResult model msg -> ( model, msg ) +undone getResult = + case getResult of + Done msg model -> + ( model, msg ) + + Stepping _ _ -> + Debug.crash "Bug in History.get" + + + +-- VIEW + + +view : Maybe Int -> History model msg -> Node Int +view maybeIndex { snapshots, recent, numMessages } = + let + (index, className) = + case maybeIndex of + Nothing -> + ( -1, "debugger-sidebar-messages" ) + Just i -> + ( i, "debugger-sidebar-messages-paused" ) + + oldStuff = + VDom.lazy2 viewSnapshots index snapshots + + newStuff = + Tuple.second <| List.foldl (consMsg index) (numMessages - 1, []) recent.messages + in + VDom.div [ VDom.class className ] (oldStuff :: newStuff) + + + +-- VIEW SNAPSHOTS + + +viewSnapshots : Int -> Array (Snapshot model msg) -> Node Int +viewSnapshots currentIndex snapshots = + let + highIndex = + maxSnapshotSize * Array.length snapshots + in + VDom.div [] <| Tuple.second <| + Array.foldr (consSnapshot currentIndex) (highIndex, []) snapshots + + +consSnapshot : Int -> Snapshot model msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consSnapshot currentIndex snapshot (index, rest) = + let + nextIndex = + index - maxSnapshotSize + + currentIndexHelp = + if nextIndex <= currentIndex && currentIndex < index then currentIndex else -1 + in + ( index - maxSnapshotSize + , VDom.lazy3 viewSnapshot currentIndexHelp index snapshot :: rest + ) + + +viewSnapshot : Int -> Int -> Snapshot model msg -> Node Int +viewSnapshot currentIndex index { messages } = + VDom.div [] <| Tuple.second <| + Array.foldl (consMsg currentIndex) (index - 1, []) messages + + + +-- VIEW MESSAGE + + +consMsg : Int -> msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consMsg currentIndex msg (index, rest) = + ( index - 1 + , VDom.lazy3 viewMessage currentIndex index msg :: rest + ) + + +viewMessage : Int -> Int -> msg -> Node Int +viewMessage currentIndex index msg = + let + className = + if currentIndex == index then + "messages-entry messages-entry-selected" + + else + "messages-entry" + + messageName = + Native.Debug.messageToString msg + in + VDom.div + [ VDom.class className + , VDom.on "click" (Decode.succeed index) + ] + [ VDom.span [VDom.class "messages-entry-content", VDom.attribute "title" messageName ] [ VDom.text messageName ] + , VDom.span [VDom.class "messages-entry-index"] [ VDom.text (toString index) ] + ] diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm new file mode 100644 index 0000000..74e7316 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm @@ -0,0 +1,326 @@ +module VirtualDom.Metadata exposing + ( Metadata + , check + , decode, decoder, encode + , Error, ProblemType, Problem(..) + ) + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Report as Report exposing (Report) + + + +-- METADATA + + +type alias Metadata = + { versions : Versions + , types : Types + } + + + +-- VERSIONS + + +type alias Versions = + { elm : String + } + + + +-- TYPES + + +type alias Types = + { message : String + , aliases : Dict String Alias + , unions : Dict String Union + } + + +type alias Alias = + { args : List String + , tipe : String + } + + +type alias Union = + { args : List String + , tags : Dict String (List String) + } + + + +-- PORTABILITY + + +isPortable : Metadata -> Maybe Error +isPortable {types} = + let + badAliases = + Dict.foldl collectBadAliases [] types.aliases + in + case Dict.foldl collectBadUnions badAliases types.unions of + [] -> + Nothing + + problems -> + Just (Error types.message problems) + + +type alias Error = + { message : String + , problems : List ProblemType + } + + +type alias ProblemType = + { name : String + , problems : List Problem + } + + +type Problem + = Function + | Decoder + | Task + | Process + | Socket + | Request + | Program + | VirtualDom + + +collectBadAliases : String -> Alias -> List ProblemType -> List ProblemType +collectBadAliases name {tipe} list = + case findProblems tipe of + [] -> + list + + problems -> + ProblemType name problems :: list + + +collectBadUnions : String -> Union -> List ProblemType -> List ProblemType +collectBadUnions name {tags} list = + case List.concatMap findProblems (List.concat (Dict.values tags)) of + [] -> + list + + problems -> + ProblemType name problems :: list + + +findProblems : String -> List Problem +findProblems tipe = + List.filterMap (hasProblem tipe) problemTable + + +hasProblem : String -> (Problem, String) -> Maybe Problem +hasProblem tipe (problem, token) = + if String.contains token tipe then Just problem else Nothing + + +problemTable : List (Problem, String) +problemTable = + [ ( Function, "->" ) + , ( Decoder, "Json.Decode.Decoder" ) + , ( Task, "Task.Task" ) + , ( Process, "Process.Id" ) + , ( Socket, "WebSocket.LowLevel.WebSocket" ) + , ( Request, "Http.Request" ) + , ( Program, "Platform.Program" ) + , ( VirtualDom, "VirtualDom.Node" ) + , ( VirtualDom, "VirtualDom.Attribute" ) + ] + + + +-- CHECK + + +check : Metadata -> Metadata -> Report +check old new = + if old.versions.elm /= new.versions.elm then + Report.VersionChanged old.versions.elm new.versions.elm + + else + checkTypes old.types new.types + + +checkTypes : Types -> Types -> Report +checkTypes old new = + if old.message /= new.message then + Report.MessageChanged old.message new.message + + else + [] + |> Dict.merge ignore checkAlias ignore old.aliases new.aliases + |> Dict.merge ignore checkUnion ignore old.unions new.unions + |> Report.SomethingChanged + + +ignore : String -> value -> a -> a +ignore key value report = + report + + + +-- CHECK ALIASES + + +checkAlias : String -> Alias -> Alias -> List Report.Change -> List Report.Change +checkAlias name old new changes = + if old.tipe == new.tipe && old.args == new.args then + changes + + else + Report.AliasChange name :: changes + + + +-- CHECK UNIONS + + +checkUnion : String -> Union -> Union -> List Report.Change -> List Report.Change +checkUnion name old new changes = + let + tagChanges = + Dict.merge removeTag checkTag addTag old.tags new.tags <| + Report.emptyTagChanges (old.args == new.args) + in + if Report.hasTagChanges tagChanges then + changes + + else + Report.UnionChange name tagChanges :: changes + + +removeTag : String -> a -> Report.TagChanges -> Report.TagChanges +removeTag tag _ changes = + { changes | removed = tag :: changes.removed } + + +addTag : String -> a -> Report.TagChanges -> Report.TagChanges +addTag tag _ changes = + { changes | added = tag :: changes.added } + + +checkTag : String -> a -> a -> Report.TagChanges -> Report.TagChanges +checkTag tag old new changes = + if old == new then + changes + + else + { changes | changed = tag :: changes.changed } + + + +-- JSON DECODE + + +decode : Encode.Value -> Result Error Metadata +decode value = + case Decode.decodeValue decoder value of + Err _ -> + Debug.crash "Compiler is generating bad metadata. Report this at ." + + Ok metadata -> + case isPortable metadata of + Nothing -> + Ok metadata + + Just error -> + Err error + + +decoder : Decode.Decoder Metadata +decoder = + Decode.map2 Metadata + (Decode.field "versions" decodeVersions) + (Decode.field "types" decodeTypes) + + +decodeVersions : Decode.Decoder Versions +decodeVersions = + Decode.map Versions + (Decode.field "elm" Decode.string) + + +decodeTypes : Decode.Decoder Types +decodeTypes = + Decode.map3 Types + (Decode.field "message" Decode.string) + (Decode.field "aliases" (Decode.dict decodeAlias)) + (Decode.field "unions" (Decode.dict decodeUnion)) + + +decodeUnion : Decode.Decoder Union +decodeUnion = + Decode.map2 Union + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "tags" (Decode.dict (Decode.list Decode.string))) + + +decodeAlias : Decode.Decoder Alias +decodeAlias = + Decode.map2 Alias + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "type" (Decode.string)) + + + +-- JSON ENCODE + + +encode : Metadata -> Encode.Value +encode { versions, types } = + Encode.object + [ ("versions", encodeVersions versions) + , ("types", encodeTypes types) + ] + + +encodeVersions : Versions -> Encode.Value +encodeVersions { elm } = + Encode.object [("elm", Encode.string elm)] + + +encodeTypes : Types -> Encode.Value +encodeTypes { message, unions, aliases } = + Encode.object + [ ("message", Encode.string message) + , ("aliases", encodeDict encodeAlias aliases) + , ("unions", encodeDict encodeUnion unions) + ] + + +encodeAlias : Alias -> Encode.Value +encodeAlias { args, tipe } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("type", Encode.string tipe) + ] + + +encodeUnion : Union -> Encode.Value +encodeUnion { args, tags } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("tags", encodeDict (Encode.list << List.map Encode.string) tags) + ] + + +encodeDict : (a -> Encode.Value) -> Dict String a -> Encode.Value +encodeDict f dict = + dict + |> Dict.map (\key value -> f value) + |> Dict.toList + |> Encode.object + + diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm new file mode 100644 index 0000000..9e6bd2e --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm @@ -0,0 +1,541 @@ +module VirtualDom.Overlay exposing + ( State, none, corruptImport, badMetadata + , Msg, close, assessImport + , isBlocking + , Config + , Block + , view + , viewImportExport + ) + +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Helpers exposing (..) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Report as Report exposing (Report) + + + +type State + = None + | BadMetadata Metadata.Error + | BadImport Report + | RiskyImport Report Encode.Value + + +none : State +none = + None + + +corruptImport : State +corruptImport = + BadImport Report.CorruptHistory + + +badMetadata : Metadata.Error -> State +badMetadata = + BadMetadata + + +isBlocking : State -> Bool +isBlocking state = + case state of + None -> + False + + _ -> + True + + + +-- UPDATE + + +type Msg = Cancel | Proceed + + +close : Msg -> State -> Maybe Encode.Value +close msg state = + case state of + None -> + Nothing + + BadMetadata _ -> + Nothing + + BadImport _ -> + Nothing + + RiskyImport _ rawHistory -> + case msg of + Cancel -> + Nothing + + Proceed -> + Just rawHistory + + +assessImport : Metadata -> String -> Result State Encode.Value +assessImport metadata jsonString = + case Decode.decodeString uploadDecoder jsonString of + Err _ -> + Err corruptImport + + Ok (foreignMetadata, rawHistory) -> + let + report = + Metadata.check foreignMetadata metadata + in + case Report.evaluate report of + Report.Impossible -> + Err (BadImport report) + + Report.Risky -> + Err (RiskyImport report rawHistory) + + Report.Fine -> + Ok rawHistory + + +uploadDecoder : Decode.Decoder (Metadata, Encode.Value) +uploadDecoder = + Decode.map2 (,) + (Decode.field "metadata" Metadata.decoder) + (Decode.field "history" Decode.value) + + + +-- VIEW + + +type alias Config msg = + { resume : msg + , open : msg + , importHistory : msg + , exportHistory : msg + , wrap : Msg -> msg + } + + +type Block = Normal | Pause | Message + + +view : Config msg -> Bool -> Bool -> Int -> State -> ( Block, Node msg ) +view config isPaused isOpen numMsgs state = + let + (block, nodes) = + viewHelp config isPaused isOpen numMsgs state + in + ( block + , div [ class "elm-overlay" ] (styles :: nodes) + ) + + +viewHelp : Config msg -> Bool -> Bool -> Int -> State -> ( Block, List (Node msg) ) +viewHelp config isPaused isOpen numMsgs state = + case state of + None -> + let + miniControls = + if isOpen then [] else [ viewMiniControls config numMsgs ] + in + ( if isPaused then Pause else Normal + , if isPaused && not isOpen then + viewResume config :: miniControls + else + miniControls + ) + + BadMetadata badMetadata -> + viewMessage config + "Cannot use Import or Export" + (viewBadMetadata badMetadata) + (Accept "Ok") + + BadImport report -> + viewMessage config + "Cannot Import History" + (viewReport True report) + (Accept "Ok") + + RiskyImport report _ -> + viewMessage config + "Warning" + (viewReport False report) + (Choose "Cancel" "Import Anyway") + + +viewResume config = + div [ class "elm-overlay-resume", onClick config.resume ] + [ div [class "elm-overlay-resume-words"] [text "Click to Resume"] ] + + + +-- VIEW MESSAGE + + +viewMessage : Config msg -> String -> List (Node msg) -> Buttons -> ( Block, List (Node msg) ) +viewMessage config title details buttons = + ( Message + , [ div [ class "elm-overlay-message" ] + [ div [ class "elm-overlay-message-title" ] [ text title ] + , div [ class "elm-overlay-message-details" ] details + , map config.wrap (viewButtons buttons) + ] + ] + ) + + +viewReport : Bool -> Report -> List (Node msg) +viewReport isBad report = + case report of + Report.CorruptHistory -> + [ text "Looks like this history file is corrupt. I cannot understand it." + ] + + Report.VersionChanged old new -> + [ text <| + "This history was created with Elm " + ++ old ++ ", but you are using Elm " + ++ new ++ " right now." + ] + + Report.MessageChanged old new -> + [ text <| + "To import some other history, the overall message type must" + ++ " be the same. The old history has " + , viewCode old + , text " messages, but the new program works with " + , viewCode new + , text " messages." + ] + + Report.SomethingChanged changes -> + [ node "p" [] [ text (if isBad then explanationBad else explanationRisky) ] + , node "ul" [] (List.map viewChange changes) + ] + + +explanationBad : String +explanationBad = """ +The messages in this history do not match the messages handled by your +program. I noticed changes in the following types: +""" + +explanationRisky : String +explanationRisky = """ +This history seems old. It will work with this program, but some +messages have been added since the history was created: +""" + + +viewCode : String -> Node msg +viewCode name = + node "code" [] [ text name ] + + +viewChange : Report.Change -> Node msg +viewChange change = + node "li" [] <| + case change of + Report.AliasChange name -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + ] + + Report.UnionChange name { removed, changed, added, argsMatch } -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + , node "ul" [] + [ viewMention removed "Removed " + , viewMention changed "Changed " + , viewMention added "Added " + ] + , if argsMatch then + text "" + else + text "This may be due to the fact that the type variable names changed." + ] + + +viewMention : List String -> String -> Node msg +viewMention tags verbed = + case List.map viewCode (List.reverse tags) of + [] -> + text "" + + [tag] -> + node "li" [] + [ text verbed, tag, text "." ] + + [tag2, tag1] -> + node "li" [] + [ text verbed, tag1, text " and ", tag2, text "." ] + + lastTag :: otherTags -> + node "li" [] <| + text verbed + :: List.intersperse (text ", ") (List.reverse otherTags) + ++ [ text ", and ", lastTag, text "." ] + + +viewBadMetadata : Metadata.Error -> List (Node msg) +viewBadMetadata {message, problems} = + [ node "p" [] + [ text "The " + , viewCode message + , text " type of your program cannot be reliably serialized for history files." + ] + , node "p" [] [ text "Functions cannot be serialized, nor can values that contain functions. This is a problem in these places:" ] + , node "ul" [] (List.map viewProblemType problems) + , node "p" [] + [ text goodNews1 + , a [ href "https://guide.elm-lang.org/types/union_types.html" ] [ text "union types" ] + , text ", in your messages. From there, your " + , viewCode "update" + , text goodNews2 + ] + ] + + +goodNews1 = """ +The good news is that having values like this in your message type is not +so great in the long run. You are better off using simpler data, like +""" + + +goodNews2 = """ +function can pattern match on that data and call whatever functions, JSON +decoders, etc. you need. This makes the code much more explicit and easy to +follow for other readers (or you in a few months!) +""" + + +viewProblemType : Metadata.ProblemType -> Node msg +viewProblemType { name, problems } = + node "li" [] + [ viewCode name + , text (" can contain " ++ addCommas (List.map problemToString problems) ++ ".") + ] + + +problemToString : Metadata.Problem -> String +problemToString problem = + case problem of + Metadata.Function -> + "functions" + + Metadata.Decoder -> + "JSON decoders" + + Metadata.Task -> + "tasks" + + Metadata.Process -> + "processes" + + Metadata.Socket -> + "web sockets" + + Metadata.Request -> + "HTTP requests" + + Metadata.Program -> + "programs" + + Metadata.VirtualDom -> + "virtual DOM values" + + +addCommas : List String -> String +addCommas items = + case items of + [] -> + "" + + [item] -> + item + + [item1, item2] -> + item1 ++ " and " ++ item2 + + lastItem :: otherItems -> + String.join ", " (otherItems ++ [ " and " ++ lastItem ]) + + + +-- VIEW MESSAGE BUTTONS + + +type Buttons + = Accept String + | Choose String String + + +viewButtons : Buttons -> Node Msg +viewButtons buttons = + div [ class "elm-overlay-message-buttons" ] <| + case buttons of + Accept proceed -> + [ node "button" [ onClick Proceed ] [ text proceed ] + ] + + Choose cancel proceed -> + [ node "button" [ onClick Cancel ] [ text cancel ] + , node "button" [ onClick Proceed ] [ text proceed ] + ] + + + +-- VIEW MINI CONTROLS + + +viewMiniControls : Config msg -> Int -> Node msg +viewMiniControls config numMsgs = + div + [ class "elm-mini-controls" + ] + [ div + [ onClick config.open + , class "elm-mini-controls-button" + ] + [ text ("Explore History (" ++ toString numMsgs ++ ")") + ] + , viewImportExport + [class "elm-mini-controls-import-export"] + config.importHistory + config.exportHistory + ] + + +viewImportExport : List (Property msg) -> msg -> msg -> Node msg +viewImportExport props importMsg exportMsg = + div + props + [ button importMsg "Import" + , text " / " + , button exportMsg "Export" + ] + + +button : msg -> String -> Node msg +button msg label = + span [ onClick msg, style [("cursor","pointer")] ] [ text label ] + + + +-- STYLE + + +styles : Node msg +styles = + node "style" [] [ text """ + +.elm-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + color: white; + pointer-events: none; + font-family: 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif; +} + +.elm-overlay-resume { + width: 100%; + height: 100%; + cursor: pointer; + text-align: center; + pointer-events: auto; + background-color: rgba(200, 200, 200, 0.7); +} + +.elm-overlay-resume-words { + position: absolute; + top: calc(50% - 40px); + font-size: 80px; + line-height: 80px; + height: 80px; + width: 100%; +} + +.elm-mini-controls { + position: fixed; + bottom: 0; + right: 6px; + border-radius: 4px; + background-color: rgb(61, 61, 61); + font-family: monospace; + pointer-events: auto; +} + +.elm-mini-controls-button { + padding: 6px; + cursor: pointer; + text-align: center; + min-width: 24ch; +} + +.elm-mini-controls-import-export { + padding: 4px 0; + font-size: 0.8em; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message { + position: absolute; + width: 600px; + height: 100%; + padding-left: calc(50% - 300px); + padding-right: calc(50% - 300px); + background-color: rgba(200, 200, 200, 0.7); + pointer-events: auto; +} + +.elm-overlay-message-title { + font-size: 36px; + height: 80px; + background-color: rgb(50, 50, 50); + padding-left: 22px; + vertical-align: middle; + line-height: 80px; +} + +.elm-overlay-message-details { + padding: 8px 20px; + overflow-y: auto; + max-height: calc(100% - 156px); + background-color: rgb(61, 61, 61); +} + +.elm-overlay-message-details-type { + font-size: 1.5em; +} + +.elm-overlay-message-details ul { + list-style-type: none; + padding-left: 20px; +} + +.elm-overlay-message-details ul ul { + list-style-type: disc; + padding-left: 2em; +} + +.elm-overlay-message-details li { + margin: 8px 0; +} + +.elm-overlay-message-buttons { + height: 60px; + line-height: 60px; + text-align: right; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message-buttons button { + margin-right: 20px; +} + +""" ] \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm new file mode 100644 index 0000000..89b4e07 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm @@ -0,0 +1,99 @@ +module VirtualDom.Report exposing + ( Report(..) + , Change(..) + , TagChanges + , emptyTagChanges + , hasTagChanges + , Status(..), evaluate + ) + + + +-- REPORTS + + +type Report + = CorruptHistory + | VersionChanged String String + | MessageChanged String String + | SomethingChanged (List Change) + + +type Change + = AliasChange String + | UnionChange String TagChanges + + +type alias TagChanges = + { removed : List String + , changed : List String + , added : List String + , argsMatch : Bool + } + + +emptyTagChanges : Bool -> TagChanges +emptyTagChanges argsMatch = + TagChanges [] [] [] argsMatch + + +hasTagChanges : TagChanges -> Bool +hasTagChanges tagChanges = + tagChanges == TagChanges [] [] [] True + + +type Status = Impossible | Risky | Fine + + +evaluate : Report -> Status +evaluate report = + case report of + CorruptHistory -> + Impossible + + VersionChanged _ _ -> + Impossible + + MessageChanged _ _ -> + Impossible + + SomethingChanged changes -> + worstCase Fine (List.map evaluateChange changes) + + +worstCase : Status -> List Status -> Status +worstCase status statusList = + case statusList of + [] -> + status + + Impossible :: _ -> + Impossible + + Risky :: rest -> + worstCase Risky rest + + Fine :: rest -> + worstCase status rest + + +evaluateChange : Change -> Status +evaluateChange change = + case change of + AliasChange _ -> + Impossible + + UnionChange _ { removed, changed, added, argsMatch } -> + if not argsMatch || some changed || some removed then + Impossible + + else if some added then + Risky + + else + Fine + + +some : List a -> Bool +some list = + not (List.isEmpty list) diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js new file mode 100644 index 0000000..6b1ebbb --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js @@ -0,0 +1,35 @@ +Elm.Native.TestHelpers = {}; +Elm.Native.TestHelpers.make = function(localRuntime) +{ + localRuntime.Native = localRuntime.Native || {}; + localRuntime.Native.TestHelpers = localRuntime.Native.TestHelpers || {}; + if (localRuntime.Native.TestHelpers.values) + { + return localRuntime.Native.TestHelpers.values; + } + + var VirtualDom = Elm.Native.VirtualDom.make(localRuntime); + + function unsafeRecordCallCount(f) { + function wrapper(a) { + wrapper.__elm_test_call_count += 1; + return f(a); + } + wrapper.__elm_test_call_count = 0; + return wrapper; + } + + function unsafeQueryCallCount(f) { + if (f.__elm_test_call_count === undefined) { + return -1; + } + return f.__elm_test_call_count; + } + + Elm.Native.TestHelpers.values = { + unsafeRecordCallCount: unsafeRecordCallCount, + unsafeQueryCallCount: unsafeQueryCallCount, + updateAndReplace: F3(VirtualDom.updateAndReplace) + }; + return localRuntime.Native.TestHelpers.values = Elm.Native.TestHelpers.values; +}; \ No newline at end of file diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm new file mode 100644 index 0000000..09e362a --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm @@ -0,0 +1,72 @@ +module TestCases.Lazy where + +import VirtualDom exposing (Node, lazy) +import ElmTest.Assertion exposing (assertEqual) +import ElmTest.Test exposing (Test, suite, test) + +import TestHelpers exposing (renderDom, updateDom, unsafeRecordCallCount, unsafeQueryCallCount) + +renderRecord : { x: String, y: String } -> Node +renderRecord r = + VirtualDom.text <| "The values: " ++ r.x ++ ", " ++ r.y + + +renderPrimitive : Int -> Node +renderPrimitive x = + VirtualDom.text <| "The value: " ++ (toString x) + + +testLazyIdenticalRecord = + test "isn't called again with identical record" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender record + v3 = updateDom v2 <| lazy wrappedRender record + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyIdenticalPrimitive = + test "isn't called again with identical primitive" <| + let wrappedRender = unsafeRecordCallCount renderPrimitive + v1 = renderDom <| lazy wrappedRender 5 + v2 = updateDom v1 <| lazy wrappedRender 5 + v3 = updateDom v2 <| lazy wrappedRender 5 + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyRecordMutationOfIdenticalValue = + test "isn't called again with record mutation of identical value" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender { record | x = "a" } + v3 = updateDom v2 <| lazy wrappedRender { record | x = "a", y = "b" } + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testNotLazyDifferentRecord = + test "is called again with an equivalent but different record" <| + let wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender { x = "a", y = "b" } + v2 = updateDom v1 <| lazy wrappedRender { x = "a", y = "b" } + v3 = updateDom v2 <| lazy wrappedRender { x = "a", y = "b" } + in + assertEqual 3 <| unsafeQueryCallCount wrappedRender + + +tests : Test +tests = + suite + "Lazy" + [ + testLazyIdenticalRecord, + testLazyIdenticalPrimitive, + -- Re-enable this test when core supports checking + -- record update values for identity before copying: + -- testLazyRecordMutationOfIdenticalValue, + testNotLazyDifferentRecord + ] diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm new file mode 100644 index 0000000..2fe24cf --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm @@ -0,0 +1,34 @@ +module TestHelpers where + +import VirtualDom exposing (Node) + +import Native.TestHelpers +import Native.VirtualDom + +unsafeRecordCallCount : (a -> b) -> (a -> b) +unsafeRecordCallCount = + Native.TestHelpers.unsafeRecordCallCount + +unsafeQueryCallCount : (a -> b) -> Int +unsafeQueryCallCount = + Native.TestHelpers.unsafeQueryCallCount + +type OpaqueDom = OpaqueDom + +render : Node -> OpaqueDom +render = + Native.VirtualDom.render + +updateAndReplace : OpaqueDom -> Node -> Node -> OpaqueDom +updateAndReplace = + Native.TestHelpers.updateAndReplace + + +renderDom : Node -> (OpaqueDom, Node) +renderDom vdom = + (render vdom, vdom) + + +updateDom : (OpaqueDom, Node) -> Node -> (OpaqueDom, Node) +updateDom (oldDom, oldVDom) newVDom = + (updateAndReplace oldDom oldVDom newVDom, newVDom) diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm new file mode 100644 index 0000000..ea59abf --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm @@ -0,0 +1,18 @@ + +import ElmTest.Runner.Console exposing (runDisplay) +import ElmTest.Test exposing (Test, suite) +import Console exposing (IO) +import Task exposing (Task) + +import TestCases.Lazy + +tests : Test +tests = + suite + "VirtualDom Library Tests" + [ + TestCases.Lazy.tests + ] + +port runner : Signal (Task x ()) +port runner = Console.run (runDisplay tests) diff --git a/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json new file mode 100644 index 0000000..5041954 --- /dev/null +++ b/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "Test for VirtualDom", + "license": "BSD3", + "repository": "https://github.com/evancz/virtual-dom.git", + "exposed-modules": [], + "source-directories": [ + ".", + "build/virtual-dom/" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "2.0.0 <= v < 4.0.0", + "laszlopandy/elm-console": "1.0.0 <= v < 2.0.0", + "deadfoxygrandpa/elm-test": "1.0.3 <= v < 2.0.0" + }, + "elm-version": "0.16.0 <= v < 0.17.0" +} \ No newline at end of file diff --git a/part1/elm-stuff/.gitignore b/part1/elm-stuff/.gitignore new file mode 100644 index 0000000..f6cea5e --- /dev/null +++ b/part1/elm-stuff/.gitignore @@ -0,0 +1,5 @@ +build-artifacts +*.md +*.yml +.eslintrc +*.sh diff --git a/part1/elm-stuff/exact-dependencies.json b/part1/elm-stuff/exact-dependencies.json new file mode 100644 index 0000000..f74308c --- /dev/null +++ b/part1/elm-stuff/exact-dependencies.json @@ -0,0 +1,5 @@ +{ + "elm-lang/virtual-dom": "2.0.4", + "elm-lang/html": "2.0.0", + "elm-lang/core": "5.1.1" +} \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore b/part1/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore new file mode 100644 index 0000000..7f3cfe4 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore @@ -0,0 +1,3 @@ +elm-stuff +tests/test.js +node_modules/ \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE b/part1/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json b/part1/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json new file mode 100644 index 0000000..2f25729 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json @@ -0,0 +1,38 @@ +{ + "version": "5.1.1", + "summary": "Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Array", + "Basics", + "Bitwise", + "Char", + "Color", + "Date", + "Debug", + "Dict", + "Json.Decode", + "Json.Encode", + "List", + "Maybe", + "Platform", + "Platform.Cmd", + "Platform.Sub", + "Process", + "Random", + "Regex", + "Result", + "Set", + "String", + "Task", + "Time", + "Tuple" + ], + "native-modules": true, + "dependencies": {}, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm new file mode 100644 index 0000000..58ae2ba --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm @@ -0,0 +1,240 @@ +module Array exposing + ( Array + , empty, repeat, initialize, fromList + , isEmpty, length, push, append + , get, set + , slice, toList, toIndexedList + , map, indexedMap, filter, foldl, foldr + ) + +{-| A library for fast immutable arrays. The elements in an array must have the +same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast +reads, updates, and appends. + +# Arrays +@docs Array + +# Creating Arrays +@docs empty, repeat, initialize, fromList + +# Basics +@docs isEmpty, length, push, append + +# Get and Set +@docs get, set + +# Taking Arrays Apart +@docs slice, toList, toIndexedList + +# Mapping, Filtering, and Folding +@docs map, indexedMap, filter, foldl, foldr +-} + +import Native.Array +import Basics exposing (..) +import Maybe exposing (..) +import List + + +{-| Representation of fast immutable arrays. You can create arrays of integers +(`Array Int`) or strings (`Array String`) or any other type of value you can +dream up. +-} +type Array a = Array + + +{-| Initialize an array. `initialize n f` creates an array of length `n` with +the element at index `i` initialized to the result of `(f i)`. + + initialize 4 identity == fromList [0,1,2,3] + initialize 4 (\n -> n*n) == fromList [0,1,4,9] + initialize 4 (always 0) == fromList [0,0,0,0] +-} +initialize : Int -> (Int -> a) -> Array a +initialize = + Native.Array.initialize + + +{-| Creates an array with a given length, filled with a default element. + + repeat 5 0 == fromList [0,0,0,0,0] + repeat 3 "cat" == fromList ["cat","cat","cat"] + +Notice that `repeat 3 x` is the same as `initialize 3 (always x)`. +-} +repeat : Int -> a -> Array a +repeat n e = + initialize n (always e) + + +{-| Create an array from a list. +-} +fromList : List a -> Array a +fromList = + Native.Array.fromList + + +{-| Create a list of elements from an array. + + toList (fromList [3,5,8]) == [3,5,8] +-} +toList : Array a -> List a +toList = + Native.Array.toList + + +-- TODO: make this a native function. +{-| Create an indexed list from an array. Each element of the array will be +paired with its index. + + toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")] +-} +toIndexedList : Array a -> List (Int, a) +toIndexedList array = + List.map2 + (,) + (List.range 0 (Native.Array.length array - 1)) + (Native.Array.toList array) + + +{-| Apply a function on every element in an array. + + map sqrt (fromList [1,4,9]) == fromList [1,2,3] +-} +map : (a -> b) -> Array a -> Array b +map = + Native.Array.map + + +{-| Apply a function on every element with its index as first argument. + + indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10] +-} +indexedMap : (Int -> a -> b) -> Array a -> Array b +indexedMap = + Native.Array.indexedMap + + +{-| Reduce an array from the left. Read `foldl` as “fold from the left”. + + foldl (::) [] (fromList [1,2,3]) == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> Array a -> b +foldl = + Native.Array.foldl + + +{-| Reduce an array from the right. Read `foldr` as “fold from the right”. + + foldr (+) 0 (repeat 3 5) == 15 +-} +foldr : (a -> b -> b) -> b -> Array a -> b +foldr = + Native.Array.foldr + + +{-| Keep only elements that satisfy the predicate: + + filter isEven (fromList [1,2,3,4,5,6]) == (fromList [2,4,6]) +-} +filter : (a -> Bool) -> Array a -> Array a +filter isOkay arr = + let + update x xs = + if isOkay x then + Native.Array.push x xs + else + xs + in + Native.Array.foldl update Native.Array.empty arr + +{-| Return an empty array. + + length empty == 0 +-} +empty : Array a +empty = + Native.Array.empty + + +{-| Push an element to the end of an array. + + push 3 (fromList [1,2]) == fromList [1,2,3] +-} +push : a -> Array a -> Array a +push = + Native.Array.push + + +{-| Return Just the element at the index or Nothing if the index is out of range. + + get 0 (fromList [0,5,3]) == Just 0 + get 2 (fromList [0,5,3]) == Just 3 + get 5 (fromList [0,5,3]) == Nothing + get -1 (fromList [0,5,3]) == Nothing + +-} +get : Int -> Array a -> Maybe a +get i array = + if 0 <= i && i < Native.Array.length array then + Just (Native.Array.get i array) + else + Nothing + + +{-| Set the element at a particular index. Returns an updated array. +If the index is out of range, the array is unaltered. + + set 1 7 (fromList [1,2,3]) == fromList [1,7,3] +-} +set : Int -> a -> Array a -> Array a +set = + Native.Array.set + + +{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a +zero-based index where we will start our slice. The `end` is a zero-based index +that indicates the end of the slice. The slice extracts up to but not including +`end`. + + slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2] + slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3] + +Both the `start` and `end` indexes can be negative, indicating an offset from +the end of the array. + + slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3] + slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4] + +This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array` +-} +slice : Int -> Int -> Array a -> Array a +slice = + Native.Array.slice + + +{-| Return the length of an array. + + length (fromList [1,2,3]) == 3 +-} +length : Array a -> Int +length = + Native.Array.length + + +{-| Determine if an array is empty. + + isEmpty empty == True +-} +isEmpty : Array a -> Bool +isEmpty array = + length array == 0 + + +{-| Append two arrays to a new one. + + append (repeat 2 42) (repeat 3 81) == fromList [42,42,81,81,81] +-} +append : Array a -> Array a -> Array a +append = + Native.Array.append diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm new file mode 100644 index 0000000..2d06c86 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm @@ -0,0 +1,650 @@ +module Basics exposing + ( (==), (/=) + , (<), (>), (<=), (>=), max, min, Order (..), compare + , not, (&&), (||), xor + , (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + , pi, cos, sin, tan, acos, asin, atan, atan2 + , round, floor, ceiling, truncate, toFloat + , degrees, radians, turns + , toPolar, fromPolar + , isNaN, isInfinite + , toString, (++) + , identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + ) + +{-| Tons of useful functions that get imported by default. + +# Equality +@docs (==), (/=) + +# Comparison + +These functions only work on `comparable` types. This includes numbers, +characters, strings, lists of comparable things, and tuples of comparable +things. Note that tuples with 7 or more elements are not comparable; why +are your tuples so big? + +@docs (<), (>), (<=), (>=), max, min, Order, compare + +# Booleans +@docs not, (&&), (||), xor + +# Mathematics +@docs (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + +# Trigonometry +@docs pi, cos, sin, tan, acos, asin, atan, atan2 + +# Number Conversions +@docs round, floor, ceiling, truncate, toFloat + +# Angle Conversions +All angle conversions result in “standard Elm angles” +which happen to be radians. + +@docs degrees, radians, turns + +# Polar Coordinates +@docs toPolar, fromPolar + +# Floating Point Checks +@docs isNaN, isInfinite + +# Strings and Lists +@docs toString, (++) + +# Higher-Order Helpers +@docs identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + +-} + +import Native.Basics +import Native.Utils + + +{-| Convert radians to standard Elm angles (radians). -} +radians : Float -> Float +radians t = + t + + +{-| Convert degrees to standard Elm angles (radians). -} +degrees : Float -> Float +degrees = + Native.Basics.degrees + + +{-| Convert turns to standard Elm angles (radians). +One turn is equal to 360°. +-} +turns : Float -> Float +turns = + Native.Basics.turns + + +{-| Convert polar coordinates (r,θ) to Cartesian coordinates (x,y). -} +fromPolar : (Float,Float) -> (Float,Float) +fromPolar = + Native.Basics.fromPolar + + +{-| Convert Cartesian coordinates (x,y) to polar coordinates (r,θ). -} +toPolar : (Float,Float) -> (Float,Float) +toPolar = + Native.Basics.toPolar + + +{-|-} +(+) : number -> number -> number +(+) = + Native.Basics.add + + +{-|-} +(-) : number -> number -> number +(-) = + Native.Basics.sub + + +{-|-} +(*) : number -> number -> number +(*) = + Native.Basics.mul + + +{-| Floating point division. -} +(/) : Float -> Float -> Float +(/) = + Native.Basics.floatDiv + + +infixl 6 + +infixl 6 - +infixl 7 * +infixl 7 / +infixr 8 ^ + +infixl 7 // +infixl 7 % + + +{-| Integer division. The remainder is discarded. -} +(//) : Int -> Int -> Int +(//) = + Native.Basics.div + + +{-| Find the remainder after dividing one number by another. + + rem 11 4 == 3 + rem 12 4 == 0 + rem 13 4 == 1 + rem -1 4 == -1 +-} +rem : Int -> Int -> Int +rem = + Native.Basics.rem + + +{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic). + + 7 % 2 == 1 + -1 % 4 == 3 +-} +(%) : Int -> Int -> Int +(%) = + Native.Basics.mod + + +{-| Exponentiation + + 3^2 == 9 +-} +(^) : number -> number -> number +(^) = + Native.Basics.exp + + +{-|-} +cos : Float -> Float +cos = + Native.Basics.cos + + +{-|-} +sin : Float -> Float +sin = + Native.Basics.sin + + +{-|-} +tan : Float -> Float +tan = + Native.Basics.tan + + +{-|-} +acos : Float -> Float +acos = + Native.Basics.acos + + +{-|-} +asin : Float -> Float +asin = + Native.Basics.asin + + +{-| You probably do not want to use this. It takes `(y/x)` as the +argument, so there is no way to know whether the negative signs comes from +the `y` or `x`. Thus, the resulting angle is always between π/2 and -π/2 +(in quadrants I and IV). You probably want to use `atan2` instead. +-} +atan : Float -> Float +atan = + Native.Basics.atan + + +{-| This helps you find the angle of a Cartesian coordinate. +You will almost certainly want to use this instead of `atan`. +So `atan2 y x` computes *atan(y/x)* but also keeps track of which +quadrant the angle should really be in. The result will be between +π and -π, giving you the full range of angles. +-} +atan2 : Float -> Float -> Float +atan2 = + Native.Basics.atan2 + + +{-| Take the square root of a number. -} +sqrt : Float -> Float +sqrt = + Native.Basics.sqrt + + +{-| Negate a number. + + negate 42 == -42 + negate -42 == 42 + negate 0 == 0 +-} +negate : number -> number +negate = + Native.Basics.negate + + +{-| Take the absolute value of a number. -} +abs : number -> number +abs = + Native.Basics.abs + + +{-| Calculate the logarithm of a number with a given base. + + logBase 10 100 == 2 + logBase 2 256 == 8 +-} +logBase : Float -> Float -> Float +logBase = + Native.Basics.logBase + + +{-| Clamps a number within a given range. With the expression +`clamp 100 200 x` the results are as follows: + + 100 if x < 100 + x if 100 <= x < 200 + 200 if 200 <= x +-} +clamp : number -> number -> number -> number +clamp = + Native.Basics.clamp + + +{-| An approximation of pi. -} +pi : Float +pi = + Native.Basics.pi + + +{-| An approximation of e. -} +e : Float +e = + Native.Basics.e + + +{-| Check if values are “the same”. + +**Note:** Elm uses structural equality on tuples, records, and user-defined +union types. This means the values `(3, 4)` and `(3, 4)` are definitely equal. +This is not true in languages like JavaScript that use reference equality on +objects. + +**Note:** Equality (in the Elm sense) is not possible for certain types. For +example, the functions `(\n -> n + 1)` and `(\n -> 1 + n)` are “the +same” but detecting this in general is [undecidable][]. In a future +release, the compiler will detect when `(==)` is used with problematic +types and provide a helpful error message. This will require quite serious +infrastructure work that makes sense to batch with another big project, so the +stopgap is to crash as quickly as possible. Problematic types include functions +and JavaScript values like `Json.Encode.Value` which could contain functions +if passed through a port. + +[undecidable]: https://en.wikipedia.org/wiki/Undecidable_problem +-} +(==) : a -> a -> Bool +(==) = + Native.Basics.eq + + +{-| Check if values are not “the same”. + +So `(a /= b)` is the same as `(not (a == b))`. +-} +(/=) : a -> a -> Bool +(/=) = + Native.Basics.neq + + +{-|-} +(<) : comparable -> comparable -> Bool +(<) = + Native.Basics.lt + + +{-|-} +(>) : comparable -> comparable -> Bool +(>) = + Native.Basics.gt + + +{-|-} +(<=) : comparable -> comparable -> Bool +(<=) = + Native.Basics.le + + +{-|-} +(>=) : comparable -> comparable -> Bool +(>=) = + Native.Basics.ge + + +infix 4 == +infix 4 /= +infix 4 < +infix 4 > +infix 4 <= +infix 4 >= + + +{-| Compare any two comparable values. Comparable values include `String`, `Char`, +`Int`, `Float`, `Time`, or a list or tuple containing comparable values. +These are also the only values that work as `Dict` keys or `Set` members. +-} +compare : comparable -> comparable -> Order +compare = + Native.Basics.compare + + +{-| Represents the relative ordering of two things. +The relations are less than, equal to, and greater than. +-} +type Order = LT | EQ | GT + + +{-| Find the smaller of two comparables. -} +min : comparable -> comparable -> comparable +min = + Native.Basics.min + + +{-| Find the larger of two comparables. -} +max : comparable -> comparable -> comparable +max = + Native.Basics.max + + +{-| The logical AND operator. `True` if both inputs are `True`. + +**Note:** When used in the infix position, like `(left && right)`, the operator +short-circuits. This means if `left` is `False` we do not bother evaluating `right` +and just return `False` overall. +-} +(&&) : Bool -> Bool -> Bool +(&&) = + Native.Basics.and + + +{-| The logical OR operator. `True` if one or both inputs are `True`. + +**Note:** When used in the infix position, like `(left || right)`, the operator +short-circuits. This means if `left` is `True` we do not bother evaluating `right` +and just return `True` overall. +-} +(||) : Bool -> Bool -> Bool +(||) = + Native.Basics.or + + +infixr 3 && +infixr 2 || + + +{-| The exclusive-or operator. `True` if exactly one input is `True`. -} +xor : Bool -> Bool -> Bool +xor = + Native.Basics.xor + + +{-| Negate a boolean value. + + not True == False + not False == True +-} +not : Bool -> Bool +not = + Native.Basics.not + + +-- Conversions + +{-| Round a number to the nearest integer. -} +round : Float -> Int +round = + Native.Basics.round + + +{-| Truncate a number, rounding towards zero. -} +truncate : Float -> Int +truncate = + Native.Basics.truncate + + +{-| Floor function, rounding down. -} +floor : Float -> Int +floor = + Native.Basics.floor + + +{-| Ceiling function, rounding up. -} +ceiling : Float -> Int +ceiling = + Native.Basics.ceiling + + +{-| Convert an integer into a float. -} +toFloat : Int -> Float +toFloat = + Native.Basics.toFloat + + +{-| Determine whether a float is an undefined or unrepresentable number. +NaN stands for *not a number* and it is [a standardized part of floating point +numbers](http://en.wikipedia.org/wiki/NaN). + + isNaN (0/0) == True + isNaN (sqrt -1) == True + isNaN (1/0) == False -- infinity is a number + isNaN 1 == False +-} +isNaN : Float -> Bool +isNaN = + Native.Basics.isNaN + + +{-| Determine whether a float is positive or negative infinity. + + isInfinite (0/0) == False + isInfinite (sqrt -1) == False + isInfinite (1/0) == True + isInfinite 1 == False + +Notice that NaN is not infinite! For float `n` to be finite implies that +`not (isInfinite n || isNaN n)` evaluates to `True`. +-} +isInfinite : Float -> Bool +isInfinite = + Native.Basics.isInfinite + + +{-| Turn any kind of value into a string. When you view the resulting string +with `Text.fromString` it should look just like the value it came from. + + toString 42 == "42" + toString [1,2] == "[1,2]" + toString "he said, \"hi\"" == "\"he said, \\\"hi\\\"\"" +-} +toString : a -> String +toString = + Native.Utils.toString + + +{-| Put two appendable things together. This includes strings, lists, and text. + + "hello" ++ "world" == "helloworld" + [1,1,2] ++ [3,5,8] == [1,1,2,3,5,8] +-} +(++) : appendable -> appendable -> appendable +(++) = + Native.Utils.append + + +infixr 5 ++ + + +-- Function Helpers + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + not << isEven << sqrt + +You can think of this operator as equivalent to the following: + + (g << f) == (\x -> g (f x)) + +So our example expands out to something like this: + + \n -> not (isEven (sqrt n)) +-} +(<<) : (b -> c) -> (a -> b) -> (a -> c) +(<<) g f x = + g (f x) + + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + sqrt >> isEven >> not + +This direction of function composition seems less pleasant than `(<<)` which +reads nicely in expressions like: `filter (not << isRegistered) students` +-} +(>>) : (a -> b) -> (b -> c) -> (a -> c) +(>>) f g x = + g (f x) + + +{-| Forward function application `x |> f == f x`. This function is useful +for avoiding parentheses and writing code in a more natural way. +Consider the following code to create a pentagon: + + scale 2 (move (10,10) (filled blue (ngon 5 30))) + +This can also be written as: + + ngon 5 30 + |> filled blue + |> move (10,10) + |> scale 2 +-} +(|>) : a -> (a -> b) -> b +(|>) x f = + f x + + +{-| Backward function application `f <| x == f x`. This function is useful for +avoiding parentheses. Consider the following code to create a text element: + + leftAligned (monospace (fromString "code")) + +This can also be written as: + + leftAligned <| monospace <| fromString "code" +-} +(<|) : (a -> b) -> a -> b +(<|) f x = + f x + + +infixr 9 << +infixl 9 >> +infixr 0 <| +infixl 0 |> + + +{-| Given a value, returns exactly the same value. This is called +[the identity function](http://en.wikipedia.org/wiki/Identity_function). +-} +identity : a -> a +identity x = + x + + +{-| Create a function that *always* returns the same value. Useful with +functions like `map`: + + List.map (always 0) [1,2,3,4,5] == [0,0,0,0,0] + + -- List.map (\_ -> 0) [1,2,3,4,5] == [0,0,0,0,0] + -- always = (\x _ -> x) +-} +always : a -> b -> a +always a _ = + a + + +{-| Flip the order of the first two arguments to a function. -} +flip : (a -> b -> c) -> (b -> a -> c) +flip f b a = + f a b + + +{-| Change how arguments are passed to a function. +This splits paired arguments into two separate arguments. +-} +curry : ((a,b) -> c) -> a -> b -> c +curry f a b = + f (a,b) + + +{-| Change how arguments are passed to a function. +This combines two arguments into a single pair. +-} +uncurry : (a -> b -> c) -> (a,b) -> c +uncurry f (a,b) = + f a b + + +{-| A value that can never happen! For context: + + - The boolean type `Bool` has two values: `True` and `False` + - The unit type `()` has one value: `()` + - The never type `Never` has no values! + +You may see it in the wild in `Html Never` which means this HTML will never +produce any messages. You would need to write an event handler like +`onClick ??? : Attribute Never` but how can we fill in the question marks?! +So there cannot be any event handlers on that HTML. + +You may also see this used with tasks that never fail, like `Task Never ()`. + +The `Never` type is useful for restricting *arguments* to a function. Maybe my +API can only accept HTML without event handlers, so I require `Html Never` and +users can give `Html msg` and everything will go fine. Generally speaking, you +do not want `Never` in your return types though. +-} +type Never = JustOneMore Never + + +{-| A function that can never be called. Seems extremely pointless, but it +*can* come in handy. Imagine you have some HTML that should never produce any +messages. And say you want to use it in some other HTML that *does* produce +messages. You could say: + + import Html exposing (..) + + embedHtml : Html Never -> Html msg + embedHtml staticStuff = + div [] + [ text "hello" + , Html.map never staticStuff + ] + +So the `never` function is basically telling the type system, make sure no one +ever calls me! +-} +never : Never -> a +never (JustOneMore nvr) = + never nvr diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm new file mode 100644 index 0000000..14c7a82 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm @@ -0,0 +1,90 @@ +module Bitwise exposing + ( and, or, xor, complement + , shiftLeftBy, shiftRightBy, shiftRightZfBy + ) + +{-| Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation). + +# Basic Operations +@docs and, or, xor, complement + +# Bit Shifts +@docs shiftLeftBy, shiftRightBy, shiftRightZfBy +-} + +import Native.Bitwise + + +{-| Bitwise AND +-} +and : Int -> Int -> Int +and = + Native.Bitwise.and + + +{-| Bitwise OR +-} +or : Int -> Int -> Int +or = + Native.Bitwise.or + + +{-| Bitwise XOR +-} +xor : Int -> Int -> Int +xor = + Native.Bitwise.xor + + +{-| Flip each bit individually, often called bitwise NOT +-} +complement : Int -> Int +complement = + Native.Bitwise.complement + + +{-| Shift bits to the left by a given offset, filling new bits with zeros. +This can be used to multiply numbers by powers of two. + + shiftLeftBy 1 5 == 10 + shiftLeftBy 5 1 == 32 +-} +shiftLeftBy : Int -> Int -> Int +shiftLeftBy = + Native.Bitwise.shiftLeftBy + + +{-| Shift bits to the right by a given offset, filling new bits with +whatever is the topmost bit. This can be used to divide numbers by powers of two. + + shiftRightBy 1 32 == 16 + shiftRightBy 2 32 == 8 + shiftRightBy 1 -32 == -16 + +This is called an [arithmetic right shift][ars], often written (>>), and +sometimes called a sign-propagating right shift because it fills empty spots +with copies of the highest bit. + +[ars]: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift +-} +shiftRightBy : Int -> Int -> Int +shiftRightBy = + Native.Bitwise.shiftRightBy + + +{-| Shift bits to the right by a given offset, filling new bits with zeros. + + shiftRightZfBy 1 32 == 16 + shiftRightZfBy 2 32 == 8 + shiftRightZfBy 1 -32 == 2147483632 + +This is called an [logical right shift][lrs], often written (>>>), and +sometimes called a zero-fill right shift because it fills empty spots with +zeros. + +[lrs]: http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift +-} +shiftRightZfBy : Int -> Int -> Int +shiftRightZfBy = + Native.Bitwise.shiftRightZfBy + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm new file mode 100644 index 0000000..288f50b --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm @@ -0,0 +1,103 @@ +module Char exposing + ( isUpper, isLower, isDigit, isOctDigit, isHexDigit + , toUpper, toLower, toLocaleUpper, toLocaleLower + , KeyCode, toCode, fromCode + ) + +{-| Functions for working with characters. Character literals are enclosed in +`'a'` pair of single quotes. + +# Classification +@docs isUpper, isLower, isDigit, isOctDigit, isHexDigit + +# Conversion +@docs toUpper, toLower, toLocaleUpper, toLocaleLower + +# Key Codes +@docs KeyCode, toCode, fromCode + +-} + +import Native.Char +import Basics exposing ((&&), (||), (>=), (<=)) + + +isBetween : Char -> Char -> Char -> Bool +isBetween low high char = + let code = toCode char + in + (code >= toCode low) && (code <= toCode high) + + +{-| True for upper case ASCII letters. -} +isUpper : Char -> Bool +isUpper = + isBetween 'A' 'Z' + + +{-| True for lower case ASCII letters. -} +isLower : Char -> Bool +isLower = + isBetween 'a' 'z' + + +{-| True for ASCII digits `[0-9]`. -} +isDigit : Char -> Bool +isDigit = + isBetween '0' '9' + + +{-| True for ASCII octal digits `[0-7]`. -} +isOctDigit : Char -> Bool +isOctDigit = + isBetween '0' '7' + + +{-| True for ASCII hexadecimal digits `[0-9a-fA-F]`. -} +isHexDigit : Char -> Bool +isHexDigit char = + isDigit char || isBetween 'a' 'f' char || isBetween 'A' 'F' char + + +{-| Convert to upper case. -} +toUpper : Char -> Char +toUpper = + Native.Char.toUpper + + +{-| Convert to lower case. -} +toLower : Char -> Char +toLower = + Native.Char.toLower + + +{-| Convert to upper case, according to any locale-specific case mappings. -} +toLocaleUpper : Char -> Char +toLocaleUpper = + Native.Char.toLocaleUpper + + +{-| Convert to lower case, according to any locale-specific case mappings. -} +toLocaleLower : Char -> Char +toLocaleLower = + Native.Char.toLocaleLower + + +{-| Keyboard keys can be represented as integers. These are called *key codes*. +You can use [`toCode`](#toCode) and [`fromCode`](#fromCode) to convert between +key codes and characters. +-} +type alias KeyCode = Int + + +{-| Convert to key code. +-} +toCode : Char -> KeyCode +toCode = + Native.Char.toCode + + +{-| Convert from key code. -} +fromCode : KeyCode -> Char +fromCode = + Native.Char.fromCode diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm new file mode 100644 index 0000000..d150240 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm @@ -0,0 +1,456 @@ +module Color exposing + ( Color, rgb, rgba, hsl, hsla, greyscale, grayscale, complement + , Gradient, linear, radial + , toRgb, toHsl + , red, orange, yellow, green, blue, purple, brown + , lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + , darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + , white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + , lightGray, gray, darkGray + ) + +{-| Library for working with colors. Includes +[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and +[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and +built-in names. + +# Colors +@docs Color + +# Creation +@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement + +# Gradients +@docs Gradient, linear, radial + +# Extracting Colors +@docs toRgb, toHsl + +# Built-in Colors +These colors come from the [Tango +palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) +which provides aesthetically reasonable defaults for colors. Each color also +comes with a light and dark version. + +### Standard +@docs red, orange, yellow, green, blue, purple, brown + +### Light +@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + +### Dark +@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + +### Eight Shades of Grey +These colors are a compatible series of shades of grey, fitting nicely +with the Tango palette. +@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + +These are identical to the *grey* versions. It seems the spelling is regional, but +that has never helped me remember which one I should be writing. +@docs lightGray, gray, darkGray + +-} + +import Basics exposing (..) + + +{-| Representation of colors. +-} +type Color + = RGBA Int Int Int Float + | HSLA Float Float Float Float + + +{-| Create RGB colors with an alpha component for transparency. +The alpha component is specified with numbers between 0 and 1. -} +rgba : Int -> Int -> Int -> Float -> Color +rgba = + RGBA + + +{-| Create RGB colors from numbers between 0 and 255 inclusive. -} +rgb : Int -> Int -> Int -> Color +rgb r g b = + RGBA r g b 1 + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV) +with an alpha component for transparency. +-} +hsla : Float -> Float -> Float -> Float -> Color +hsla hue saturation lightness alpha = + HSLA (hue - turns (toFloat (floor (hue / (2*pi))))) saturation lightness alpha + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives +you access to colors more like a color wheel, where all hues are arranged in a +circle that you specify with standard Elm angles (radians). + + red = hsl (degrees 0) 1 0.5 + green = hsl (degrees 120) 1 0.5 + blue = hsl (degrees 240) 1 0.5 + + pastelRed = hsl (degrees 0) 0.7 0.7 + +To cycle through all colors, just cycle through degrees. The saturation level +is how vibrant the color is, like a dial between grey and bright colors. The +lightness level is a dial between white and black. +-} +hsl : Float -> Float -> Float -> Color +hsl hue saturation lightness = + hsla hue saturation lightness 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +grayscale : Float -> Color +grayscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +greyscale : Float -> Color +greyscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a “complementary color”. The two colors will +accent each other. This is the same as rotating the hue by 180°. +-} +complement : Color -> Color +complement color = + case color of + HSLA h s l a -> + hsla (h + degrees 180) s l a + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + hsla (h + degrees 180) s l a + + +{-| Extract the components of a color in the HSL format. +-} +toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float } +toHsl color = + case color of + HSLA h s l a -> + { hue=h, saturation=s, lightness=l, alpha=a } + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + { hue=h, saturation=s, lightness=l, alpha=a } + + +{-| Extract the components of a color in the RGB format. +-} +toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float } +toRgb color = + case color of + RGBA r g b a -> + { red = r, green = g, blue = b, alpha = a } + + HSLA h s l a -> + let + (r,g,b) = hslToRgb h s l + in + { red = round (255 * r) + , green = round (255 * g) + , blue = round (255 * b) + , alpha = a + } + + +fmod : Float -> Int -> Float +fmod f n = + let + integer = floor f + in + toFloat (integer % n) + f - toFloat integer + + +rgbToHsl : Int -> Int -> Int -> (Float,Float,Float) +rgbToHsl red green blue = + let + r = toFloat red / 255 + g = toFloat green / 255 + b = toFloat blue / 255 + + cMax = max (max r g) b + cMin = min (min r g) b + + c = cMax - cMin + + hue = + degrees 60 * + if cMax == r then + fmod ((g - b) / c) 6 + else if cMax == g then + ((b - r) / c) + 2 + else {- cMax == b -} + ((r - g) / c) + 4 + + lightness = + (cMax + cMin) / 2 + + saturation = + if lightness == 0 then + 0 + else + c / (1 - abs (2 * lightness - 1)) + in + (hue, saturation, lightness) + + +hslToRgb : Float -> Float -> Float -> (Float,Float,Float) +hslToRgb hue saturation lightness = + let + chroma = (1 - abs (2 * lightness - 1)) * saturation + normHue = hue / degrees 60 + + x = chroma * (1 - abs (fmod normHue 2 - 1)) + + (r,g,b) = + if normHue < 0 then (0, 0, 0) + else if normHue < 1 then (chroma, x, 0) + else if normHue < 2 then (x, chroma, 0) + else if normHue < 3 then (0, chroma, x) + else if normHue < 4 then (0, x, chroma) + else if normHue < 5 then (x, 0, chroma) + else if normHue < 6 then (chroma, 0, x) + else (0, 0, 0) + + m = lightness - chroma / 2 + in + (r + m, g + m, b + m) + + +--toV3 : Color -> V3 + +--toV4 : Color -> V4 + +{-| Abstract representation of a color gradient. +-} +type Gradient + = Linear (Float,Float) (Float,Float) (List (Float,Color)) + | Radial (Float,Float) Float (Float,Float) Float (List (Float,Color)) + + +{-| Create a linear gradient. Takes a start and end point and then a series of +“color stops” that indicate how to interpolate between the start and +end points. See [this example](http://elm-lang.org/examples/linear-gradient) for a +more visual explanation. +-} +linear : (Float, Float) -> (Float, Float) -> List (Float,Color) -> Gradient +linear = + Linear + + +{-| Create a radial gradient. First takes a start point and inner radius. Then +takes an end point and outer radius. It then takes a series of “color +stops” that indicate how to interpolate between the inner and outer +circles. See [this example](http://elm-lang.org/examples/radial-gradient) for a +more visual explanation. +-} +radial : (Float,Float) -> Float -> (Float,Float) -> Float -> List (Float,Color) -> Gradient +radial = + Radial + + +-- BUILT-IN COLORS + +{-|-} +lightRed : Color +lightRed = + RGBA 239 41 41 1 + + +{-|-} +red : Color +red = + RGBA 204 0 0 1 + + +{-|-} +darkRed : Color +darkRed = + RGBA 164 0 0 1 + + +{-|-} +lightOrange : Color +lightOrange = + RGBA 252 175 62 1 + + +{-|-} +orange : Color +orange = + RGBA 245 121 0 1 + + +{-|-} +darkOrange : Color +darkOrange = + RGBA 206 92 0 1 + + +{-|-} +lightYellow : Color +lightYellow = + RGBA 255 233 79 1 + + +{-|-} +yellow : Color +yellow = + RGBA 237 212 0 1 + + +{-|-} +darkYellow : Color +darkYellow = + RGBA 196 160 0 1 + + +{-|-} +lightGreen : Color +lightGreen = + RGBA 138 226 52 1 + + +{-|-} +green : Color +green = + RGBA 115 210 22 1 + + +{-|-} +darkGreen : Color +darkGreen = + RGBA 78 154 6 1 + + +{-|-} +lightBlue : Color +lightBlue = + RGBA 114 159 207 1 + + +{-|-} +blue : Color +blue = + RGBA 52 101 164 1 + + +{-|-} +darkBlue : Color +darkBlue = + RGBA 32 74 135 1 + + +{-|-} +lightPurple : Color +lightPurple = + RGBA 173 127 168 1 + + +{-|-} +purple : Color +purple = + RGBA 117 80 123 1 + + +{-|-} +darkPurple : Color +darkPurple = + RGBA 92 53 102 1 + + +{-|-} +lightBrown : Color +lightBrown = + RGBA 233 185 110 1 + + +{-|-} +brown : Color +brown = + RGBA 193 125 17 1 + + +{-|-} +darkBrown : Color +darkBrown = + RGBA 143 89 2 1 + + +{-|-} +black : Color +black = + RGBA 0 0 0 1 + + +{-|-} +white : Color +white = + RGBA 255 255 255 1 + + +{-|-} +lightGrey : Color +lightGrey = + RGBA 238 238 236 1 + + +{-|-} +grey : Color +grey = + RGBA 211 215 207 1 + + +{-|-} +darkGrey : Color +darkGrey = + RGBA 186 189 182 1 + + +{-|-} +lightGray : Color +lightGray = + RGBA 238 238 236 1 + + +{-|-} +gray : Color +gray = + RGBA 211 215 207 1 + + +{-|-} +darkGray : Color +darkGray = + RGBA 186 189 182 1 + + +{-|-} +lightCharcoal : Color +lightCharcoal = + RGBA 136 138 133 1 + + +{-|-} +charcoal : Color +charcoal = + RGBA 85 87 83 1 + + +{-|-} +darkCharcoal : Color +darkCharcoal = + RGBA 46 52 54 1 diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm new file mode 100644 index 0000000..0d62982 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm @@ -0,0 +1,150 @@ +module Date exposing + ( Date, fromString, toTime, fromTime + , year, month, Month(..) + , day, dayOfWeek, Day(..) + , hour, minute, second, millisecond + , now + ) + +{-| Library for working with dates. Email the mailing list if you encounter +issues with internationalization or locale formatting. + +# Dates +@docs Date, now + +# Conversions +@docs fromString, toTime, fromTime + +# Extractions +@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second, millisecond + +-} + +import Native.Date +import Task exposing (Task) +import Time exposing (Time) +import Result exposing (Result) + + + +-- DATES + + +{-| Representation of a date. +-} +type Date = Date + + +{-| Get the `Date` at the moment when this task is run. +-} +now : Task x Date +now = + Task.map fromTime Time.now + + + +-- CONVERSIONS AND EXTRACTIONS + + +{-| Represents the days of the week. +-} +type Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun + + +{-| Represents the month of the year. +-} +type Month + = Jan | Feb | Mar | Apr + | May | Jun | Jul | Aug + | Sep | Oct | Nov | Dec + + +{-| Attempt to read a date from a string. +-} +fromString : String -> Result String Date +fromString = + Native.Date.fromString + + +{-| Convert a `Date` to a time in milliseconds. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +toTime : Date -> Time +toTime = + Native.Date.toTime + + +{-| Convert a time in milliseconds into a `Date`. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +fromTime : Time -> Date +fromTime = + Native.Date.fromTime + + +{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `1990`. +-} +year : Date -> Int +year = + Native.Date.year + + +{-| Extract the month of a given date. Given the date 23 June 1990 at 11:45AM +this returns the month `Jun` as defined below. +-} +month : Date -> Month +month = + Native.Date.month + + +{-| Extract the day of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `23`. +-} +day : Date -> Int +day = + Native.Date.day + + +{-| Extract the day of the week for a given date. Given the date 23 June +1990 at 11:45AM this returns the day `Sat` as defined below. +-} +dayOfWeek : Date -> Day +dayOfWeek = + Native.Date.dayOfWeek + + +{-| Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `11`. +-} +hour : Date -> Int +hour = + Native.Date.hour + + +{-| Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `45`. +-} +minute : Date -> Int +minute = + Native.Date.minute + + +{-| Extract the second of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `0`. +-} +second : Date -> Int +second = + Native.Date.second + + +{-| Extract the millisecond of a given date. Given the date 23 June 1990 at 11:45:30.123AM +this returns the integer `123`. +-} +millisecond : Date -> Int +millisecond = + Native.Date.millisecond diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm new file mode 100644 index 0000000..49668f5 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm @@ -0,0 +1,62 @@ +module Debug exposing + ( log + , crash + ) + +{-| This library is for investigating bugs or performance problems. It should +*not* be used in production code. + +# Debugging +@docs log, crash +-} + +import Native.Debug + + +{-| Log a tagged value on the developer console, and then return the value. + + 1 + log "number" 1 -- equals 2, logs "number: 1" + length (log "start" []) -- equals 0, logs "start: []" + +Notice that `log` is not a pure function! It should *only* be used for +investigating bugs or performance problems. +-} +log : String -> a -> a +log = + Native.Debug.log + + +{-| Crash the program with an error message. This is an uncatchable error, +intended for code that is soon-to-be-implemented. For example, if you are +working with a large ADT and have partially completed a case expression, it may +make sense to do this: + + type Entity = Ship | Fish | Captain | Seagull + + drawEntity entity = + case entity of + Ship -> + ... + + Fish -> + ... + + _ -> + Debug.crash "TODO" + +The Elm compiler recognizes each `Debug.crash` and when you run into it at +runtime, the error will point to the corresponding module name and line number. +For `case` expressions that ends with a wildcard pattern and a crash, it will +also show the value that snuck through. In our example, that'd be `Captain` or +`Seagull`. + +**Use this if** you want to do some testing while you are partway through +writing a function. + +**Do not use this if** you want to do some typical try-catch exception handling. +Use the [`Maybe`](Maybe) or [`Result`](Result) libraries instead. +-} +crash : String -> a +crash = + Native.Debug.crash + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm new file mode 100644 index 0000000..0bb9501 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm @@ -0,0 +1,661 @@ +module Dict exposing + ( Dict + , empty, singleton, insert, update + , isEmpty, get, remove, member, size + , filter + , partition + , foldl, foldr, map + , union, intersect, diff, merge + , keys, values + , toList, fromList + ) + +{-| A dictionary mapping unique keys to values. The keys can be any comparable +type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or +lists of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Dictionaries +@docs Dict + +# Build +@docs empty, singleton, insert, update, remove + +# Query +@docs isEmpty, member, get, size + +# Lists +@docs keys, values, toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +# Combine +@docs union, intersect, diff, merge + +-} + + +import Basics exposing (..) +import Maybe exposing (..) +import List exposing (..) +import Native.Debug +import String + + + +-- DICTIONARIES + + +-- BBlack and NBlack should only be used during the deletion +-- algorithm. Any other occurrence is a bug and should fail an assert. +type NColor + = Red + | Black + | BBlack -- Double Black, counts as 2 blacks for the invariant + | NBlack -- Negative Black, counts as -1 blacks for the invariant + + +type LeafColor + = LBlack + | LBBlack -- Double Black, counts as 2 + + +{-| A dictionary of keys and values. So a `(Dict String User)` is a dictionary +that lets you look up a `String` (such as user names) and find the associated +`User`. +-} +type Dict k v + = RBNode_elm_builtin NColor k v (Dict k v) (Dict k v) + | RBEmpty_elm_builtin LeafColor + + +{-| Create an empty dictionary. -} +empty : Dict k v +empty = + RBEmpty_elm_builtin LBlack + + +maxWithDefault : k -> v -> Dict k v -> (k, v) +maxWithDefault k v r = + case r of + RBEmpty_elm_builtin _ -> + (k, v) + + RBNode_elm_builtin _ kr vr _ rr -> + maxWithDefault kr vr rr + + +{-| Get the value associated with a key. If the key is not found, return +`Nothing`. This is useful when you are not sure if a key will be in the +dictionary. + + animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ] + + get "Tom" animals == Just Cat + get "Jerry" animals == Just Mouse + get "Spike" animals == Nothing + +-} +get : comparable -> Dict comparable v -> Maybe v +get targetKey dict = + case dict of + RBEmpty_elm_builtin _ -> + Nothing + + RBNode_elm_builtin _ key value left right -> + case compare targetKey key of + LT -> + get targetKey left + + EQ -> + Just value + + GT -> + get targetKey right + + +{-| Determine if a key is in a dictionary. -} +member : comparable -> Dict comparable v -> Bool +member key dict = + case get key dict of + Just _ -> + True + + Nothing -> + False + + +{-| Determine the number of key-value pairs in the dictionary. -} +size : Dict k v -> Int +size dict = + sizeHelp 0 dict + + +sizeHelp : Int -> Dict k v -> Int +sizeHelp n dict = + case dict of + RBEmpty_elm_builtin _ -> + n + + RBNode_elm_builtin _ _ _ left right -> + sizeHelp (sizeHelp (n+1) right) left + + +{-| Determine if a dictionary is empty. + + isEmpty empty == True +-} +isEmpty : Dict k v -> Bool +isEmpty dict = + dict == empty + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + red node => black node + black node => same + bblack node => xxx + nblack node => xxx + + black leaf => same + bblack leaf => xxx +-} +ensureBlackRoot : Dict k v -> Dict k v +ensureBlackRoot dict = + case dict of + RBNode_elm_builtin Red key value left right -> + RBNode_elm_builtin Black key value left right + + _ -> + dict + + +{-| Insert a key-value pair into a dictionary. Replaces value when there is +a collision. -} +insert : comparable -> v -> Dict comparable v -> Dict comparable v +insert key value dict = + update key (always (Just value)) dict + + +{-| Remove a key-value pair from a dictionary. If the key is not found, +no changes are made. -} +remove : comparable -> Dict comparable v -> Dict comparable v +remove key dict = + update key (always Nothing) dict + + +type Flag = Insert | Remove | Same + + +{-| Update the value of a dictionary for a specific key with a given function. -} +update : comparable -> (Maybe v -> Maybe v) -> Dict comparable v -> Dict comparable v +update k alter dict = + let + up dict = + case dict of + -- expecting only black nodes, never double black nodes here + RBEmpty_elm_builtin _ -> + case alter Nothing of + Nothing -> + (Same, empty) + + Just v -> + (Insert, RBNode_elm_builtin Red k v empty empty) + + RBNode_elm_builtin clr key value left right -> + case compare k key of + EQ -> + case alter (Just value) of + Nothing -> + (Remove, rem clr left right) + + Just newValue -> + (Same, RBNode_elm_builtin clr key newValue left right) + + LT -> + let (flag, newLeft) = up left in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value newLeft right) + + Insert -> + (Insert, balance clr key value newLeft right) + + Remove -> + (Remove, bubble clr key value newLeft right) + + GT -> + let (flag, newRight) = up right in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value left newRight) + + Insert -> + (Insert, balance clr key value left newRight) + + Remove -> + (Remove, bubble clr key value left newRight) + + (flag, updatedDict) = + up dict + in + case flag of + Same -> + updatedDict + + Insert -> + ensureBlackRoot updatedDict + + Remove -> + blacken updatedDict + + +{-| Create a dictionary with one key-value pair. -} +singleton : comparable -> v -> Dict comparable v +singleton key value = + insert key value empty + + + +-- HELPERS + + +isBBlack : Dict k v -> Bool +isBBlack dict = + case dict of + RBNode_elm_builtin BBlack _ _ _ _ -> + True + + RBEmpty_elm_builtin LBBlack -> + True + + _ -> + False + + +moreBlack : NColor -> NColor +moreBlack color = + case color of + Black -> + BBlack + + Red -> + Black + + NBlack -> + Red + + BBlack -> + Native.Debug.crash "Can't make a double black node more black!" + + +lessBlack : NColor -> NColor +lessBlack color = + case color of + BBlack -> + Black + + Black -> + Red + + Red -> + NBlack + + NBlack -> + Native.Debug.crash "Can't make a negative black node less black!" + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + node => less black node + + bblack leaf => black leaf + black leaf => xxx +-} +lessBlackTree : Dict k v -> Dict k v +lessBlackTree dict = + case dict of + RBNode_elm_builtin c k v l r -> + RBNode_elm_builtin (lessBlack c) k v l r + + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + +reportRemBug : String -> NColor -> String -> String -> a +reportRemBug msg c lgot rgot = + Native.Debug.crash <| + String.concat + [ "Internal red-black tree invariant violated, expected " + , msg, " and got ", toString c, "/", lgot, "/", rgot + , "\nPlease report this bug to " + ] + + +-- Remove the top node from the tree, may leave behind BBlacks +rem : NColor -> Dict k v -> Dict k v -> Dict k v +rem color left right = + case (left, right) of + (RBEmpty_elm_builtin _, RBEmpty_elm_builtin _) -> + case color of + Red -> + RBEmpty_elm_builtin LBlack + + Black -> + RBEmpty_elm_builtin LBBlack + + _ -> + Native.Debug.crash "cannot have bblack or nblack nodes at this point" + + (RBEmpty_elm_builtin cl, RBNode_elm_builtin cr k v l r) -> + case (color, cl, cr) of + (Black, LBlack, Red) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/LBlack/Red" color (toString cl) (toString cr) + + (RBNode_elm_builtin cl k v l r, RBEmpty_elm_builtin cr) -> + case (color, cl, cr) of + (Black, Red, LBlack) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/Red/LBlack" color (toString cl) (toString cr) + + -- l and r are both RBNodes + (RBNode_elm_builtin cl kl vl ll rl, RBNode_elm_builtin _ _ _ _ _) -> + let + (k, v) = + maxWithDefault kl vl rl + + newLeft = + removeMax cl kl vl ll rl + in + bubble color k v newLeft right + + +-- Kills a BBlack or moves it upward, may leave behind NBlack +bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +bubble c k v l r = + if isBBlack l || isBBlack r then + balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r) + + else + RBNode_elm_builtin c k v l r + + +-- Removes rightmost node, may leave root as BBlack +removeMax : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +removeMax c k v l r = + case r of + RBEmpty_elm_builtin _ -> + rem c l r + + RBNode_elm_builtin cr kr vr lr rr -> + bubble c k v l (removeMax cr kr vr lr rr) + + +-- generalized tree balancing act +balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +balance c k v l r = + let + tree = + RBNode_elm_builtin c k v l r + in + if blackish tree then + balanceHelp tree + + else + tree + + +blackish : Dict k v -> Bool +blackish t = + case t of + RBNode_elm_builtin c _ _ _ _ -> + c == Black || c == BBlack + + RBEmpty_elm_builtin _ -> + True + + +balanceHelp : Dict k v -> Dict k v +balanceHelp tree = + case tree of + -- double red: left, left + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red yk yv (RBNode_elm_builtin Red xk xv a b) c) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: left, right + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red xk xv a (RBNode_elm_builtin Red yk yv b c)) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, left + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red zk zv (RBNode_elm_builtin Red yk yv b c) d) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, right + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red yk yv b (RBNode_elm_builtin Red zk zv c d)) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- handle double blacks + RBNode_elm_builtin BBlack xk xv a (RBNode_elm_builtin NBlack zk zv (RBNode_elm_builtin Black yk yv b c) (RBNode_elm_builtin Black _ _ _ _ as d)) -> + RBNode_elm_builtin Black yk yv (RBNode_elm_builtin Black xk xv a b) (balance Black zk zv c (redden d)) + + RBNode_elm_builtin BBlack zk zv (RBNode_elm_builtin NBlack xk xv (RBNode_elm_builtin Black _ _ _ _ as a) (RBNode_elm_builtin Black yk yv b c)) d -> + RBNode_elm_builtin Black yk yv (balance Black xk xv (redden a) b) (RBNode_elm_builtin Black zk zv c d) + + _ -> + tree + + +balancedTree : NColor -> k -> v -> k -> v -> k -> v -> Dict k v -> Dict k v -> Dict k v -> Dict k v -> Dict k v +balancedTree col xk xv yk yv zk zv a b c d = + RBNode_elm_builtin + (lessBlack col) + yk + yv + (RBNode_elm_builtin Black xk xv a b) + (RBNode_elm_builtin Black zk zv c d) + + +-- make the top node black +blacken : Dict k v -> Dict k v +blacken t = + case t of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Black k v l r + + +-- make the top node red +redden : Dict k v -> Dict k v +redden t = + case t of + RBEmpty_elm_builtin _ -> + Native.Debug.crash "can't make a Leaf red" + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Red k v l r + + + +-- COMBINE + + +{-| Combine two dictionaries. If there is a collision, preference is given +to the first dictionary. +-} +union : Dict comparable v -> Dict comparable v -> Dict comparable v +union t1 t2 = + foldl insert t2 t1 + + +{-| Keep a key-value pair when its key appears in the second dictionary. +Preference is given to values in the first dictionary. +-} +intersect : Dict comparable v -> Dict comparable v -> Dict comparable v +intersect t1 t2 = + filter (\k _ -> member k t2) t1 + + +{-| Keep a key-value pair when its key does not appear in the second dictionary. +-} +diff : Dict comparable v -> Dict comparable v -> Dict comparable v +diff t1 t2 = + foldl (\k v t -> remove k t) t1 t2 + + +{-| The most general way of combining two dictionaries. You provide three +accumulators for when a given key appears: + + 1. Only in the left dictionary. + 2. In both dictionaries. + 3. Only in the right dictionary. + +You then traverse all the keys from lowest to highest, building up whatever +you want. +-} +merge + : (comparable -> a -> result -> result) + -> (comparable -> a -> b -> result -> result) + -> (comparable -> b -> result -> result) + -> Dict comparable a + -> Dict comparable b + -> result + -> result +merge leftStep bothStep rightStep leftDict rightDict initialResult = + let + stepState rKey rValue (list, result) = + case list of + [] -> + (list, rightStep rKey rValue result) + + (lKey, lValue) :: rest -> + if lKey < rKey then + stepState rKey rValue (rest, leftStep lKey lValue result) + + else if lKey > rKey then + (list, rightStep rKey rValue result) + + else + (rest, bothStep lKey lValue rValue result) + + (leftovers, intermediateResult) = + foldl stepState (toList leftDict, initialResult) rightDict + in + List.foldl (\(k,v) result -> leftStep k v result) intermediateResult leftovers + + + +-- TRANSFORM + + +{-| Apply a function to all values in a dictionary. +-} +map : (comparable -> a -> b) -> Dict comparable a -> Dict comparable b +map f dict = + case dict of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin clr key value left right -> + RBNode_elm_builtin clr key (f key value) (map f left) (map f right) + + +{-| Fold over the key-value pairs in a dictionary, in order from lowest +key to highest key. +-} +foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldl f acc dict = + case dict of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldl f (f key value (foldl f acc left)) right + + +{-| Fold over the key-value pairs in a dictionary, in order from highest +key to lowest key. +-} +foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldr f acc t = + case t of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldr f (f key value (foldr f acc right)) left + + +{-| Keep a key-value pair when it satisfies a predicate. -} +filter : (comparable -> v -> Bool) -> Dict comparable v -> Dict comparable v +filter predicate dictionary = + let + add key value dict = + if predicate key value then + insert key value dict + + else + dict + in + foldl add empty dictionary + + +{-| Partition a dictionary according to a predicate. The first dictionary +contains all key-value pairs which satisfy the predicate, and the second +contains the rest. +-} +partition : (comparable -> v -> Bool) -> Dict comparable v -> (Dict comparable v, Dict comparable v) +partition predicate dict = + let + add key value (t1, t2) = + if predicate key value then + (insert key value t1, t2) + + else + (t1, insert key value t2) + in + foldl add (empty, empty) dict + + + +-- LISTS + + +{-| Get all of the keys in a dictionary, sorted from lowest to highest. + + keys (fromList [(0,"Alice"),(1,"Bob")]) == [0,1] +-} +keys : Dict comparable v -> List comparable +keys dict = + foldr (\key value keyList -> key :: keyList) [] dict + + +{-| Get all of the values in a dictionary, in the order of their keys. + + values (fromList [(0,"Alice"),(1,"Bob")]) == ["Alice", "Bob"] +-} +values : Dict comparable v -> List v +values dict = + foldr (\key value valueList -> value :: valueList) [] dict + + +{-| Convert a dictionary into an association list of key-value pairs, sorted by keys. -} +toList : Dict comparable v -> List (comparable,v) +toList dict = + foldr (\key value list -> (key,value) :: list) [] dict + + +{-| Convert an association list into a dictionary. -} +fromList : List (comparable,v) -> Dict comparable v +fromList assocs = + List.foldl (\(key,value) dict -> insert key value dict) empty assocs diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm new file mode 100644 index 0000000..0fc853d --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm @@ -0,0 +1,520 @@ +module Json.Decode exposing + ( Decoder, string, bool, int, float + , nullable, list, array, dict, keyValuePairs + , field, at, index + , maybe, oneOf + , decodeString, decodeValue, Value + , map, map2, map3, map4, map5, map6, map7, map8 + , lazy, value, null, succeed, fail, andThen + ) + +{-| Turn JSON values into Elm values. Definitely check out this [intro to +JSON decoders][guide] to get a feel for how this library works! + +[guide]: https://guide.elm-lang.org/interop/json.html + +# Primitives +@docs Decoder, string, bool, int, float + +# Data Structures +@docs nullable, list, array, dict, keyValuePairs + +# Object Primitives +@docs field, at, index + +# Inconsistent Structure +@docs maybe, oneOf + +# Run Decoders +@docs decodeString, decodeValue, Value + +# Mapping + +**Note:** If you run out of map functions, take a look at [elm-decode-pipeline][pipe] +which makes it easier to handle large objects, but produces lower quality type +errors. + +[pipe]: http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest + +@docs map, map2, map3, map4, map5, map6, map7, map8 + +# Fancy Decoding +@docs lazy, value, null, succeed, fail, andThen +-} + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Encode as JsEncode +import List +import Maybe exposing (Maybe(..)) +import Result exposing (Result(..)) +import Native.Json + + + +-- PRIMITIVES + + +{-| A value that knows how to decode JSON values. +-} +type Decoder a = Decoder + + +{-| Decode a JSON string into an Elm `String`. + + decodeString string "true" == Err ... + decodeString string "42" == Err ... + decodeString string "3.14" == Err ... + decodeString string "\"hello\"" == Ok "hello" + decodeString string "{ \"hello\": 42 }" == Err ... +-} +string : Decoder String +string = + Native.Json.decodePrimitive "string" + + +{-| Decode a JSON boolean into an Elm `Bool`. + + decodeString bool "true" == Ok True + decodeString bool "42" == Err ... + decodeString bool "3.14" == Err ... + decodeString bool "\"hello\"" == Err ... + decodeString bool "{ \"hello\": 42 }" == Err ... +-} +bool : Decoder Bool +bool = + Native.Json.decodePrimitive "bool" + + +{-| Decode a JSON number into an Elm `Int`. + + decodeString int "true" == Err ... + decodeString int "42" == Ok 42 + decodeString int "3.14" == Err ... + decodeString int "\"hello\"" == Err ... + decodeString int "{ \"hello\": 42 }" == Err ... +-} +int : Decoder Int +int = + Native.Json.decodePrimitive "int" + + +{-| Decode a JSON number into an Elm `Float`. + + decodeString float "true" == Err .. + decodeString float "42" == Ok 42 + decodeString float "3.14" == Ok 3.14 + decodeString float "\"hello\"" == Err ... + decodeString float "{ \"hello\": 42 }" == Err ... +-} +float : Decoder Float +float = + Native.Json.decodePrimitive "float" + + + +-- DATA STRUCTURES + + +{-| Decode a nullable JSON value into an Elm value. + + decodeString (nullable int) "13" == Ok (Just 13) + decodeString (nullable int) "42" == Ok (Just 42) + decodeString (nullable int) "null" == Ok Nothing + decodeString (nullable int) "true" == Err .. +-} +nullable : Decoder a -> Decoder (Maybe a) +nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] + + +{-| Decode a JSON array into an Elm `List`. + + decodeString (list int) "[1,2,3]" == Ok [1,2,3] + decodeString (list bool) "[true,false]" == Ok [True,False] +-} +list : Decoder a -> Decoder (List a) +list decoder = + Native.Json.decodeContainer "list" decoder + + +{-| Decode a JSON array into an Elm `Array`. + + decodeString (array int) "[1,2,3]" == Ok (Array.fromList [1,2,3]) + decodeString (array bool) "[true,false]" == Ok (Array.fromList [True,False]) +-} +array : Decoder a -> Decoder (Array a) +array decoder = + Native.Json.decodeContainer "array" decoder + + +{-| Decode a JSON object into an Elm `Dict`. + + decodeString (dict int) "{ \"alice\": 42, \"bob\": 99 }" + == Dict.fromList [("alice", 42), ("bob", 99)] +-} +dict : Decoder a -> Decoder (Dict String a) +dict decoder = + map Dict.fromList (keyValuePairs decoder) + + +{-| Decode a JSON object into an Elm `List` of pairs. + + decodeString (keyValuePairs int) "{ \"alice\": 42, \"bob\": 99 }" + == [("alice", 42), ("bob", 99)] +-} +keyValuePairs : Decoder a -> Decoder (List (String, a)) +keyValuePairs = + Native.Json.decodeKeyValuePairs + + + +-- OBJECT PRIMITIVES + + +{-| Decode a JSON object, requiring a particular field. + + decodeString (field "x" int) "{ \"x\": 3 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": 3, \"y\": 4 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": true }" == Err ... + decodeString (field "x" int) "{ \"y\": 4 }" == Err ... + + decodeString (field "name" string) "{ \"name\": \"tom\" }" == Ok "tom" + +The object *can* have other fields. Lots of them! The only thing this decoder +cares about is if `x` is present and that the value there is an `Int`. + +Check out [`map2`](#map2) to see how to decode multiple fields! +-} +field : String -> Decoder a -> Decoder a +field = + Native.Json.decodeField + + +{-| Decode a nested JSON object, requiring certain fields. + + json = """{ "person": { "name": "tom", "age": 42 } }""" + + decodeString (at ["person", "name"] string) json == Ok "tom" + decodeString (at ["person", "age" ] int ) json == Ok "42 + +This is really just a shorthand for saying things like: + + field "person" (field "name" string) == at ["person","name"] string +-} +at : List String -> Decoder a -> Decoder a +at fields decoder = + List.foldr field decoder fields + + +{-| Decode a JSON array, requiring a particular index. + + json = """[ "alice", "bob", "chuck" ]""" + + decodeString (index 0 string) json == Ok "alice" + decodeString (index 1 string) json == Ok "bob" + decodeString (index 2 string) json == Ok "chuck" + decodeString (index 3 string) json == Err ... +-} +index : Int -> Decoder a -> Decoder a +index = + Native.Json.decodeIndex + + + +-- WEIRD STRUCTURE + + +{-| Helpful for dealing with optional fields. Here are a few slightly different +examples: + + json = """{ "name": "tom", "age": 42 }""" + + decodeString (maybe (field "age" int )) json == Ok (Just 42) + decodeString (maybe (field "name" int )) json == Ok Nothing + decodeString (maybe (field "height" float)) json == Ok Nothing + + decodeString (field "age" (maybe int )) json == Ok (Just 42) + decodeString (field "name" (maybe int )) json == Ok Nothing + decodeString (field "height" (maybe float)) json == Err ... + +Notice the last example! It is saying we *must* have a field named `height` and +the content *may* be a float. There is no `height` field, so the decoder fails. + +Point is, `maybe` will make exactly what it contains conditional. For optional +fields, this means you probably want it *outside* a use of `field` or `at`. +-} +maybe : Decoder a -> Decoder (Maybe a) +maybe decoder = + Native.Json.decodeContainer "maybe" decoder + + +{-| Try a bunch of different decoders. This can be useful if the JSON may come +in a couple different formats. For example, say you want to read an array of +numbers, but some of them are `null`. + + import String + + badInt : Decoder Int + badInt = + oneOf [ int, null 0 ] + + -- decodeString (list badInt) "[1,2,null,4]" == Ok [1,2,0,4] + +Why would someone generate JSON like this? Questions like this are not good +for your health. The point is that you can use `oneOf` to handle situations +like this! + +You could also use `oneOf` to help version your data. Try the latest format, +then a few older ones that you still support. You could use `andThen` to be +even more particular if you wanted. +-} +oneOf : List (Decoder a) -> Decoder a +oneOf = + Native.Json.oneOf + + + +-- MAPPING + + +{-| Transform a decoder. Maybe you just want to know the length of a string: + + import String + + stringLength : Decoder Int + stringLength = + map String.length string + +It is often helpful to use `map` with `oneOf`, like when defining `nullable`: + + nullable : Decoder a -> Decoder (Maybe a) + nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] +-} +map : (a -> value) -> Decoder a -> Decoder value +map = + Native.Json.map1 + + +{-| Try two decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Point = { x : Float, y : Float } + + point : Decoder Point + point = + map2 Point + (field "x" float) + (field "y" float) + + -- decodeString point """{ "x": 3, "y": 4 }""" == Ok { x = 3, y = 4 } + +It tries each individual decoder and puts the result together with the `Point` +constructor. +-} +map2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value +map2 = + Native.Json.map2 + + +{-| Try three decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Person = { name : String, age : Int, height : Float } + + person : Decoder Person + person = + map3 Person + (at ["name"] string) + (at ["info","age"] int) + (at ["info","height"] float) + + -- json = """{ "name": "tom", "info": { "age": 42, "height": 1.8 } }""" + -- decodeString person json == Ok { name = "tom", age = 42, height = 1.8 } + +Like `map2` it tries each decoder in order and then give the results to the +`Person` constructor. That can be any function though! +-} +map3 : (a -> b -> c -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder value +map3 = + Native.Json.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder value +map4 = + Native.Json.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder value +map5 = + Native.Json.map5 + + +{-|-} +map6 : (a -> b -> c -> d -> e -> f -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder value +map6 = + Native.Json.map6 + + +{-|-} +map7 : (a -> b -> c -> d -> e -> f -> g -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder value +map7 = + Native.Json.map7 + + +{-|-} +map8 : (a -> b -> c -> d -> e -> f -> g -> h -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder h -> Decoder value +map8 = + Native.Json.map8 + + + +-- RUN DECODERS + + +{-| Parse the given string into a JSON value and then run the `Decoder` on it. +This will fail if the string is not well-formed JSON or if the `Decoder` +fails for some reason. + + decodeString int "4" == Ok 4 + decodeString int "1 + 2" == Err ... +-} +decodeString : Decoder a -> String -> Result String a +decodeString = + Native.Json.runOnString + + +{-| Run a `Decoder` on some JSON `Value`. You can send these JSON values +through ports, so that is probably the main time you would use this function. +-} +decodeValue : Decoder a -> Value -> Result String a +decodeValue = + Native.Json.run + + +{-| A JSON value. +-} +type alias Value = JsEncode.Value + + + +-- FANCY PRIMITIVES + + +{-| Ignore the JSON and produce a certain Elm value. + + decodeString (succeed 42) "true" == Ok 42 + decodeString (succeed 42) "[1,2,3]" == Ok 42 + decodeString (succeed 42) "hello" == Err ... -- this is not a valid JSON string + +This is handy when used with `oneOf` or `andThen`. +-} +succeed : a -> Decoder a +succeed = + Native.Json.succeed + + +{-| Ignore the JSON and make the decoder fail. This is handy when used with +`oneOf` or `andThen` where you want to give a custom error message in some +case. + +See the [`andThen`](#andThen) docs for an example. +-} +fail : String -> Decoder a +fail = + Native.Json.fail + + +{-| Create decoders that depend on previous results. If you are creating +versioned data, you might do something like this: + + info : Decoder Info + info = + field "version" int + |> andThen infoHelp + + infoHelp : Int -> Decoder Info + infoHelp version = + case version of + 4 -> + infoDecoder4 + + 3 -> + infoDecoder3 + + _ -> + fail <| + "Trying to decode info, but version " + ++ toString version ++ " is not supported." + + -- infoDecoder4 : Decoder Info + -- infoDecoder3 : Decoder Info +-} +andThen : (a -> Decoder b) -> Decoder a -> Decoder b +andThen = + Native.Json.andThen + + +{-| Sometimes you have JSON with recursive structure, like nested comments. +You can use `lazy` to make sure your decoder unrolls lazily. + + type alias Comment = + { message : String + , responses : Responses + } + + type Responses = Responses (List Comment) + + comment : Decoder Comment + comment = + map2 Comment + (field "message" string) + (field "responses" (map Responses (list (lazy (\_ -> comment))))) + +If we had said `list comment` instead, we would start expanding the value +infinitely. What is a `comment`? It is a decoder for objects where the +`responses` field contains comments. What is a `comment` though? Etc. + +By using `list (lazy (\_ -> comment))` we make sure the decoder only expands +to be as deep as the JSON we are given. You can read more about recursive data +structures [here][]. + +[here]: https://github.com/elm-lang/elm-compiler/blob/master/hints/recursive-alias.md +-} +lazy : (() -> Decoder a) -> Decoder a +lazy thunk = + andThen thunk (succeed ()) + + +{-| Do not do anything with a JSON value, just bring it into Elm as a `Value`. +This can be useful if you have particularly crazy data that you would like to +deal with later. Or if you are going to send it out a port and do not care +about its structure. +-} +value : Decoder Value +value = + Native.Json.decodePrimitive "value" + + +{-| Decode a `null` value into some Elm value. + + decodeString (null False) "null" == Ok False + decodeString (null 42) "null" == Ok 42 + decodeString (null 42) "42" == Err .. + decodeString (null 42) "false" == Err .. + +So if you ever see a `null`, this will return whatever value you specified. +-} +null : a -> Decoder a +null = + Native.Json.decodeNull diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm new file mode 100644 index 0000000..29e6fc9 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm @@ -0,0 +1,102 @@ +module Json.Encode exposing + ( Value + , encode + , string, int, float, bool, null + , list, array + , object + ) + +{-| Library for turning Elm values into Json values. + +# Encoding +@docs encode, Value + +# Primitives +@docs string, int, float, bool, null + +# Arrays +@docs list, array + +# Objects +@docs object +-} + +import Array exposing (Array) +import Native.Json + + +{-| Represents a JavaScript value. +-} +type Value = Value + + +{-| Convert a `Value` into a prettified string. The first argument specifies +the amount of indentation in the resulting string. + + person = + object + [ ("name", string "Tom") + , ("age", int 42) + ] + + compact = encode 0 person + -- {"name":"Tom","age":42} + + readable = encode 4 person + -- { + -- "name": "Tom", + -- "age": 42 + -- } +-} +encode : Int -> Value -> String +encode = + Native.Json.encode + + +{-|-} +string : String -> Value +string = + Native.Json.identity + + +{-|-} +int : Int -> Value +int = + Native.Json.identity + + +{-| Encode a Float. `Infinity` and `NaN` are encoded as `null`. +-} +float : Float -> Value +float = + Native.Json.identity + + +{-|-} +bool : Bool -> Value +bool = + Native.Json.identity + + +{-|-} +null : Value +null = + Native.Json.encodeNull + + +{-|-} +object : List (String, Value) -> Value +object = + Native.Json.encodeObject + + +{-|-} +array : Array Value -> Value +array = + Native.Json.encodeArray + + +{-|-} +list : List Value -> Value +list = + Native.Json.encodeList diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm new file mode 100644 index 0000000..0b7ddf9 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm @@ -0,0 +1,613 @@ +module List exposing + ( isEmpty, length, reverse, member + , head, tail, filter, take, drop + , singleton, repeat, range, (::), append, concat, intersperse + , partition, unzip + , map, map2, map3, map4, map5 + , filterMap, concatMap, indexedMap + , foldr, foldl + , sum, product, maximum, minimum, all, any, scanl + , sort, sortBy, sortWith + ) + +{-| A library for manipulating lists of values. Every value in a +list must have the same type. + +# Basics +@docs isEmpty, length, reverse, member + +# Sub-lists +@docs head, tail, filter, take, drop + +# Putting Lists Together +@docs singleton, repeat, range, (::), append, concat, intersperse + +# Taking Lists Apart +@docs partition, unzip + +# Mapping +@docs map, map2, map3, map4, map5 + +If you can think of a legitimate use of `mapN` where `N` is 6 or more, please +let us know on [the list](https://groups.google.com/forum/#!forum/elm-discuss). +The current sentiment is that it is already quite error prone once you get to +4 and possibly should be approached another way. + +# Special Maps +@docs filterMap, concatMap, indexedMap + +# Folding +@docs foldr, foldl + +# Special Folds +@docs sum, product, maximum, minimum, all, any, scanl + +# Sorting +@docs sort, sortBy, sortWith + +-} + +import Basics exposing (..) +import Maybe +import Maybe exposing ( Maybe(Just,Nothing) ) +import Native.List + + +{-| Add an element to the front of a list. Pronounced *cons*. + + 1 :: [2,3] == [1,2,3] + 1 :: [] == [1] +-} +(::) : a -> List a -> List a +(::) = + Native.List.cons + + +infixr 5 :: + + +{-| Extract the first element of a list. + + head [1,2,3] == Just 1 + head [] == Nothing +-} +head : List a -> Maybe a +head list = + case list of + x :: xs -> + Just x + + [] -> + Nothing + + +{-| Extract the rest of the list. + + tail [1,2,3] == Just [2,3] + tail [] == Nothing +-} +tail : List a -> Maybe (List a) +tail list = + case list of + x :: xs -> + Just xs + + [] -> + Nothing + + +{-| Determine if a list is empty. + + isEmpty [] == True +-} +isEmpty : List a -> Bool +isEmpty xs = + case xs of + [] -> + True + + _ -> + False + + +{-| Figure out whether a list contains a value. + + member 9 [1,2,3,4] == False + member 4 [1,2,3,4] == True +-} +member : a -> List a -> Bool +member x xs = + any (\a -> a == x) xs + + +{-| Apply a function to every element of a list. + + map sqrt [1,4,9] == [1,2,3] + + map not [True,False,True] == [False,True,False] +-} +map : (a -> b) -> List a -> List b +map f xs = + foldr (\x acc -> f x :: acc) [] xs + + +{-| Same as `map` but the function is also applied to the index of each +element (starting at zero). + + indexedMap (,) ["Tom","Sue","Bob"] == [ (0,"Tom"), (1,"Sue"), (2,"Bob") ] +-} +indexedMap : (Int -> a -> b) -> List a -> List b +indexedMap f xs = + map2 f (range 0 (length xs - 1)) xs + + +{-| Reduce a list from the left. + + foldl (::) [] [1,2,3] == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> List a -> b +foldl func acc list = + case list of + [] -> + acc + + x :: xs -> + foldl func (func x acc) xs + + +{-| Reduce a list from the right. + + foldr (+) 0 [1,2,3] == 6 +-} +foldr : (a -> b -> b) -> b -> List a -> b +foldr = + Native.List.foldr + + +{-| Reduce a list from the left, building up all of the intermediate results into a list. + + scanl (+) 0 [1,2,3,4] == [0,1,3,6,10] +-} +scanl : (a -> b -> b) -> b -> List a -> List b +scanl f b xs = + let + scan1 x accAcc = + case accAcc of + acc :: _ -> + f x acc :: accAcc + + [] -> + [] -- impossible + in + reverse (foldl scan1 [b] xs) + + +{-| Keep only elements that satisfy the predicate. + + filter isEven [1,2,3,4,5,6] == [2,4,6] +-} +filter : (a -> Bool) -> List a -> List a +filter pred xs = + let + conditionalCons front back = + if pred front then + front :: back + + else + back + in + foldr conditionalCons [] xs + + +{-| Apply a function that may succeed to all values in the list, but only keep +the successes. + + onlyTeens = + filterMap isTeen [3, 15, 12, 18, 24] == [15, 18] + + isTeen : Int -> Maybe Int + isTeen n = + if 13 <= n && n <= 19 then + Just n + + else + Nothing +-} +filterMap : (a -> Maybe b) -> List a -> List b +filterMap f xs = + foldr (maybeCons f) [] xs + + +maybeCons : (a -> Maybe b) -> a -> List b -> List b +maybeCons f mx xs = + case f mx of + Just x -> + x :: xs + + Nothing -> + xs + + +{-| Determine the length of a list. + + length [1,2,3] == 3 +-} +length : List a -> Int +length xs = + foldl (\_ i -> i + 1) 0 xs + + +{-| Reverse a list. + + reverse [1,2,3,4] == [4,3,2,1] +-} +reverse : List a -> List a +reverse list = + foldl (::) [] list + + +{-| Determine if all elements satisfy the predicate. + + all isEven [2,4] == True + all isEven [2,3] == False + all isEven [] == True +-} +all : (a -> Bool) -> List a -> Bool +all isOkay list = + not (any (not << isOkay) list) + + +{-| Determine if any elements satisfy the predicate. + + any isEven [2,3] == True + any isEven [1,3] == False + any isEven [] == False +-} +any : (a -> Bool) -> List a -> Bool +any isOkay list = + case list of + [] -> + False + + x :: xs -> + -- note: (isOkay x || any isOkay xs) would not get TCO + if isOkay x then + True + + else + any isOkay xs + + +{-| Put two lists together. + + append [1,1,2] [3,5,8] == [1,1,2,3,5,8] + append ['a','b'] ['c'] == ['a','b','c'] + +You can also use [the `(++)` operator](Basics#++) to append lists. +-} +append : List a -> List a -> List a +append xs ys = + case ys of + [] -> + xs + + _ -> + foldr (::) ys xs + + +{-| Concatenate a bunch of lists into a single list: + + concat [[1,2],[3],[4,5]] == [1,2,3,4,5] +-} +concat : List (List a) -> List a +concat lists = + foldr append [] lists + + +{-| Map a given function onto a list and flatten the resulting lists. + + concatMap f xs == concat (map f xs) +-} +concatMap : (a -> List b) -> List a -> List b +concatMap f list = + concat (map f list) + + +{-| Get the sum of the list elements. + + sum [1,2,3,4] == 10 +-} +sum : List number -> number +sum numbers = + foldl (+) 0 numbers + + +{-| Get the product of the list elements. + + product [1,2,3,4] == 24 +-} +product : List number -> number +product numbers = + foldl (*) 1 numbers + + +{-| Find the maximum element in a non-empty list. + + maximum [1,4,2] == Just 4 + maximum [] == Nothing +-} +maximum : List comparable -> Maybe comparable +maximum list = + case list of + x :: xs -> + Just (foldl max x xs) + + _ -> + Nothing + + +{-| Find the minimum element in a non-empty list. + + minimum [3,2,1] == Just 1 + minimum [] == Nothing +-} +minimum : List comparable -> Maybe comparable +minimum list = + case list of + x :: xs -> + Just (foldl min x xs) + + _ -> + Nothing + + +{-| Partition a list based on a predicate. The first list contains all values +that satisfy the predicate, and the second list contains all the value that do +not. + + partition (\x -> x < 3) [0,1,2,3,4,5] == ([0,1,2], [3,4,5]) + partition isEven [0,1,2,3,4,5] == ([0,2,4], [1,3,5]) +-} +partition : (a -> Bool) -> List a -> (List a, List a) +partition pred list = + let + step x (trues, falses) = + if pred x then + (x :: trues, falses) + + else + (trues, x :: falses) + in + foldr step ([],[]) list + + +{-| Combine two lists, combining them with the given function. +If one list is longer, the extra elements are dropped. + + map2 (+) [1,2,3] [1,2,3,4] == [2,4,6] + + map2 (,) [1,2,3] ['a','b'] == [ (1,'a'), (2,'b') ] + + pairs : List a -> List b -> List (a,b) + pairs lefts rights = + map2 (,) lefts rights +-} +map2 : (a -> b -> result) -> List a -> List b -> List result +map2 = + Native.List.map2 + + +{-|-} +map3 : (a -> b -> c -> result) -> List a -> List b -> List c -> List result +map3 = + Native.List.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result +map4 = + Native.List.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result +map5 = + Native.List.map5 + + +{-| Decompose a list of tuples into a tuple of lists. + + unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True]) +-} +unzip : List (a,b) -> (List a, List b) +unzip pairs = + let + step (x,y) (xs,ys) = + (x :: xs, y :: ys) + in + foldr step ([], []) pairs + + +{-| Places the given value between all members of the given list. + + intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"] +-} +intersperse : a -> List a -> List a +intersperse sep xs = + case xs of + [] -> + [] + + hd :: tl -> + let + step x rest = + sep :: x :: rest + + spersed = + foldr step [] tl + in + hd :: spersed + + +{-| Take the first *n* members of a list. + + take 2 [1,2,3,4] == [1,2] +-} +take : Int -> List a -> List a +take n list = + takeFast 0 n list + + +takeFast : Int -> Int -> List a -> List a +takeFast ctr n list = + if n <= 0 then + [] + else + case ( n, list ) of + ( _, [] ) -> + list + + ( 1, x :: _ ) -> + [ x ] + + ( 2, x :: y :: _ ) -> + [ x, y ] + + ( 3, x :: y :: z :: _ ) -> + [ x, y, z ] + + ( _, x :: y :: z :: w :: tl ) -> + if ctr > 1000 then + x :: y :: z :: w :: takeTailRec (n - 4) tl + else + x :: y :: z :: w :: takeFast (ctr + 1) (n - 4) tl + + _ -> + list + +takeTailRec : Int -> List a -> List a +takeTailRec n list = + reverse (takeReverse n list []) + + +takeReverse : Int -> List a -> List a -> List a +takeReverse n list taken = + if n <= 0 then + taken + else + case list of + [] -> + taken + + x :: xs -> + takeReverse (n - 1) xs (x :: taken) + + +{-| Drop the first *n* members of a list. + + drop 2 [1,2,3,4] == [3,4] +-} +drop : Int -> List a -> List a +drop n list = + if n <= 0 then + list + + else + case list of + [] -> + list + + x :: xs -> + drop (n-1) xs + + +{-| Create a list with only one element: + + singleton 1234 == [1234] + singleton "hi" == ["hi"] +-} +singleton : a -> List a +singleton value = + [value] + + +{-| Create a list with *n* copies of a value: + + repeat 3 (0,0) == [(0,0),(0,0),(0,0)] +-} +repeat : Int -> a -> List a +repeat n value = + repeatHelp [] n value + + +repeatHelp : List a -> Int -> a -> List a +repeatHelp result n value = + if n <= 0 then + result + + else + repeatHelp (value :: result) (n-1) value + + +{-| Create a list of numbers, every element increasing by one. +You give the lowest and highest number that should be in the list. + + range 3 6 == [3, 4, 5, 6] + range 3 3 == [3] + range 6 3 == [] +-} +range : Int -> Int -> List Int +range lo hi = + rangeHelp lo hi [] + + +rangeHelp : Int -> Int -> List Int -> List Int +rangeHelp lo hi list = + if lo <= hi then + rangeHelp lo (hi - 1) (hi :: list) + + else + list + + +{-| Sort values from lowest to highest + + sort [3,1,5] == [1,3,5] +-} +sort : List comparable -> List comparable +sort xs = + sortBy identity xs + + +{-| Sort values by a derived property. + + alice = { name="Alice", height=1.62 } + bob = { name="Bob" , height=1.85 } + chuck = { name="Chuck", height=1.76 } + + sortBy .name [chuck,alice,bob] == [alice,bob,chuck] + sortBy .height [chuck,alice,bob] == [alice,chuck,bob] + + sortBy String.length ["mouse","cat"] == ["cat","mouse"] +-} +sortBy : (a -> comparable) -> List a -> List a +sortBy = + Native.List.sortBy + + +{-| Sort values with a custom comparison function. + + sortWith flippedComparison [1,2,3,4,5] == [5,4,3,2,1] + + flippedComparison a b = + case compare a b of + LT -> GT + EQ -> EQ + GT -> LT + +This is also the most general sort function, allowing you +to define any other: `sort == sortWith compare` +-} +sortWith : (a -> a -> Order) -> List a -> List a +sortWith = + Native.List.sortWith diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm new file mode 100644 index 0000000..337a246 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm @@ -0,0 +1,157 @@ +module Maybe exposing + ( Maybe(Just,Nothing) + , andThen + , map, map2, map3, map4, map5 + , withDefault + ) + +{-| This library fills a bunch of important niches in Elm. A `Maybe` can help +you with optional arguments, error handling, and records with optional fields. + +# Definition +@docs Maybe + +# Common Helpers +@docs withDefault, map, map2, map3, map4, map5 + +# Chaining Maybes +@docs andThen +-} + +{-| Represent values that may or may not exist. It can be useful if you have a +record field that is only filled in sometimes. Or if a function takes a value +sometimes, but does not absolutely need it. + + -- A person, but maybe we do not know their age. + type alias Person = + { name : String + , age : Maybe Int + } + + tom = { name = "Tom", age = Just 42 } + sue = { name = "Sue", age = Nothing } +-} +type Maybe a + = Just a + | Nothing + + +{-| Provide a default value, turning an optional value into a normal +value. This comes in handy when paired with functions like +[`Dict.get`](Dict#get) which gives back a `Maybe`. + + withDefault 100 (Just 42) -- 42 + withDefault 100 Nothing -- 100 + + withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" + +-} +withDefault : a -> Maybe a -> a +withDefault default maybe = + case maybe of + Just value -> value + Nothing -> default + + +{-| Transform a `Maybe` value with a given function: + + map sqrt (Just 9) == Just 3 + map sqrt Nothing == Nothing +-} +map : (a -> b) -> Maybe a -> Maybe b +map f maybe = + case maybe of + Just value -> Just (f value) + Nothing -> Nothing + + +{-| Apply a function if all the arguments are `Just` a value. + + map2 (+) (Just 3) (Just 4) == Just 7 + map2 (+) (Just 3) Nothing == Nothing + map2 (+) Nothing (Just 4) == Nothing +-} +map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value +map2 func ma mb = + case (ma,mb) of + (Just a, Just b) -> + Just (func a b) + + _ -> + Nothing + + +{-|-} +map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value +map3 func ma mb mc = + case (ma,mb,mc) of + (Just a, Just b, Just c) -> + Just (func a b c) + + _ -> + Nothing + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value +map4 func ma mb mc md = + case (ma,mb,mc,md) of + (Just a, Just b, Just c, Just d) -> + Just (func a b c d) + + _ -> + Nothing + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value +map5 func ma mb mc md me = + case (ma,mb,mc,md,me) of + (Just a, Just b, Just c, Just d, Just e) -> + Just (func a b c d e) + + _ -> + Nothing + + +{-| Chain together many computations that may fail. It is helpful to see its +definition: + + andThen : (a -> Maybe b) -> Maybe a -> Maybe b + andThen callback maybe = + case maybe of + Just value -> + callback value + + Nothing -> + Nothing + +This means we only continue with the callback if things are going well. For +example, say you need to use (`head : List Int -> Maybe Int`) to get the +first month from a `List` and then make sure it is between 1 and 12: + + toValidMonth : Int -> Maybe Int + toValidMonth month = + if month >= 1 && month <= 12 then + Just month + else + Nothing + + getFirstMonth : List Int -> Maybe Int + getFirstMonth months = + head months + |> andThen toValidMonth + +If `head` fails and results in `Nothing` (because the `List` was `empty`), +this entire chain of operations will short-circuit and result in `Nothing`. +If `toValidMonth` results in `Nothing`, again the chain of computations +will result in `Nothing`. +-} +andThen : (a -> Maybe b) -> Maybe a -> Maybe b +andThen callback maybeValue = + case maybeValue of + Just value -> + callback value + + Nothing -> + Nothing diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js new file mode 100644 index 0000000..7ddd42d --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js @@ -0,0 +1,967 @@ +//import Native.List // + +var _elm_lang$core$Native_Array = function() { + +// A RRB-Tree has two distinct data types. +// Leaf -> "height" is always 0 +// "table" is an array of elements +// Node -> "height" is always greater than 0 +// "table" is an array of child nodes +// "lengths" is an array of accumulated lengths of the child nodes + +// M is the maximal table size. 32 seems fast. E is the allowed increase +// of search steps when concatting to find an index. Lower values will +// decrease balancing, but will increase search steps. +var M = 32; +var E = 2; + +// An empty array. +var empty = { + ctor: '_Array', + height: 0, + table: [] +}; + + +function get(i, array) +{ + if (i < 0 || i >= length(array)) + { + throw new Error( + 'Index ' + i + ' is out of range. Check the length of ' + + 'your array first or use getMaybe or getWithDefault.'); + } + return unsafeGet(i, array); +} + + +function unsafeGet(i, array) +{ + for (var x = array.height; x > 0; x--) + { + var slot = i >> (x * 5); + while (array.lengths[slot] <= i) + { + slot++; + } + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array = array.table[slot]; + } + return array.table[i]; +} + + +// Sets the value at the index i. Only the nodes leading to i will get +// copied and updated. +function set(i, item, array) +{ + if (i < 0 || length(array) <= i) + { + return array; + } + return unsafeSet(i, item, array); +} + + +function unsafeSet(i, item, array) +{ + array = nodeCopy(array); + + if (array.height === 0) + { + array.table[i] = item; + } + else + { + var slot = getSlot(i, array); + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array.table[slot] = unsafeSet(i, item, array.table[slot]); + } + return array; +} + + +function initialize(len, f) +{ + if (len <= 0) + { + return empty; + } + var h = Math.floor( Math.log(len) / Math.log(M) ); + return initialize_(f, h, 0, len); +} + +function initialize_(f, h, from, to) +{ + if (h === 0) + { + var table = new Array((to - from) % (M + 1)); + for (var i = 0; i < table.length; i++) + { + table[i] = f(from + i); + } + return { + ctor: '_Array', + height: 0, + table: table + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = initialize_(f, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +function fromList(list) +{ + if (list.ctor === '[]') + { + return empty; + } + + // Allocate M sized blocks (table) and write list elements to it. + var table = new Array(M); + var nodes = []; + var i = 0; + + while (list.ctor !== '[]') + { + table[i] = list._0; + list = list._1; + i++; + + // table is full, so we can push a leaf containing it into the + // next node. + if (i === M) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table + }; + fromListPush(leaf, nodes); + table = new Array(M); + i = 0; + } + } + + // Maybe there is something left on the table. + if (i > 0) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table.splice(0, i) + }; + fromListPush(leaf, nodes); + } + + // Go through all of the nodes and eventually push them into higher nodes. + for (var h = 0; h < nodes.length - 1; h++) + { + if (nodes[h].table.length > 0) + { + fromListPush(nodes[h], nodes); + } + } + + var head = nodes[nodes.length - 1]; + if (head.height > 0 && head.table.length === 1) + { + return head.table[0]; + } + else + { + return head; + } +} + +// Push a node into a higher node as a child. +function fromListPush(toPush, nodes) +{ + var h = toPush.height; + + // Maybe the node on this height does not exist. + if (nodes.length === h) + { + var node = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + nodes.push(node); + } + + nodes[h].table.push(toPush); + var len = length(toPush); + if (nodes[h].lengths.length > 0) + { + len += nodes[h].lengths[nodes[h].lengths.length - 1]; + } + nodes[h].lengths.push(len); + + if (nodes[h].table.length === M) + { + fromListPush(nodes[h], nodes); + nodes[h] = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + } +} + +// Pushes an item via push_ to the bottom right of a tree. +function push(item, a) +{ + var pushed = push_(item, a); + if (pushed !== null) + { + return pushed; + } + + var newTree = create(item, a.height); + return siblise(a, newTree); +} + +// Recursively tries to push an item to the bottom-right most +// tree possible. If there is no space left for the item, +// null will be returned. +function push_(item, a) +{ + // Handle resursion stop at leaf level. + if (a.height === 0) + { + if (a.table.length < M) + { + var newA = { + ctor: '_Array', + height: 0, + table: a.table.slice() + }; + newA.table.push(item); + return newA; + } + else + { + return null; + } + } + + // Recursively push + var pushed = push_(item, botRight(a)); + + // There was space in the bottom right tree, so the slot will + // be updated. + if (pushed !== null) + { + var newA = nodeCopy(a); + newA.table[newA.table.length - 1] = pushed; + newA.lengths[newA.lengths.length - 1]++; + return newA; + } + + // When there was no space left, check if there is space left + // for a new slot with a tree which contains only the item + // at the bottom. + if (a.table.length < M) + { + var newSlot = create(item, a.height - 1); + var newA = nodeCopy(a); + newA.table.push(newSlot); + newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot)); + return newA; + } + else + { + return null; + } +} + +// Converts an array into a list of elements. +function toList(a) +{ + return toList_(_elm_lang$core$Native_List.Nil, a); +} + +function toList_(list, a) +{ + for (var i = a.table.length - 1; i >= 0; i--) + { + list = + a.height === 0 + ? _elm_lang$core$Native_List.Cons(a.table[i], list) + : toList_(list, a.table[i]); + } + return list; +} + +// Maps a function over the elements of an array. +function map(f, a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? f(a.table[i]) + : map(f, a.table[i]); + } + return newA; +} + +// Maps a function over the elements with their index as first argument. +function indexedMap(f, a) +{ + return indexedMap_(f, a, 0); +} + +function indexedMap_(f, a, from) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? A2(f, from + i, a.table[i]) + : indexedMap_(f, a.table[i], i == 0 ? from : from + a.lengths[i - 1]); + } + return newA; +} + +function foldl(f, b, a) +{ + if (a.height === 0) + { + for (var i = 0; i < a.table.length; i++) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = 0; i < a.table.length; i++) + { + b = foldl(f, b, a.table[i]); + } + } + return b; +} + +function foldr(f, b, a) +{ + if (a.height === 0) + { + for (var i = a.table.length; i--; ) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = a.table.length; i--; ) + { + b = foldr(f, b, a.table[i]); + } + } + return b; +} + +// TODO: currently, it slices the right, then the left. This can be +// optimized. +function slice(from, to, a) +{ + if (from < 0) + { + from += length(a); + } + if (to < 0) + { + to += length(a); + } + return sliceLeft(from, sliceRight(to, a)); +} + +function sliceRight(to, a) +{ + if (to === length(a)) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(0, to); + return newA; + } + + // Slice the right recursively. + var right = getSlot(to, a); + var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (right === 0) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(0, right), + lengths: a.lengths.slice(0, right) + }; + if (sliced.table.length > 0) + { + newA.table[right] = sliced; + newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0); + } + return newA; +} + +function sliceLeft(from, a) +{ + if (from === 0) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(from, a.table.length + 1); + return newA; + } + + // Slice the left recursively. + var left = getSlot(from, a); + var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (left === a.table.length - 1) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(left, a.table.length + 1), + lengths: new Array(a.table.length - left) + }; + newA.table[0] = sliced; + var len = 0; + for (var i = 0; i < newA.table.length; i++) + { + len += length(newA.table[i]); + newA.lengths[i] = len; + } + + return newA; +} + +// Appends two trees. +function append(a,b) +{ + if (a.table.length === 0) + { + return b; + } + if (b.table.length === 0) + { + return a; + } + + var c = append_(a, b); + + // Check if both nodes can be crunshed together. + if (c[0].table.length + c[1].table.length <= M) + { + if (c[0].table.length === 0) + { + return c[1]; + } + if (c[1].table.length === 0) + { + return c[0]; + } + + // Adjust .table and .lengths + c[0].table = c[0].table.concat(c[1].table); + if (c[0].height > 0) + { + var len = length(c[0]); + for (var i = 0; i < c[1].lengths.length; i++) + { + c[1].lengths[i] += len; + } + c[0].lengths = c[0].lengths.concat(c[1].lengths); + } + + return c[0]; + } + + if (c[0].height > 0) + { + var toRemove = calcToRemove(a, b); + if (toRemove > E) + { + c = shuffle(c[0], c[1], toRemove); + } + } + + return siblise(c[0], c[1]); +} + +// Returns an array of two nodes; right and left. One node _may_ be empty. +function append_(a, b) +{ + if (a.height === 0 && b.height === 0) + { + return [a, b]; + } + + if (a.height !== 1 || b.height !== 1) + { + if (a.height === b.height) + { + a = nodeCopy(a); + b = nodeCopy(b); + var appended = append_(botRight(a), botLeft(b)); + + insertRight(a, appended[1]); + insertLeft(b, appended[0]); + } + else if (a.height > b.height) + { + a = nodeCopy(a); + var appended = append_(botRight(a), b); + + insertRight(a, appended[0]); + b = parentise(appended[1], appended[1].height + 1); + } + else + { + b = nodeCopy(b); + var appended = append_(a, botLeft(b)); + + var left = appended[0].table.length === 0 ? 0 : 1; + var right = left === 0 ? 1 : 0; + insertLeft(b, appended[left]); + a = parentise(appended[right], appended[right].height + 1); + } + } + + // Check if balancing is needed and return based on that. + if (a.table.length === 0 || b.table.length === 0) + { + return [a, b]; + } + + var toRemove = calcToRemove(a, b); + if (toRemove <= E) + { + return [a, b]; + } + return shuffle(a, b, toRemove); +} + +// Helperfunctions for append_. Replaces a child node at the side of the parent. +function insertRight(parent, node) +{ + var index = parent.table.length - 1; + parent.table[index] = node; + parent.lengths[index] = length(node); + parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0; +} + +function insertLeft(parent, node) +{ + if (node.table.length > 0) + { + parent.table[0] = node; + parent.lengths[0] = length(node); + + var len = length(parent.table[0]); + for (var i = 1; i < parent.lengths.length; i++) + { + len += length(parent.table[i]); + parent.lengths[i] = len; + } + } + else + { + parent.table.shift(); + for (var i = 1; i < parent.lengths.length; i++) + { + parent.lengths[i] = parent.lengths[i] - parent.lengths[0]; + } + parent.lengths.shift(); + } +} + +// Returns the extra search steps for E. Refer to the paper. +function calcToRemove(a, b) +{ + var subLengths = 0; + for (var i = 0; i < a.table.length; i++) + { + subLengths += a.table[i].table.length; + } + for (var i = 0; i < b.table.length; i++) + { + subLengths += b.table[i].table.length; + } + + var toRemove = a.table.length + b.table.length; + return toRemove - (Math.floor((subLengths - 1) / M) + 1); +} + +// get2, set2 and saveSlot are helpers for accessing elements over two arrays. +function get2(a, b, index) +{ + return index < a.length + ? a[index] + : b[index - a.length]; +} + +function set2(a, b, index, value) +{ + if (index < a.length) + { + a[index] = value; + } + else + { + b[index - a.length] = value; + } +} + +function saveSlot(a, b, index, slot) +{ + set2(a.table, b.table, index, slot); + + var l = (index === 0 || index === a.lengths.length) + ? 0 + : get2(a.lengths, a.lengths, index - 1); + + set2(a.lengths, b.lengths, index, l + length(slot)); +} + +// Creates a node or leaf with a given length at their arrays for perfomance. +// Is only used by shuffle. +function createNode(h, length) +{ + if (length < 0) + { + length = 0; + } + var a = { + ctor: '_Array', + height: h, + table: new Array(length) + }; + if (h > 0) + { + a.lengths = new Array(length); + } + return a; +} + +// Returns an array of two balanced nodes. +function shuffle(a, b, toRemove) +{ + var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove)); + var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove)); + + // Skip the slots with size M. More precise: copy the slot references + // to the new node + var read = 0; + while (get2(a.table, b.table, read).table.length % M === 0) + { + set2(newA.table, newB.table, read, get2(a.table, b.table, read)); + set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read)); + read++; + } + + // Pulling items from left to right, caching in a slot before writing + // it into the new nodes. + var write = read; + var slot = new createNode(a.height - 1, 0); + var from = 0; + + // If the current slot is still containing data, then there will be at + // least one more write, so we do not break this loop yet. + while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) + { + // Find out the max possible items for copying. + var source = get2(a.table, b.table, read); + var to = Math.min(M - slot.table.length, source.table.length); + + // Copy and adjust size table. + slot.table = slot.table.concat(source.table.slice(from, to)); + if (slot.height > 0) + { + var len = slot.lengths.length; + for (var i = len; i < len + to - from; i++) + { + slot.lengths[i] = length(slot.table[i]); + slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0); + } + } + + from += to; + + // Only proceed to next slots[i] if the current one was + // fully copied. + if (source.table.length <= to) + { + read++; from = 0; + } + + // Only create a new slot if the current one is filled up. + if (slot.table.length === M) + { + saveSlot(newA, newB, write, slot); + slot = createNode(a.height - 1, 0); + write++; + } + } + + // Cleanup after the loop. Copy the last slot into the new nodes. + if (slot.table.length > 0) + { + saveSlot(newA, newB, write, slot); + write++; + } + + // Shift the untouched slots to the left + while (read < a.table.length + b.table.length ) + { + saveSlot(newA, newB, write, get2(a.table, b.table, read)); + read++; + write++; + } + + return [newA, newB]; +} + +// Navigation functions +function botRight(a) +{ + return a.table[a.table.length - 1]; +} +function botLeft(a) +{ + return a.table[0]; +} + +// Copies a node for updating. Note that you should not use this if +// only updating only one of "table" or "lengths" for performance reasons. +function nodeCopy(a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice() + }; + if (a.height > 0) + { + newA.lengths = a.lengths.slice(); + } + return newA; +} + +// Returns how many items are in the tree. +function length(array) +{ + if (array.height === 0) + { + return array.table.length; + } + else + { + return array.lengths[array.lengths.length - 1]; + } +} + +// Calculates in which slot of "table" the item probably is, then +// find the exact slot via forward searching in "lengths". Returns the index. +function getSlot(i, a) +{ + var slot = i >> (5 * a.height); + while (a.lengths[slot] <= i) + { + slot++; + } + return slot; +} + +// Recursively creates a tree with a given height containing +// only the given item. +function create(item, h) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: [item] + }; + } + return { + ctor: '_Array', + height: h, + table: [create(item, h - 1)], + lengths: [1] + }; +} + +// Recursively creates a tree that contains the given tree. +function parentise(tree, h) +{ + if (h === tree.height) + { + return tree; + } + + return { + ctor: '_Array', + height: h, + table: [parentise(tree, h - 1)], + lengths: [length(tree)] + }; +} + +// Emphasizes blood brotherhood beneath two trees. +function siblise(a, b) +{ + return { + ctor: '_Array', + height: a.height + 1, + table: [a, b], + lengths: [length(a), length(a) + length(b)] + }; +} + +function toJSArray(a) +{ + var jsArray = new Array(length(a)); + toJSArray_(jsArray, 0, a); + return jsArray; +} + +function toJSArray_(jsArray, i, a) +{ + for (var t = 0; t < a.table.length; t++) + { + if (a.height === 0) + { + jsArray[i + t] = a.table[t]; + } + else + { + var inc = t === 0 ? 0 : a.lengths[t - 1]; + toJSArray_(jsArray, i + inc, a.table[t]); + } + } +} + +function fromJSArray(jsArray) +{ + if (jsArray.length === 0) + { + return empty; + } + var h = Math.floor(Math.log(jsArray.length) / Math.log(M)); + return fromJSArray_(jsArray, h, 0, jsArray.length); +} + +function fromJSArray_(jsArray, h, from, to) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: jsArray.slice(from, to) + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = fromJSArray_(jsArray, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i - 1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +return { + empty: empty, + fromList: fromList, + toList: toList, + initialize: F2(initialize), + append: F2(append), + push: F2(push), + slice: F3(slice), + get: F2(get), + set: F3(set), + map: F2(map), + indexedMap: F2(indexedMap), + foldl: F3(foldl), + foldr: F3(foldr), + length: length, + + toJSArray: toJSArray, + fromJSArray: fromJSArray +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js new file mode 100644 index 0000000..1d97bf3 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js @@ -0,0 +1,141 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Basics = function() { + +function div(a, b) +{ + return (a / b) | 0; +} +function rem(a, b) +{ + return a % b; +} +function mod(a, b) +{ + if (b === 0) + { + throw new Error('Cannot perform mod 0. Division by zero error.'); + } + var r = a % b; + var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r + b) : -mod(-a, -b)); + + return m === b ? 0 : m; +} +function logBase(base, n) +{ + return Math.log(n) / Math.log(base); +} +function negate(n) +{ + return -n; +} +function abs(n) +{ + return n < 0 ? -n : n; +} + +function min(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) < 0 ? a : b; +} +function max(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) > 0 ? a : b; +} +function clamp(lo, hi, n) +{ + return _elm_lang$core$Native_Utils.cmp(n, lo) < 0 + ? lo + : _elm_lang$core$Native_Utils.cmp(n, hi) > 0 + ? hi + : n; +} + +var ord = ['LT', 'EQ', 'GT']; + +function compare(x, y) +{ + return { ctor: ord[_elm_lang$core$Native_Utils.cmp(x, y) + 1] }; +} + +function xor(a, b) +{ + return a !== b; +} +function not(b) +{ + return !b; +} +function isInfinite(n) +{ + return n === Infinity || n === -Infinity; +} + +function truncate(n) +{ + return n | 0; +} + +function degrees(d) +{ + return d * Math.PI / 180; +} +function turns(t) +{ + return 2 * Math.PI * t; +} +function fromPolar(point) +{ + var r = point._0; + var t = point._1; + return _elm_lang$core$Native_Utils.Tuple2(r * Math.cos(t), r * Math.sin(t)); +} +function toPolar(point) +{ + var x = point._0; + var y = point._1; + return _elm_lang$core$Native_Utils.Tuple2(Math.sqrt(x * x + y * y), Math.atan2(y, x)); +} + +return { + div: F2(div), + rem: F2(rem), + mod: F2(mod), + + pi: Math.PI, + e: Math.E, + cos: Math.cos, + sin: Math.sin, + tan: Math.tan, + acos: Math.acos, + asin: Math.asin, + atan: Math.atan, + atan2: F2(Math.atan2), + + degrees: degrees, + turns: turns, + fromPolar: fromPolar, + toPolar: toPolar, + + sqrt: Math.sqrt, + logBase: F2(logBase), + negate: negate, + abs: abs, + min: F2(min), + max: F2(max), + clamp: F3(clamp), + compare: F2(compare), + + xor: F2(xor), + not: not, + + truncate: truncate, + ceiling: Math.ceil, + floor: Math.floor, + round: Math.round, + toFloat: function(x) { return x; }, + isNaN: isNaN, + isInfinite: isInfinite +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js new file mode 100644 index 0000000..a597f82 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js @@ -0,0 +1,13 @@ +var _elm_lang$core$Native_Bitwise = function() { + +return { + and: F2(function and(a, b) { return a & b; }), + or: F2(function or(a, b) { return a | b; }), + xor: F2(function xor(a, b) { return a ^ b; }), + complement: function complement(a) { return ~a; }, + shiftLeftBy: F2(function(offset, a) { return a << offset; }), + shiftRightBy: F2(function(offset, a) { return a >> offset; }), + shiftRightZfBy: F2(function(offset, a) { return a >>> offset; }) +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js new file mode 100644 index 0000000..56c2957 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js @@ -0,0 +1,14 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Char = function() { + +return { + fromCode: function(c) { return _elm_lang$core$Native_Utils.chr(String.fromCharCode(c)); }, + toCode: function(c) { return c.charCodeAt(0); }, + toUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toUpperCase()); }, + toLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLowerCase()); }, + toLocaleUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleUpperCase()); }, + toLocaleLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleLowerCase()); } +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js new file mode 100644 index 0000000..cb64193 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js @@ -0,0 +1,33 @@ +//import Result // + +var _elm_lang$core$Native_Date = function() { + +function fromString(str) +{ + var date = new Date(str); + return isNaN(date.getTime()) + ? _elm_lang$core$Result$Err('Unable to parse \'' + str + '\' as a date. Dates must be in the ISO 8601 format.') + : _elm_lang$core$Result$Ok(date); +} + +var dayTable = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; +var monthTable = + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + +return { + fromString: fromString, + year: function(d) { return d.getFullYear(); }, + month: function(d) { return { ctor: monthTable[d.getMonth()] }; }, + day: function(d) { return d.getDate(); }, + hour: function(d) { return d.getHours(); }, + minute: function(d) { return d.getMinutes(); }, + second: function(d) { return d.getSeconds(); }, + millisecond: function(d) { return d.getMilliseconds(); }, + toTime: function(d) { return d.getTime(); }, + fromTime: function(t) { return new Date(t); }, + dayOfWeek: function(d) { return { ctor: dayTable[d.getDay()] }; } +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js new file mode 100644 index 0000000..15ce1dc --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js @@ -0,0 +1,30 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Debug = function() { + +function log(tag, value) +{ + var msg = tag + ': ' + _elm_lang$core$Native_Utils.toString(value); + var process = process || {}; + if (process.stdout) + { + process.stdout.write(msg); + } + else + { + console.log(msg); + } + return value; +} + +function crash(message) +{ + throw new Error(message); +} + +return { + crash: crash, + log: F2(log) +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js new file mode 100644 index 0000000..61df889 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js @@ -0,0 +1,575 @@ +//import Maybe, Native.Array, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_Json = function() { + + +// CORE DECODERS + +function succeed(msg) +{ + return { + ctor: '', + tag: 'succeed', + msg: msg + }; +} + +function fail(msg) +{ + return { + ctor: '', + tag: 'fail', + msg: msg + }; +} + +function decodePrimitive(tag) +{ + return { + ctor: '', + tag: tag + }; +} + +function decodeContainer(tag, decoder) +{ + return { + ctor: '', + tag: tag, + decoder: decoder + }; +} + +function decodeNull(value) +{ + return { + ctor: '', + tag: 'null', + value: value + }; +} + +function decodeField(field, decoder) +{ + return { + ctor: '', + tag: 'field', + field: field, + decoder: decoder + }; +} + +function decodeIndex(index, decoder) +{ + return { + ctor: '', + tag: 'index', + index: index, + decoder: decoder + }; +} + +function decodeKeyValuePairs(decoder) +{ + return { + ctor: '', + tag: 'key-value', + decoder: decoder + }; +} + +function mapMany(f, decoders) +{ + return { + ctor: '', + tag: 'map-many', + func: f, + decoders: decoders + }; +} + +function andThen(callback, decoder) +{ + return { + ctor: '', + tag: 'andThen', + decoder: decoder, + callback: callback + }; +} + +function oneOf(decoders) +{ + return { + ctor: '', + tag: 'oneOf', + decoders: decoders + }; +} + + +// DECODING OBJECTS + +function map1(f, d1) +{ + return mapMany(f, [d1]); +} + +function map2(f, d1, d2) +{ + return mapMany(f, [d1, d2]); +} + +function map3(f, d1, d2, d3) +{ + return mapMany(f, [d1, d2, d3]); +} + +function map4(f, d1, d2, d3, d4) +{ + return mapMany(f, [d1, d2, d3, d4]); +} + +function map5(f, d1, d2, d3, d4, d5) +{ + return mapMany(f, [d1, d2, d3, d4, d5]); +} + +function map6(f, d1, d2, d3, d4, d5, d6) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6]); +} + +function map7(f, d1, d2, d3, d4, d5, d6, d7) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7]); +} + +function map8(f, d1, d2, d3, d4, d5, d6, d7, d8) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7, d8]); +} + + +// DECODE HELPERS + +function ok(value) +{ + return { tag: 'ok', value: value }; +} + +function badPrimitive(type, value) +{ + return { tag: 'primitive', type: type, value: value }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badField(field, nestedProblems) +{ + return { tag: 'field', field: field, rest: nestedProblems }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badOneOf(problems) +{ + return { tag: 'oneOf', problems: problems }; +} + +function bad(msg) +{ + return { tag: 'fail', msg: msg }; +} + +function badToString(problem) +{ + var context = '_'; + while (problem) + { + switch (problem.tag) + { + case 'primitive': + return 'Expecting ' + problem.type + + (context === '_' ? '' : ' at ' + context) + + ' but instead got: ' + jsToString(problem.value); + + case 'index': + context += '[' + problem.index + ']'; + problem = problem.rest; + break; + + case 'field': + context += '.' + problem.field; + problem = problem.rest; + break; + + case 'oneOf': + var problems = problem.problems; + for (var i = 0; i < problems.length; i++) + { + problems[i] = badToString(problems[i]); + } + return 'I ran into the following problems' + + (context === '_' ? '' : ' at ' + context) + + ':\n\n' + problems.join('\n'); + + case 'fail': + return 'I ran into a `fail` decoder' + + (context === '_' ? '' : ' at ' + context) + + ': ' + problem.msg; + } + } +} + +function jsToString(value) +{ + return value === undefined + ? 'undefined' + : JSON.stringify(value); +} + + +// DECODE + +function runOnString(decoder, string) +{ + var json; + try + { + json = JSON.parse(string); + } + catch (e) + { + return _elm_lang$core$Result$Err('Given an invalid JSON: ' + e.message); + } + return run(decoder, json); +} + +function run(decoder, value) +{ + var result = runHelp(decoder, value); + return (result.tag === 'ok') + ? _elm_lang$core$Result$Ok(result.value) + : _elm_lang$core$Result$Err(badToString(result)); +} + +function runHelp(decoder, value) +{ + switch (decoder.tag) + { + case 'bool': + return (typeof value === 'boolean') + ? ok(value) + : badPrimitive('a Bool', value); + + case 'int': + if (typeof value !== 'number') { + return badPrimitive('an Int', value); + } + + if (-2147483647 < value && value < 2147483647 && (value | 0) === value) { + return ok(value); + } + + if (isFinite(value) && !(value % 1)) { + return ok(value); + } + + return badPrimitive('an Int', value); + + case 'float': + return (typeof value === 'number') + ? ok(value) + : badPrimitive('a Float', value); + + case 'string': + return (typeof value === 'string') + ? ok(value) + : (value instanceof String) + ? ok(value + '') + : badPrimitive('a String', value); + + case 'null': + return (value === null) + ? ok(decoder.value) + : badPrimitive('null', value); + + case 'value': + return ok(value); + + case 'list': + if (!(value instanceof Array)) + { + return badPrimitive('a List', value); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i = value.length; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result) + } + list = _elm_lang$core$Native_List.Cons(result.value, list); + } + return ok(list); + + case 'array': + if (!(value instanceof Array)) + { + return badPrimitive('an Array', value); + } + + var len = value.length; + var array = new Array(len); + for (var i = len; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result); + } + array[i] = result.value; + } + return ok(_elm_lang$core$Native_Array.fromJSArray(array)); + + case 'maybe': + var result = runHelp(decoder.decoder, value); + return (result.tag === 'ok') + ? ok(_elm_lang$core$Maybe$Just(result.value)) + : ok(_elm_lang$core$Maybe$Nothing); + + case 'field': + var field = decoder.field; + if (typeof value !== 'object' || value === null || !(field in value)) + { + return badPrimitive('an object with a field named `' + field + '`', value); + } + + var result = runHelp(decoder.decoder, value[field]); + return (result.tag === 'ok') ? result : badField(field, result); + + case 'index': + var index = decoder.index; + if (!(value instanceof Array)) + { + return badPrimitive('an array', value); + } + if (index >= value.length) + { + return badPrimitive('a longer array. Need index ' + index + ' but there are only ' + value.length + ' entries', value); + } + + var result = runHelp(decoder.decoder, value[index]); + return (result.tag === 'ok') ? result : badIndex(index, result); + + case 'key-value': + if (typeof value !== 'object' || value === null || value instanceof Array) + { + return badPrimitive('an object', value); + } + + var keyValuePairs = _elm_lang$core$Native_List.Nil; + for (var key in value) + { + var result = runHelp(decoder.decoder, value[key]); + if (result.tag !== 'ok') + { + return badField(key, result); + } + var pair = _elm_lang$core$Native_Utils.Tuple2(key, result.value); + keyValuePairs = _elm_lang$core$Native_List.Cons(pair, keyValuePairs); + } + return ok(keyValuePairs); + + case 'map-many': + var answer = decoder.func; + var decoders = decoder.decoders; + for (var i = 0; i < decoders.length; i++) + { + var result = runHelp(decoders[i], value); + if (result.tag !== 'ok') + { + return result; + } + answer = answer(result.value); + } + return ok(answer); + + case 'andThen': + var result = runHelp(decoder.decoder, value); + return (result.tag !== 'ok') + ? result + : runHelp(decoder.callback(result.value), value); + + case 'oneOf': + var errors = []; + var temp = decoder.decoders; + while (temp.ctor !== '[]') + { + var result = runHelp(temp._0, value); + + if (result.tag === 'ok') + { + return result; + } + + errors.push(result); + + temp = temp._1; + } + return badOneOf(errors); + + case 'fail': + return bad(decoder.msg); + + case 'succeed': + return ok(decoder.msg); + } +} + + +// EQUALITY + +function equality(a, b) +{ + if (a === b) + { + return true; + } + + if (a.tag !== b.tag) + { + return false; + } + + switch (a.tag) + { + case 'succeed': + case 'fail': + return a.msg === b.msg; + + case 'bool': + case 'int': + case 'float': + case 'string': + case 'value': + return true; + + case 'null': + return a.value === b.value; + + case 'list': + case 'array': + case 'maybe': + case 'key-value': + return equality(a.decoder, b.decoder); + + case 'field': + return a.field === b.field && equality(a.decoder, b.decoder); + + case 'index': + return a.index === b.index && equality(a.decoder, b.decoder); + + case 'map-many': + if (a.func !== b.func) + { + return false; + } + return listEquality(a.decoders, b.decoders); + + case 'andThen': + return a.callback === b.callback && equality(a.decoder, b.decoder); + + case 'oneOf': + return listEquality(a.decoders, b.decoders); + } +} + +function listEquality(aDecoders, bDecoders) +{ + var len = aDecoders.length; + if (len !== bDecoders.length) + { + return false; + } + for (var i = 0; i < len; i++) + { + if (!equality(aDecoders[i], bDecoders[i])) + { + return false; + } + } + return true; +} + + +// ENCODE + +function encode(indentLevel, value) +{ + return JSON.stringify(value, null, indentLevel); +} + +function identity(value) +{ + return value; +} + +function encodeObject(keyValuePairs) +{ + var obj = {}; + while (keyValuePairs.ctor !== '[]') + { + var pair = keyValuePairs._0; + obj[pair._0] = pair._1; + keyValuePairs = keyValuePairs._1; + } + return obj; +} + +return { + encode: F2(encode), + runOnString: F2(runOnString), + run: F2(run), + + decodeNull: decodeNull, + decodePrimitive: decodePrimitive, + decodeContainer: F2(decodeContainer), + + decodeField: F2(decodeField), + decodeIndex: F2(decodeIndex), + + map1: F2(map1), + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + map6: F7(map6), + map7: F8(map7), + map8: F9(map8), + decodeKeyValuePairs: decodeKeyValuePairs, + + andThen: F2(andThen), + fail: fail, + succeed: succeed, + oneOf: oneOf, + + identity: identity, + encodeNull: null, + encodeArray: _elm_lang$core$Native_Array.toJSArray, + encodeList: _elm_lang$core$Native_List.toArray, + encodeObject: encodeObject, + + equality: equality +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js new file mode 100644 index 0000000..ccefb9c --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js @@ -0,0 +1,137 @@ +//import Native.Utils // + +var _elm_lang$core$Native_List = function() { + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { ctor: '::', _0: hd, _1: tl }; +} + +function fromArray(arr) +{ + var out = Nil; + for (var i = arr.length; i--; ) + { + out = Cons(arr[i], out); + } + return out; +} + +function toArray(xs) +{ + var out = []; + while (xs.ctor !== '[]') + { + out.push(xs._0); + xs = xs._1; + } + return out; +} + +function foldr(f, b, xs) +{ + var arr = toArray(xs); + var acc = b; + for (var i = arr.length; i--; ) + { + acc = A2(f, arr[i], acc); + } + return acc; +} + +function map2(f, xs, ys) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]') + { + arr.push(A2(f, xs._0, ys._0)); + xs = xs._1; + ys = ys._1; + } + return fromArray(arr); +} + +function map3(f, xs, ys, zs) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]' && zs.ctor !== '[]') + { + arr.push(A3(f, xs._0, ys._0, zs._0)); + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map4(f, ws, xs, ys, zs) +{ + var arr = []; + while ( ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A4(f, ws._0, xs._0, ys._0, zs._0)); + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map5(f, vs, ws, xs, ys, zs) +{ + var arr = []; + while ( vs.ctor !== '[]' + && ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A5(f, vs._0, ws._0, xs._0, ys._0, zs._0)); + vs = vs._1; + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function sortBy(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + return _elm_lang$core$Native_Utils.cmp(f(a), f(b)); + })); +} + +function sortWith(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + var ord = f(a)(b).ctor; + return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1; + })); +} + +return { + Nil: Nil, + Cons: Cons, + cons: F2(Cons), + toArray: toArray, + fromArray: fromArray, + + foldr: F3(foldr), + + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + sortBy: F2(sortBy), + sortWith: F2(sortWith) +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js new file mode 100644 index 0000000..bd6da19 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js @@ -0,0 +1,559 @@ +//import // + +var _elm_lang$core$Native_Platform = function() { + + +// PROGRAMS + +function program(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flags !== 'undefined') + { + throw new Error( + 'The `' + moduleName + '` module does not need flags.\n' + + 'Call ' + moduleName + '.worker() with no arguments and you should be all set!' + ); + } + + return initialize( + impl.init, + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function programWithFlags(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flagDecoder === 'undefined') + { + throw new Error( + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + ); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Err') + { + throw new Error( + moduleName + '.worker(...) was called with an unexpected argument.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0 + ); + } + + return initialize( + impl.init(result._0), + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function renderer(enqueue, _) +{ + return function(_) {}; +} + + +// HTML TO PROGRAM + +function htmlToProgram(vnode) +{ + var emptyBag = batch(_elm_lang$core$Native_List.Nil); + var noChange = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + emptyBag + ); + + return _elm_lang$virtual_dom$VirtualDom$program({ + init: noChange, + view: function(model) { return main; }, + update: F2(function(msg, model) { return noChange; }), + subscriptions: function (model) { return emptyBag; } + }); +} + + +// INITIALIZE A PROGRAM + +function initialize(init, update, subscriptions, renderer) +{ + // ambient state + var managers = {}; + var updateView; + + // init and update state in main process + var initApp = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var model = init._0; + updateView = renderer(enqueue, model); + var cmds = init._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + + function onMessage(msg, model) + { + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var results = A2(update, msg, model); + model = results._0; + updateView(model); + var cmds = results._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + } + + var mainProcess = spawnLoop(initApp, onMessage); + + function enqueue(msg) + { + _elm_lang$core$Native_Scheduler.rawSend(mainProcess, msg); + } + + var ports = setupEffects(managers, enqueue); + + return ports ? { ports: ports } : {}; +} + + +// EFFECT MANAGERS + +var effectManagers = {}; + +function setupEffects(managers, callback) +{ + var ports; + + // setup all necessary effect managers + for (var key in effectManagers) + { + var manager = effectManagers[key]; + + if (manager.isForeign) + { + ports = ports || {}; + ports[key] = manager.tag === 'cmd' + ? setupOutgoingPort(key) + : setupIncomingPort(key, callback); + } + + managers[key] = makeManager(manager, callback); + } + + return ports; +} + +function makeManager(info, callback) +{ + var router = { + main: callback, + self: undefined + }; + + var tag = info.tag; + var onEffects = info.onEffects; + var onSelfMsg = info.onSelfMsg; + + function onMessage(msg, state) + { + if (msg.ctor === 'self') + { + return A3(onSelfMsg, router, msg._0, state); + } + + var fx = msg._0; + switch (tag) + { + case 'cmd': + return A3(onEffects, router, fx.cmds, state); + + case 'sub': + return A3(onEffects, router, fx.subs, state); + + case 'fx': + return A4(onEffects, router, fx.cmds, fx.subs, state); + } + } + + var process = spawnLoop(info.init, onMessage); + router.self = process; + return process; +} + +function sendToApp(router, msg) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + router.main(msg); + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sendToSelf(router, msg) +{ + return A2(_elm_lang$core$Native_Scheduler.send, router.self, { + ctor: 'self', + _0: msg + }); +} + + +// HELPER for STATEFUL LOOPS + +function spawnLoop(init, onMessage) +{ + var andThen = _elm_lang$core$Native_Scheduler.andThen; + + function loop(state) + { + var handleMsg = _elm_lang$core$Native_Scheduler.receive(function(msg) { + return onMessage(msg, state); + }); + return A2(andThen, loop, handleMsg); + } + + var task = A2(andThen, loop, init); + + return _elm_lang$core$Native_Scheduler.rawSpawn(task); +} + + +// BAGS + +function leaf(home) +{ + return function(value) + { + return { + type: 'leaf', + home: home, + value: value + }; + }; +} + +function batch(list) +{ + return { + type: 'node', + branches: list + }; +} + +function map(tagger, bag) +{ + return { + type: 'map', + tagger: tagger, + tree: bag + } +} + + +// PIPE BAGS INTO EFFECT MANAGERS + +function dispatchEffects(managers, cmdBag, subBag) +{ + var effectsDict = {}; + gatherEffects(true, cmdBag, effectsDict, null); + gatherEffects(false, subBag, effectsDict, null); + + for (var home in managers) + { + var fx = home in effectsDict + ? effectsDict[home] + : { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + + _elm_lang$core$Native_Scheduler.rawSend(managers[home], { ctor: 'fx', _0: fx }); + } +} + +function gatherEffects(isCmd, bag, effectsDict, taggers) +{ + switch (bag.type) + { + case 'leaf': + var home = bag.home; + var effect = toEffect(isCmd, home, taggers, bag.value); + effectsDict[home] = insert(isCmd, effect, effectsDict[home]); + return; + + case 'node': + var list = bag.branches; + while (list.ctor !== '[]') + { + gatherEffects(isCmd, list._0, effectsDict, taggers); + list = list._1; + } + return; + + case 'map': + gatherEffects(isCmd, bag.tree, effectsDict, { + tagger: bag.tagger, + rest: taggers + }); + return; + } +} + +function toEffect(isCmd, home, taggers, value) +{ + function applyTaggers(x) + { + var temp = taggers; + while (temp) + { + x = temp.tagger(x); + temp = temp.rest; + } + return x; + } + + var map = isCmd + ? effectManagers[home].cmdMap + : effectManagers[home].subMap; + + return A2(map, applyTaggers, value) +} + +function insert(isCmd, newEffect, effects) +{ + effects = effects || { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + if (isCmd) + { + effects.cmds = _elm_lang$core$Native_List.Cons(newEffect, effects.cmds); + return effects; + } + effects.subs = _elm_lang$core$Native_List.Cons(newEffect, effects.subs); + return effects; +} + + +// PORTS + +function checkPortName(name) +{ + if (name in effectManagers) + { + throw new Error('There can only be one port named `' + name + '`, but your program has multiple.'); + } +} + + +// OUTGOING PORTS + +function outgoingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'cmd', + cmdMap: outgoingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var outgoingPortMap = F2(function cmdMap(tagger, value) { + return value; +}); + +function setupOutgoingPort(name) +{ + var subs = []; + var converter = effectManagers[name].converter; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function onEffects(router, cmdList, state) + { + while (cmdList.ctor !== '[]') + { + // grab a separate reference to subs in case unsubscribe is called + var currentSubs = subs; + var value = converter(cmdList._0); + for (var i = 0; i < currentSubs.length; i++) + { + currentSubs[i](value); + } + cmdList = cmdList._1; + } + return init; + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function subscribe(callback) + { + subs.push(callback); + } + + function unsubscribe(callback) + { + // copy subs into a new array in case unsubscribe is called within a + // subscribed callback + subs = subs.slice(); + var index = subs.indexOf(callback); + if (index >= 0) + { + subs.splice(index, 1); + } + } + + return { + subscribe: subscribe, + unsubscribe: unsubscribe + }; +} + + +// INCOMING PORTS + +function incomingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'sub', + subMap: incomingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var incomingPortMap = F2(function subMap(tagger, finalTagger) +{ + return function(value) + { + return tagger(finalTagger(value)); + }; +}); + +function setupIncomingPort(name, callback) +{ + var sentBeforeInit = []; + var subs = _elm_lang$core$Native_List.Nil; + var converter = effectManagers[name].converter; + var currentOnEffects = preInitOnEffects; + var currentSend = preInitSend; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function preInitOnEffects(router, subList, state) + { + var postInitResult = postInitOnEffects(router, subList, state); + + for(var i = 0; i < sentBeforeInit.length; i++) + { + postInitSend(sentBeforeInit[i]); + } + + sentBeforeInit = null; // to release objects held in queue + currentSend = postInitSend; + currentOnEffects = postInitOnEffects; + return postInitResult; + } + + function postInitOnEffects(router, subList, state) + { + subs = subList; + return init; + } + + function onEffects(router, subList, state) + { + return currentOnEffects(router, subList, state); + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function preInitSend(value) + { + sentBeforeInit.push(value); + } + + function postInitSend(value) + { + var temp = subs; + while (temp.ctor !== '[]') + { + callback(temp._0(value)); + temp = temp._1; + } + } + + function send(incomingValue) + { + var result = A2(_elm_lang$core$Json_Decode$decodeValue, converter, incomingValue); + if (result.ctor === 'Err') + { + throw new Error('Trying to send an unexpected type of value through port `' + name + '`:\n' + result._0); + } + + currentSend(result._0); + } + + return { send: send }; +} + +return { + // routers + sendToApp: F2(sendToApp), + sendToSelf: F2(sendToSelf), + + // global setup + effectManagers: effectManagers, + outgoingPort: outgoingPort, + incomingPort: incomingPort, + + htmlToProgram: htmlToProgram, + program: program, + programWithFlags: programWithFlags, + initialize: initialize, + + // effect bags + leaf: leaf, + batch: batch, + map: F2(map) +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js new file mode 100644 index 0000000..d3cc0dd --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js @@ -0,0 +1,119 @@ +//import Maybe, Native.List // + +var _elm_lang$core$Native_Regex = function() { + +function escape(str) +{ + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +} +function caseInsensitive(re) +{ + return new RegExp(re.source, 'gi'); +} +function regex(raw) +{ + return new RegExp(raw, 'g'); +} + +function contains(re, string) +{ + return string.match(re) !== null; +} + +function find(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var out = []; + var number = 0; + var string = str; + var lastIndex = re.lastIndex; + var prevLastIndex = -1; + var result; + while (number++ < n && (result = re.exec(string))) + { + if (prevLastIndex === re.lastIndex) break; + var i = result.length - 1; + var subs = new Array(i); + while (i > 0) + { + var submatch = result[i]; + subs[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + out.push({ + match: result[0], + submatches: _elm_lang$core$Native_List.fromArray(subs), + index: result.index, + number: number + }); + prevLastIndex = re.lastIndex; + } + re.lastIndex = lastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +function replace(n, re, replacer, string) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var count = 0; + function jsReplacer(match) + { + if (count++ >= n) + { + return match; + } + var i = arguments.length - 3; + var submatches = new Array(i); + while (i > 0) + { + var submatch = arguments[i]; + submatches[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + return replacer({ + match: match, + submatches: _elm_lang$core$Native_List.fromArray(submatches), + index: arguments[arguments.length - 2], + number: count + }); + } + return string.replace(re, jsReplacer); +} + +function split(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + if (n === Infinity) + { + return _elm_lang$core$Native_List.fromArray(str.split(re)); + } + var string = str; + var result; + var out = []; + var start = re.lastIndex; + var restoreLastIndex = re.lastIndex; + while (n--) + { + if (!(result = re.exec(string))) break; + out.push(string.slice(start, result.index)); + start = re.lastIndex; + } + out.push(string.slice(start)); + re.lastIndex = restoreLastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +return { + regex: regex, + caseInsensitive: caseInsensitive, + escape: escape, + + contains: F2(contains), + find: F3(find), + replace: F4(replace), + split: F3(split) +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js new file mode 100644 index 0000000..00f8259 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js @@ -0,0 +1,281 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Scheduler = function() { + +var MAX_STEPS = 10000; + + +// TASKS + +function succeed(value) +{ + return { + ctor: '_Task_succeed', + value: value + }; +} + +function fail(error) +{ + return { + ctor: '_Task_fail', + value: error + }; +} + +function nativeBinding(callback) +{ + return { + ctor: '_Task_nativeBinding', + callback: callback, + cancel: null + }; +} + +function andThen(callback, task) +{ + return { + ctor: '_Task_andThen', + callback: callback, + task: task + }; +} + +function onError(callback, task) +{ + return { + ctor: '_Task_onError', + callback: callback, + task: task + }; +} + +function receive(callback) +{ + return { + ctor: '_Task_receive', + callback: callback + }; +} + + +// PROCESSES + +function rawSpawn(task) +{ + var process = { + ctor: '_Process', + id: _elm_lang$core$Native_Utils.guid(), + root: task, + stack: null, + mailbox: [] + }; + + enqueue(process); + + return process; +} + +function spawn(task) +{ + return nativeBinding(function(callback) { + var process = rawSpawn(task); + callback(succeed(process)); + }); +} + +function rawSend(process, msg) +{ + process.mailbox.push(msg); + enqueue(process); +} + +function send(process, msg) +{ + return nativeBinding(function(callback) { + rawSend(process, msg); + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function kill(process) +{ + return nativeBinding(function(callback) { + var root = process.root; + if (root.ctor === '_Task_nativeBinding' && root.cancel) + { + root.cancel(); + } + + process.root = null; + + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sleep(time) +{ + return nativeBinding(function(callback) { + var id = setTimeout(function() { + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }, time); + + return function() { clearTimeout(id); }; + }); +} + + +// STEP PROCESSES + +function step(numSteps, process) +{ + while (numSteps < MAX_STEPS) + { + var ctor = process.root.ctor; + + if (ctor === '_Task_succeed') + { + while (process.stack && process.stack.ctor === '_Task_onError') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_fail') + { + while (process.stack && process.stack.ctor === '_Task_andThen') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_andThen') + { + process.stack = { + ctor: '_Task_andThen', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_onError') + { + process.stack = { + ctor: '_Task_onError', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_nativeBinding') + { + process.root.cancel = process.root.callback(function(newRoot) { + process.root = newRoot; + enqueue(process); + }); + + break; + } + + if (ctor === '_Task_receive') + { + var mailbox = process.mailbox; + if (mailbox.length === 0) + { + break; + } + + process.root = process.root.callback(mailbox.shift()); + ++numSteps; + continue; + } + + throw new Error(ctor); + } + + if (numSteps < MAX_STEPS) + { + return numSteps + 1; + } + enqueue(process); + + return numSteps; +} + + +// WORK QUEUE + +var working = false; +var workQueue = []; + +function enqueue(process) +{ + workQueue.push(process); + + if (!working) + { + setTimeout(work, 0); + working = true; + } +} + +function work() +{ + var numSteps = 0; + var process; + while (numSteps < MAX_STEPS && (process = workQueue.shift())) + { + if (process.root) + { + numSteps = step(numSteps, process); + } + } + if (!process) + { + working = false; + return; + } + setTimeout(work, 0); +} + + +return { + succeed: succeed, + fail: fail, + nativeBinding: nativeBinding, + andThen: F2(andThen), + onError: F2(onError), + receive: receive, + + spawn: spawn, + kill: kill, + sleep: sleep, + send: F2(send), + + rawSpawn: rawSpawn, + rawSend: rawSend +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js new file mode 100644 index 0000000..3a21c76 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js @@ -0,0 +1,339 @@ +//import Maybe, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_String = function() { + +function isEmpty(str) +{ + return str.length === 0; +} +function cons(chr, str) +{ + return chr + str; +} +function uncons(str) +{ + var hd = str[0]; + if (hd) + { + return _elm_lang$core$Maybe$Just(_elm_lang$core$Native_Utils.Tuple2(_elm_lang$core$Native_Utils.chr(hd), str.slice(1))); + } + return _elm_lang$core$Maybe$Nothing; +} +function append(a, b) +{ + return a + b; +} +function concat(strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(''); +} +function length(str) +{ + return str.length; +} +function map(f, str) +{ + var out = str.split(''); + for (var i = out.length; i--; ) + { + out[i] = f(_elm_lang$core$Native_Utils.chr(out[i])); + } + return out.join(''); +} +function filter(pred, str) +{ + return str.split('').map(_elm_lang$core$Native_Utils.chr).filter(pred).join(''); +} +function reverse(str) +{ + return str.split('').reverse().join(''); +} +function foldl(f, b, str) +{ + var len = str.length; + for (var i = 0; i < len; ++i) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function foldr(f, b, str) +{ + for (var i = str.length; i--; ) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function split(sep, str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(sep)); +} +function join(sep, strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(sep); +} +function repeat(n, str) +{ + var result = ''; + while (n > 0) + { + if (n & 1) + { + result += str; + } + n >>= 1, str += str; + } + return result; +} +function slice(start, end, str) +{ + return str.slice(start, end); +} +function left(n, str) +{ + return n < 1 ? '' : str.slice(0, n); +} +function right(n, str) +{ + return n < 1 ? '' : str.slice(-n); +} +function dropLeft(n, str) +{ + return n < 1 ? str : str.slice(n); +} +function dropRight(n, str) +{ + return n < 1 ? str : str.slice(0, -n); +} +function pad(n, chr, str) +{ + var half = (n - str.length) / 2; + return repeat(Math.ceil(half), chr) + str + repeat(half | 0, chr); +} +function padRight(n, chr, str) +{ + return str + repeat(n - str.length, chr); +} +function padLeft(n, chr, str) +{ + return repeat(n - str.length, chr) + str; +} + +function trim(str) +{ + return str.trim(); +} +function trimLeft(str) +{ + return str.replace(/^\s+/, ''); +} +function trimRight(str) +{ + return str.replace(/\s+$/, ''); +} + +function words(str) +{ + return _elm_lang$core$Native_List.fromArray(str.trim().split(/\s+/g)); +} +function lines(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(/\r\n|\r|\n/g)); +} + +function toUpper(str) +{ + return str.toUpperCase(); +} +function toLower(str) +{ + return str.toLowerCase(); +} + +function any(pred, str) +{ + for (var i = str.length; i--; ) + { + if (pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return true; + } + } + return false; +} +function all(pred, str) +{ + for (var i = str.length; i--; ) + { + if (!pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return false; + } + } + return true; +} + +function contains(sub, str) +{ + return str.indexOf(sub) > -1; +} +function startsWith(sub, str) +{ + return str.indexOf(sub) === 0; +} +function endsWith(sub, str) +{ + return str.length >= sub.length && + str.lastIndexOf(sub) === str.length - sub.length; +} +function indexes(sub, str) +{ + var subLen = sub.length; + + if (subLen < 1) + { + return _elm_lang$core$Native_List.Nil; + } + + var i = 0; + var is = []; + + while ((i = str.indexOf(sub, i)) > -1) + { + is.push(i); + i = i + subLen; + } + + return _elm_lang$core$Native_List.fromArray(is); +} + + +function toInt(s) +{ + var len = s.length; + + // if empty + if (len === 0) + { + return intErr(s); + } + + // if hex + var c = s[0]; + if (c === '0' && s[1] === 'x') + { + for (var i = 2; i < len; ++i) + { + var c = s[i]; + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) + { + continue; + } + return intErr(s); + } + return _elm_lang$core$Result$Ok(parseInt(s, 16)); + } + + // is decimal + if (c > '9' || (c < '0' && c !== '-' && c !== '+')) + { + return intErr(s); + } + for (var i = 1; i < len; ++i) + { + var c = s[i]; + if (c < '0' || '9' < c) + { + return intErr(s); + } + } + + return _elm_lang$core$Result$Ok(parseInt(s, 10)); +} + +function intErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to an Int"); +} + + +function toFloat(s) +{ + // check if it is a hex, octal, or binary number + if (s.length === 0 || /[\sxbo]/.test(s)) + { + return floatErr(s); + } + var n = +s; + // faster isNaN check + return n === n ? _elm_lang$core$Result$Ok(n) : floatErr(s); +} + +function floatErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to a Float"); +} + + +function toList(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split('').map(_elm_lang$core$Native_Utils.chr)); +} +function fromList(chars) +{ + return _elm_lang$core$Native_List.toArray(chars).join(''); +} + +return { + isEmpty: isEmpty, + cons: F2(cons), + uncons: uncons, + append: F2(append), + concat: concat, + length: length, + map: F2(map), + filter: F2(filter), + reverse: reverse, + foldl: F3(foldl), + foldr: F3(foldr), + + split: F2(split), + join: F2(join), + repeat: F2(repeat), + + slice: F3(slice), + left: F2(left), + right: F2(right), + dropLeft: F2(dropLeft), + dropRight: F2(dropRight), + + pad: F3(pad), + padLeft: F3(padLeft), + padRight: F3(padRight), + + trim: trim, + trimLeft: trimLeft, + trimRight: trimRight, + + words: words, + lines: lines, + + toUpper: toUpper, + toLower: toLower, + + any: F2(any), + all: F2(all), + + contains: F2(contains), + startsWith: F2(startsWith), + endsWith: F2(endsWith), + indexes: F2(indexes), + + toInt: toInt, + toFloat: toFloat, + toList: toList, + fromList: fromList +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js new file mode 100644 index 0000000..6b665ea --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js @@ -0,0 +1,27 @@ +//import Native.Scheduler // + +var _elm_lang$core$Native_Time = function() { + +var now = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + callback(_elm_lang$core$Native_Scheduler.succeed(Date.now())); +}); + +function setInterval_(interval, task) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var id = setInterval(function() { + _elm_lang$core$Native_Scheduler.rawSpawn(task); + }, interval); + + return function() { clearInterval(id); }; + }); +} + +return { + now: now, + setInterval_: F2(setInterval_) +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js new file mode 100644 index 0000000..20aed5f --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js @@ -0,0 +1,488 @@ +//import // + +var _elm_lang$core$Native_Utils = function() { + +// COMPARISONS + +function eq(x, y) +{ + var stack = []; + var isEqual = eqHelp(x, y, 0, stack); + var pair; + while (isEqual && (pair = stack.pop())) + { + isEqual = eqHelp(pair.x, pair.y, 0, stack); + } + return isEqual; +} + + +function eqHelp(x, y, depth, stack) +{ + if (depth > 100) + { + stack.push({ x: x, y: y }); + return true; + } + + if (x === y) + { + return true; + } + + if (typeof x !== 'object') + { + if (typeof x === 'function') + { + throw new Error( + 'Trying to use `(==)` on functions. There is no way to know if functions are "the same" in the Elm sense.' + + ' Read more about this at http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#==' + + ' which describes why it is this way and what the better version will look like.' + ); + } + return false; + } + + if (x === null || y === null) + { + return false + } + + if (x instanceof Date) + { + return x.getTime() === y.getTime(); + } + + if (!('ctor' in x)) + { + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; + } + + // convert Dicts and Sets to lists + if (x.ctor === 'RBNode_elm_builtin' || x.ctor === 'RBEmpty_elm_builtin') + { + x = _elm_lang$core$Dict$toList(x); + y = _elm_lang$core$Dict$toList(y); + } + if (x.ctor === 'Set_elm_builtin') + { + x = _elm_lang$core$Set$toList(x); + y = _elm_lang$core$Set$toList(y); + } + + // check if lists are equal without recursion + if (x.ctor === '::') + { + var a = x; + var b = y; + while (a.ctor === '::' && b.ctor === '::') + { + if (!eqHelp(a._0, b._0, depth + 1, stack)) + { + return false; + } + a = a._1; + b = b._1; + } + return a.ctor === b.ctor; + } + + // check if Arrays are equal + if (x.ctor === '_Array') + { + var xs = _elm_lang$core$Native_Array.toJSArray(x); + var ys = _elm_lang$core$Native_Array.toJSArray(y); + if (xs.length !== ys.length) + { + return false; + } + for (var i = 0; i < xs.length; i++) + { + if (!eqHelp(xs[i], ys[i], depth + 1, stack)) + { + return false; + } + } + return true; + } + + if (!eqHelp(x.ctor, y.ctor, depth + 1, stack)) + { + return false; + } + + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; +} + +// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on +// the particular integer values assigned to LT, EQ, and GT. + +var LT = -1, EQ = 0, GT = 1; + +function cmp(x, y) +{ + if (typeof x !== 'object') + { + return x === y ? EQ : x < y ? LT : GT; + } + + if (x instanceof String) + { + var a = x.valueOf(); + var b = y.valueOf(); + return a === b ? EQ : a < b ? LT : GT; + } + + if (x.ctor === '::' || x.ctor === '[]') + { + while (x.ctor === '::' && y.ctor === '::') + { + var ord = cmp(x._0, y._0); + if (ord !== EQ) + { + return ord; + } + x = x._1; + y = y._1; + } + return x.ctor === y.ctor ? EQ : x.ctor === '[]' ? LT : GT; + } + + if (x.ctor.slice(0, 6) === '_Tuple') + { + var ord; + var n = x.ctor.slice(6) - 0; + var err = 'cannot compare tuples with more than 6 elements.'; + if (n === 0) return EQ; + if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord; + if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord; + if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord; + if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord; + if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord; + if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord; + if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } } + return EQ; + } + + throw new Error( + 'Comparison error: comparison is only defined on ints, ' + + 'floats, times, chars, strings, lists of comparable values, ' + + 'and tuples of comparable values.' + ); +} + + +// COMMON VALUES + +var Tuple0 = { + ctor: '_Tuple0' +}; + +function Tuple2(x, y) +{ + return { + ctor: '_Tuple2', + _0: x, + _1: y + }; +} + +function chr(c) +{ + return new String(c); +} + + +// GUID + +var count = 0; +function guid(_) +{ + return count++; +} + + +// RECORDS + +function update(oldRecord, updatedFields) +{ + var newRecord = {}; + + for (var key in oldRecord) + { + newRecord[key] = oldRecord[key]; + } + + for (var key in updatedFields) + { + newRecord[key] = updatedFields[key]; + } + + return newRecord; +} + + +//// LIST STUFF //// + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { + ctor: '::', + _0: hd, + _1: tl + }; +} + +function append(xs, ys) +{ + // append Strings + if (typeof xs === 'string') + { + return xs + ys; + } + + // append Lists + if (xs.ctor === '[]') + { + return ys; + } + var root = Cons(xs._0, Nil); + var curr = root; + xs = xs._1; + while (xs.ctor !== '[]') + { + curr._1 = Cons(xs._0, Nil); + xs = xs._1; + curr = curr._1; + } + curr._1 = ys; + return root; +} + + +// CRASHES + +function crash(moduleName, region) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '` ' + regionToString(region) + '\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function crashCase(moduleName, region, value) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '`\n\n' + + 'This was caused by the `case` expression ' + regionToString(region) + '.\n' + + 'One of the branches ended with a crash and the following value got through:\n\n ' + toString(value) + '\n\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function regionToString(region) +{ + if (region.start.line == region.end.line) + { + return 'on line ' + region.start.line; + } + return 'between lines ' + region.start.line + ' and ' + region.end.line; +} + + +// TO STRING + +function toString(v) +{ + var type = typeof v; + if (type === 'function') + { + return ''; + } + + if (type === 'boolean') + { + return v ? 'True' : 'False'; + } + + if (type === 'number') + { + return v + ''; + } + + if (v instanceof String) + { + return '\'' + addSlashes(v, true) + '\''; + } + + if (type === 'string') + { + return '"' + addSlashes(v, false) + '"'; + } + + if (v === null) + { + return 'null'; + } + + if (type === 'object' && 'ctor' in v) + { + var ctorStarter = v.ctor.substring(0, 5); + + if (ctorStarter === '_Tupl') + { + var output = []; + for (var k in v) + { + if (k === 'ctor') continue; + output.push(toString(v[k])); + } + return '(' + output.join(',') + ')'; + } + + if (ctorStarter === '_Task') + { + return '' + } + + if (v.ctor === '_Array') + { + var list = _elm_lang$core$Array$toList(v); + return 'Array.fromList ' + toString(list); + } + + if (v.ctor === '') + { + return ''; + } + + if (v.ctor === '_Process') + { + return ''; + } + + if (v.ctor === '::') + { + var output = '[' + toString(v._0); + v = v._1; + while (v.ctor === '::') + { + output += ',' + toString(v._0); + v = v._1; + } + return output + ']'; + } + + if (v.ctor === '[]') + { + return '[]'; + } + + if (v.ctor === 'Set_elm_builtin') + { + return 'Set.fromList ' + toString(_elm_lang$core$Set$toList(v)); + } + + if (v.ctor === 'RBNode_elm_builtin' || v.ctor === 'RBEmpty_elm_builtin') + { + return 'Dict.fromList ' + toString(_elm_lang$core$Dict$toList(v)); + } + + var output = ''; + for (var i in v) + { + if (i === 'ctor') continue; + var str = toString(v[i]); + var c0 = str[0]; + var parenless = c0 === '{' || c0 === '(' || c0 === '<' || c0 === '"' || str.indexOf(' ') < 0; + output += ' ' + (parenless ? str : '(' + str + ')'); + } + return v.ctor + output; + } + + if (type === 'object') + { + if (v instanceof Date) + { + return '<' + v.toString() + '>'; + } + + if (v.elm_web_socket) + { + return ''; + } + + var output = []; + for (var k in v) + { + output.push(k + ' = ' + toString(v[k])); + } + if (output.length === 0) + { + return '{}'; + } + return '{ ' + output.join(', ') + ' }'; + } + + return ''; +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + eq: eq, + cmp: cmp, + Tuple0: Tuple0, + Tuple2: Tuple2, + chr: chr, + update: update, + guid: guid, + + append: F2(append), + + crash: crash, + crashCase: crashCase, + + toString: toString +}; + +}(); \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm new file mode 100644 index 0000000..2a136cc --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm @@ -0,0 +1,145 @@ +module Platform exposing + ( Program, program, programWithFlags + , Task, ProcessId + , Router, sendToApp, sendToSelf + ) + +{-| + +# Programs +@docs Program, program, programWithFlags + +# Platform Internals + +## Tasks and Processes +@docs Task, ProcessId + +## Effect Manager Helpers + +An extremely tiny portion of library authors should ever write effect managers. +Fundamentally, Elm needs maybe 10 of them total. I get that people are smart, +curious, etc. but that is not a substitute for a legitimate reason to make an +effect manager. Do you have an *organic need* this fills? Or are you just +curious? Public discussions of your explorations should be framed accordingly. + +@docs Router, sendToApp, sendToSelf +-} + +import Basics exposing (Never) +import Native.Platform +import Native.Scheduler +import Platform.Cmd exposing (Cmd) +import Platform.Sub exposing (Sub) + + + +-- PROGRAMS + + +{-| A `Program` describes how to manage your Elm app. + +You can create [headless][] programs with the [`program`](#program) and +[`programWithFlags`](#programWithFlags) functions. Similar functions exist in +[`Html`][html] that let you specify a view. + +[headless]: https://en.wikipedia.org/wiki/Headless_software +[html]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html + +Honestly, it is totally normal if this seems crazy at first. The best way to +understand is to work through [guide.elm-lang.org](http://guide.elm-lang.org/). +It makes way more sense in context! +-} +type Program flags model msg = Program + + +{-| Create a [headless][] program. This is great if you want to use Elm as the +“brain” for something else. You can still communicate with JS via +ports and manage your model, you just do not have to specify a `view`. + +[headless]: https://en.wikipedia.org/wiki/Headless_software + +Initializing a headless program from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker(); +``` +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program Never model msg +program = + Native.Platform.program + + +{-| Same as [`program`](#program), but you can provide flags. Initializing a +headless program (with flags) from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker({ user: 'Tom', token: 1234 }); +``` + +Whatever argument you provide to `worker` will get converted to an Elm value, +allowing you to configure your Elm program however you want from JavaScript! +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program flags model msg +programWithFlags = + Native.Platform.programWithFlags + + + +-- TASKS and PROCESSES + +{-| Head over to the documentation for the [`Task`](Task) module for more +information on this. It is only defined here because it is a platform +primitive. +-} +type Task err ok = Task + + +{-| Head over to the documentation for the [`Process`](Process) module for +information on this. It is only defined here because it is a platform +primitive. +-} +type ProcessId = ProcessId + + + +-- EFFECT MANAGER INTERNALS + + +{-| An effect manager has access to a “router” that routes messages between +the main app and your individual effect manager. +-} +type Router appMsg selfMsg = + Router + + +{-| Send the router a message for the main loop of your app. This message will +be handled by the overall `update` function, just like events from `Html`. +-} +sendToApp : Router msg a -> msg -> Task x () +sendToApp = + Native.Platform.sendToApp + + +{-| Send the router a message for your effect manager. This message will +be routed to the `onSelfMsg` function, where you can update the state of your +effect manager as necessary. + +As an example, the effect manager for web sockets +-} +sendToSelf : Router a msg -> msg -> Task x () +sendToSelf = + Native.Platform.sendToSelf + + +hack = + Native.Scheduler.succeed diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm new file mode 100644 index 0000000..a4ae4ed --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm @@ -0,0 +1,67 @@ +module Platform.Cmd exposing + ( Cmd + , map + , batch + , none + , (!) + ) + +{-| + +# Effects + +Elm has **managed effects**, meaning that things like HTTP requests or writing +to disk are all treated as *data* in Elm. When this data is given to the Elm +runtime system, it can do some “query optimization” before actually performing +the effect. Perhaps unexpectedly, this managed effects idea is the heart of why +Elm is so nice for testing, reuse, reproducibility, etc. + +There are two kinds of managed effects you will use in your programs: commands +and subscriptions. + +@docs Cmd, map, batch, none, (!) + +-} + +import Native.Platform + + +{-| A command is a way of telling Elm, “Hey, I want you to do this thing!” +So if you want to send an HTTP request, you would need to command Elm to do it. +Or if you wanted to ask for geolocation, you would need to command Elm to go +get it. + +Every `Cmd` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, commands will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they +fit into a real application! +-} +type Cmd msg = Cmd + + +{-|-} +map : (a -> msg) -> Cmd a -> Cmd msg +map = + Native.Platform.map + + +{-|-} +batch : List (Cmd msg) -> Cmd msg +batch = + Native.Platform.batch + + +{-|-} +none : Cmd msg +none = + batch [] + + +{-|-} +(!) : model -> List (Cmd msg) -> (model, Cmd msg) +(!) model commands = + (model, batch commands) + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm new file mode 100644 index 0000000..03f2f81 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm @@ -0,0 +1,52 @@ +module Platform.Sub exposing + ( Sub + , map + , batch + , none + ) + +{-| + +@docs Sub, map, batch, none +-} + +import Native.Platform + + +{-| A subscription is a way of telling Elm, “Hey, let me know if anything +interesting happens over there!” So if you want to listen for messages on a web +socket, you would tell Elm to create a subscription. If you want to get clock +ticks, you would tell Elm to subscribe to that. The cool thing here is that +this means *Elm* manages all the details of subscriptions instead of *you*. +So if a web socket goes down, *you* do not need to manually reconnect with an +exponential backoff strategy, *Elm* does this all for you behind the scenes! + +Every `Sub` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, subscriptions will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they fit +into a real application! +-} +type Sub msg = Sub + + +{-|-} +map : (a -> msg) -> Sub a -> Sub msg +map = + Native.Platform.map + + +{-|-} +batch : List (Sub msg) -> Sub msg +batch = + Native.Platform.batch + + +{-|-} +none : Sub msg +none = + batch [] + + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm new file mode 100644 index 0000000..0ef59af --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm @@ -0,0 +1,106 @@ +module Process exposing + ( Id + , spawn + , sleep + , kill + ) + +{-| + +# Processes +@docs Id, spawn, sleep, kill + +## Future Plans + +Right now, this library is pretty sparse. For example, there is no public API +for processes to communicate with each other. This is a really important +ability, but it is also something that is extraordinarily easy to get wrong! + +I think the trend will be towards an Erlang style of concurrency, where every +process has an “event queue” that anyone can send messages to. I currently +think the API will be extended to be more like this: + + type Id exit msg + + spawn : Task exit a -> Task x (Id exit Never) + + kill : Id exit msg -> Task x () + + send : Id exit msg -> msg -> Task x () + +A process `Id` will have two type variables to make sure all communication is +valid. The `exit` type describes the messages that are produced if the process +fails because of user code. So if processes are linked and trapping errors, +they will need to handle this. The `msg` type just describes what kind of +messages this process can be sent by strangers. + +We shall see though! This is just a draft that does not cover nearly everything +it needs to, so the long-term vision for concurrency in Elm will be rolling out +slowly as I get more data and experience. + +I ask that people bullish on compiling to node.js keep this in mind. I think we +can do better than the hopelessly bad concurrency model of node.js, and I hope +the Elm community will be supportive of being more ambitious, even if it takes +longer. That’s kind of what Elm is all about. +-} + +import Basics exposing (Never) +import Native.Scheduler +import Platform +import Task exposing (Task) +import Time exposing (Time) + + +{-| A light-weight process that runs concurrently. You can use `spawn` to +get a bunch of different tasks running in different processes. The Elm runtime +will interleave their progress. So if a task is taking too long, we will pause +it at an `andThen` and switch over to other stuff. + +**Note:** We make a distinction between *concurrency* which means interleaving +different sequences and *parallelism* which means running different +sequences at the exact same time. For example, a +[time-sharing system](https://en.wikipedia.org/wiki/Time-sharing) is definitely +concurrent, but not necessarily parallel. So even though JS runs within a +single OS-level thread, Elm can still run things concurrently. +-} +type alias Id = + Platform.ProcessId + + +{-| Run a task in its own light-weight process. In the following example, +`task1` and `task2` will be interleaved. If `task1` makes a long HTTP request +or is just taking a long time, we can hop over to `task2` and do some work +there. + + spawn task1 + |> Task.andThen (\_ -> spawn task2) + +**Note:** This creates a relatively restricted kind of `Process` because it +cannot receive any messages. More flexibility for user-defined processes will +come in a later release! +-} +spawn : Task x a -> Task y Id +spawn = + Native.Scheduler.spawn + + +{-| Block progress on the current process for a given amount of time. The +JavaScript equivalent of this is [`setTimeout`][setTimeout] which lets you +delay work until later. + +[setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout +-} +sleep : Time -> Task x () +sleep = + Native.Scheduler.sleep + + +{-| Sometimes you `spawn` a process, but later decide it would be a waste to +have it keep running and doing stuff. The `kill` function will force a process +to bail on whatever task it is running. So if there is an HTTP request in +flight, it will also abort the request. +-} +kill : Id -> Task x () +kill = + Native.Scheduler.kill + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm new file mode 100644 index 0000000..d506433 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm @@ -0,0 +1,532 @@ +effect module Random where { command = MyCmd } exposing + ( Generator, Seed + , bool, int, float + , list, pair + , map, map2, map3, map4, map5 + , andThen + , minInt, maxInt + , generate + , step, initialSeed + ) + +{-| This library helps you generate pseudo-random values. + +This library is all about building [`generators`](#Generator) for whatever +type of values you need. There are a bunch of primitive generators like +[`bool`](#bool) and [`int`](#int) that you can build up into fancier +generators with functions like [`list`](#list) and [`map`](#map). + +It may be helpful to [read about JSON decoders][json] because they work very +similarly. + +[json]: https://evancz.gitbooks.io/an-introduction-to-elm/content/interop/json.html + +> *Note:* This is an implementation of the Portable Combined Generator of +L'Ecuyer for 32-bit computers. It is almost a direct translation from the +[System.Random](http://hackage.haskell.org/package/random-1.0.1.1/docs/System-Random.html) +module. It has a period of roughly 2.30584e18. + +# Generators +@docs Generator + +# Primitive Generators +@docs bool, int, float + +# Data Structure Generators +@docs pair, list + +# Custom Generators +@docs map, map2, map3, map4, map5, andThen + +# Generate Values +@docs generate + +# Generate Values Manually +@docs step, Seed, initialSeed + +# Constants +@docs maxInt, minInt + +-} + +import Basics exposing (..) +import List exposing ((::)) +import Platform +import Platform.Cmd exposing (Cmd) +import Task exposing (Task) +import Time +import Tuple + + + +-- PRIMITIVE GENERATORS + + +{-| Create a generator that produces boolean values. The following example +simulates a coin flip that may land heads or tails. + + type Flip = Heads | Tails + + coinFlip : Generator Flip + coinFlip = + map (\b -> if b then Heads else Tails) bool +-} +bool : Generator Bool +bool = + map ((==) 1) (int 0 1) + + +{-| Generate 32-bit integers in a given range. + + int 0 10 -- an integer between zero and ten + int -5 5 -- an integer between -5 and 5 + + int minInt maxInt -- an integer in the widest range feasible + +This function *can* produce values outside of the range [[`minInt`](#minInt), +[`maxInt`](#maxInt)] but sufficient randomness is not guaranteed. +-} +int : Int -> Int -> Generator Int +int a b = + Generator <| \(Seed seed) -> + let + (lo,hi) = + if a < b then (a,b) else (b,a) + + k = hi - lo + 1 + -- 2^31 - 87 + base = 2147483561 + n = iLogBase base k + + f n acc state = + case n of + 0 -> (acc, state) + _ -> + let + (x, nextState) = seed.next state + in + f (n - 1) (x + acc * base) nextState + + (v, nextState) = + f n 1 seed.state + in + ( lo + v % k + , Seed { seed | state = nextState } + ) + + +iLogBase : Int -> Int -> Int +iLogBase b i = + if i < b then + 1 + else + 1 + iLogBase b (i // b) + + +{-| The maximum value for randomly generated 32-bit ints: 2147483647 -} +maxInt : Int +maxInt = + 2147483647 + + +{-| The minimum value for randomly generated 32-bit ints: -2147483648 -} +minInt : Int +minInt = + -2147483648 + + +{-| Generate floats in a given range. The following example is a generator +that produces decimals between 0 and 1. + + probability : Generator Float + probability = + float 0 1 +-} +float : Float -> Float -> Generator Float +float a b = + Generator <| \seed -> + let + (lo, hi) = + if a < b then (a,b) else (b,a) + + (number, newSeed) = + step (int minInt maxInt) seed + + negativeOneToOne = + toFloat number / toFloat (maxInt - minInt) + + scaled = + (lo+hi)/2 + ((hi-lo) * negativeOneToOne) + in + (scaled, newSeed) + + + +-- DATA STRUCTURES + + +{-| Create a pair of random values. A common use of this might be to generate +a point in a certain 2D space. Imagine we have a collage that is 400 pixels +wide and 200 pixels tall. + + randomPoint : Generator (Int,Int) + randomPoint = + pair (int -200 200) (int -100 100) + +-} +pair : Generator a -> Generator b -> Generator (a,b) +pair genA genB = + map2 (,) genA genB + + +{-| Create a list of random values. + + floatList : Generator (List Float) + floatList = + list 10 (float 0 1) + + intList : Generator (List Int) + intList = + list 5 (int 0 100) + + intPairs : Generator (List (Int, Int)) + intPairs = + list 10 <| pair (int 0 100) (int 0 100) +-} +list : Int -> Generator a -> Generator (List a) +list n (Generator generate) = + Generator <| \seed -> + listHelp [] n generate seed + + +listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed) +listHelp list n generate seed = + if n < 1 then + (List.reverse list, seed) + + else + let + (value, newSeed) = + generate seed + in + listHelp (value :: list) (n-1) generate newSeed + + + +-- CUSTOM GENERATORS + + +{-| Transform the values produced by a generator. The following examples show +how to generate booleans and letters based on a basic integer generator. + + bool : Generator Bool + bool = + map ((==) 1) (int 0 1) + + lowercaseLetter : Generator Char + lowercaseLetter = + map (\n -> Char.fromCode (n + 97)) (int 0 25) + + uppercaseLetter : Generator Char + uppercaseLetter = + map (\n -> Char.fromCode (n + 65)) (int 0 25) + +-} +map : (a -> b) -> Generator a -> Generator b +map func (Generator genA) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + in + (func a, seed1) + + +{-| Combine two generators. + +This function is used to define things like [`pair`](#pair) where you want to +put two generators together. + + pair : Generator a -> Generator b -> Generator (a,b) + pair genA genB = + map2 (,) genA genB + +-} +map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c +map2 func (Generator genA) (Generator genB) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + in + (func a b, seed2) + + +{-| Combine three generators. This could be used to produce random colors. + + import Color + + rgb : Generator Color.Color + rgb = + map3 Color.rgb (int 0 255) (int 0 255) (int 0 255) + + hsl : Generator Color.Color + hsl = + map3 Color.hsl (map degrees (int 0 360)) (float 0 1) (float 0 1) +-} +map3 : (a -> b -> c -> d) -> Generator a -> Generator b -> Generator c -> Generator d +map3 func (Generator genA) (Generator genB) (Generator genC) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + in + (func a b c, seed3) + + +{-| Combine four generators. +-} +map4 : (a -> b -> c -> d -> e) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e +map4 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + in + (func a b c d, seed4) + + +{-| Combine five generators. +-} +map5 : (a -> b -> c -> d -> e -> f) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e -> Generator f +map5 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) (Generator genE) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + (e, seed5) = genE seed4 + in + (func a b c d e, seed5) + + +{-| Chain random operations, threading through the seed. In the following +example, we will generate a random letter by putting together uppercase and +lowercase letters. + + letter : Generator Char + letter = + bool + |> andThen upperOrLower + + upperOrLower : Bool -> Generator Char + upperOrLower b = + if b then uppercaseLetter else lowercaseLetter + + -- bool : Generator Bool + -- uppercaseLetter : Generator Char + -- lowercaseLetter : Generator Char +-} +andThen : (a -> Generator b) -> Generator a -> Generator b +andThen callback (Generator generate) = + Generator <| \seed -> + let + (result, newSeed) = + generate seed + + (Generator genB) = + callback result + in + genB newSeed + + + +-- IMPLEMENTATION + + +{-| A `Generator` is like a recipe for generating certain random values. So a +`Generator Int` describes how to generate integers and a `Generator String` +describes how to generate strings. + +To actually *run* a generator and produce the random values, you need to use +functions like [`generate`](#generate) and [`initialSeed`](#initialSeed). +-} +type Generator a = + Generator (Seed -> (a, Seed)) + + +type State = State Int Int + + +{-| A `Seed` is the source of randomness in this whole system. Whenever +you want to use a generator, you need to pair it with a seed. +-} +type Seed = + Seed + { state : State + , next : State -> (Int, State) + , split : State -> (State, State) + , range : State -> (Int,Int) + } + + +{-| Generate a random value as specified by a given `Generator`. + +In the following example, we are trying to generate a number between 0 and 100 +with the `int 0 100` generator. Each time we call `step` we need to provide a +seed. This will produce a random number and a *new* seed to use if we want to +run other generators later. + +So here it is done right, where we get a new seed from each `step` call and +thread that through. + + seed0 = initialSeed 31415 + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed1 ==> (31, seed2) + -- step (int 0 100) seed2 ==> (99, seed3) + +Notice that we use different seeds on each line. This is important! If you use +the same seed, you get the same results. + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) +-} +step : Generator a -> Seed -> (a, Seed) +step (Generator generator) seed = + generator seed + + +{-| Create a “seed” of randomness which makes it possible to +generate random values. If you use the same seed many times, it will result +in the same thing every time! A good way to get an unexpected seed is to use +the current time. +-} +initialSeed : Int -> Seed +initialSeed n = + Seed + { state = initState n + , next = next + , split = split + , range = range + } + + +{-| Produce the initial generator state. Distinct arguments should be likely +to produce distinct generator states. +-} +initState : Int -> State +initState seed = + let + s = max seed -seed + q = s // (magicNum6-1) + s1 = s % (magicNum6-1) + s2 = q % (magicNum7-1) + in + State (s1+1) (s2+1) + + +magicNum0 = 40014 +magicNum1 = 53668 +magicNum2 = 12211 +magicNum3 = 52774 +magicNum4 = 40692 +magicNum5 = 3791 +magicNum6 = 2147483563 +magicNum7 = 2147483399 +magicNum8 = 2147483562 + + +next : State -> (Int, State) +next (State state1 state2) = + -- Div always rounds down and so random numbers are biased + -- ideally we would use division that rounds towards zero so + -- that in the negative case it rounds up and in the positive case + -- it rounds down. Thus half the time it rounds up and half the time it + -- rounds down + let + k1 = state1 // magicNum1 + rawState1 = magicNum0 * (state1 - k1 * magicNum1) - k1 * magicNum2 + newState1 = if rawState1 < 0 then rawState1 + magicNum6 else rawState1 + k2 = state2 // magicNum3 + rawState2 = magicNum4 * (state2 - k2 * magicNum3) - k2 * magicNum5 + newState2 = if rawState2 < 0 then rawState2 + magicNum7 else rawState2 + z = newState1 - newState2 + newZ = if z < 1 then z + magicNum8 else z + in + (newZ, State newState1 newState2) + + +split : State -> (State, State) +split (State s1 s2 as std) = + let + new_s1 = + if s1 == magicNum6-1 then 1 else s1 + 1 + + new_s2 = + if s2 == 1 then magicNum7-1 else s2 - 1 + + (State t1 t2) = + Tuple.second (next std) + in + (State new_s1 t2, State t1 new_s2) + + +range : State -> (Int,Int) +range _ = + (0, magicNum8) + + + +-- MANAGER + + +{-| Create a command that will generate random values. + +Read more about how to use this in your programs in [The Elm Architecture +tutorial][arch] which has a section specifically [about random values][rand]. + +[arch]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/index.html +[rand]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/effects/random.html +-} +generate : (a -> msg) -> Generator a -> Cmd msg +generate tagger generator = + command (Generate (map tagger generator)) + + +type MyCmd msg = Generate (Generator msg) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap func (Generate generator) = + Generate (map func generator) + + +init : Task Never Seed +init = + Time.now + |> Task.andThen (\t -> Task.succeed (initialSeed (round t))) + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> Seed -> Task Never Seed +onEffects router commands seed = + case commands of + [] -> + Task.succeed seed + + Generate generator :: rest -> + let + (value, newSeed) = + step generator seed + in + Platform.sendToApp router value + |> Task.andThen (\_ -> onEffects router rest newSeed) + + +onSelfMsg : Platform.Router msg Never -> Never -> Seed -> Task Never Seed +onSelfMsg _ _ seed = + Task.succeed seed diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm new file mode 100644 index 0000000..2d58ecf --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm @@ -0,0 +1,148 @@ +module Regex exposing + ( Regex + , regex, escape, caseInsensitive + , HowMany(..), Match + , contains, find, replace, split + ) + +{-| A library for working with regular expressions. It uses [the +same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions). + +# Create +@docs Regex, regex, escape, caseInsensitive + +# Helpful Data Structures + +These data structures are needed to help define functions like [`find`](#find) +and [`replace`](#replace). + +@docs HowMany, Match + +# Use +@docs contains, find, replace, split + +-} + +import Maybe exposing (Maybe) +import Native.Regex + + +{-| A regular expression, describing a certain set of strings. +-} +type Regex = Regex + + +{-| Escape strings to be regular expressions, making all special characters +safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series +of `a`’s that start at the beginning of the line. +-} +escape : String -> String +escape = + Native.Regex.escape + + +{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern). + +Be careful to escape backslashes properly! For example, `"\w"` is escaping the +letter `w` which is probably not what you want. You probably want `"\\w"` +instead, which escapes the backslash. +-} +regex : String -> Regex +regex = + Native.Regex.regex + + + +{-| Make a regex case insensitive -} +caseInsensitive : Regex -> Regex +caseInsensitive = + Native.Regex.caseInsensitive + + +{-| Check to see if a Regex is contained in a string. + + contains (regex "123") "12345" == True + contains (regex "b+") "aabbcc" == True + + contains (regex "789") "12345" == False + contains (regex "z+") "aabbcc" == False +-} +contains : Regex -> String -> Bool +contains = + Native.Regex.contains + + +{-| A `Match` represents all of the details about a particular match in a string. +Here are details on each field: + + * `match` — the full string of the match. + * `submatches` — a regex might have [subpatterns, surrounded by + parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches). + If there are N subpatterns, there will be N elements in the `submatches` list. + Each submatch in this list is a `Maybe` because not all subpatterns may trigger. + For example, `(regex "(a+)|(b+)")` will either match many `a`’s or + many `b`’s, but never both. + * `index` — the index of the match in the original string. + * `number` — if you find many matches, you can think of each one + as being labeled with a `number` starting at one. So the first time you + find a match, that is match `number` one. Second time is match `number` two. + This is useful when paired with `replace All` if replacement is dependent on how + many times a pattern has appeared before. +-} +type alias Match = + { match : String + , submatches : List (Maybe String) + , index : Int + , number : Int + } + + +{-| `HowMany` is used to specify how many matches you want to make. So +`replace All` would replace every match, but `replace (AtMost 2)` would +replace at most two matches (i.e. zero, one, two, but never three or more). +-} +type HowMany = All | AtMost Int + + +{-| Find matches in a string: + + findTwoCommas = find (AtMost 2) (regex ",") + + -- map .index (findTwoCommas "a,b,c,d,e") == [1,3] + -- map .index (findTwoCommas "a b c d e") == [] + + places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake." + + -- map .match places == ["on a boat", "in a lake"] + -- map .submatches places == [ [Just "boat"], [Just "lake"] ] +-} +find : HowMany -> Regex -> String -> List Match +find = + Native.Regex.find + + +{-| Replace matches. The function from `Match` to `String` lets +you use the details of a specific match when making replacements. + + devowel = replace All (regex "[aeiou]") (\_ -> "") + + -- devowel "The quick brown fox" == "Th qck brwn fx" + + reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match) + + -- reverseWords "deliver mined parts" == "reviled denim strap" +-} +replace : HowMany -> Regex -> (Match -> String) -> String -> String +replace = + Native.Regex.replace + + +{-| Split a string, using the regex as the separator. + + split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"] + + split All (regex ",") "a,b,c,d" == ["a","b","c","d"] +-} +split : HowMany -> Regex -> String -> List String +split = + Native.Regex.split diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm new file mode 100644 index 0000000..61c678c --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm @@ -0,0 +1,210 @@ +module Result exposing + ( Result(..) + , withDefault + , map, map2, map3, map4, map5 + , andThen + , toMaybe, fromMaybe, mapError + ) + +{-| A `Result` is the result of a computation that may fail. This is a great +way to manage errors in Elm. + +# Type and Constructors +@docs Result + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen + +# Handling Errors +@docs withDefault, toMaybe, fromMaybe, mapError +-} + +import Maybe exposing ( Maybe(Just, Nothing) ) + + +{-| A `Result` is either `Ok` meaning the computation succeeded, or it is an +`Err` meaning that there was some failure. +-} +type Result error value + = Ok value + | Err error + + +{-| If the result is `Ok` return the value, but if the result is an `Err` then +return a given default value. The following examples try to parse integers. + + Result.withDefault 0 (String.toInt "123") == 123 + Result.withDefault 0 (String.toInt "abc") == 0 +-} +withDefault : a -> Result x a -> a +withDefault def result = + case result of + Ok a -> + a + + Err _ -> + def + + +{-| Apply a function to a result. If the result is `Ok`, it will be converted. +If the result is an `Err`, the same error value will propagate through. + + map sqrt (Ok 4.0) == Ok 2.0 + map sqrt (Err "bad input") == Err "bad input" +-} +map : (a -> value) -> Result x a -> Result x value +map func ra = + case ra of + Ok a -> Ok (func a) + Err e -> Err e + + +{-| Apply a function to two results, if both results are `Ok`. If not, +the first argument which is an `Err` will propagate through. + + map2 (+) (String.toInt "1") (String.toInt "2") == Ok 3 + map2 (+) (String.toInt "1") (String.toInt "y") == Err "could not convert string 'y' to an Int" + map2 (+) (String.toInt "x") (String.toInt "y") == Err "could not convert string 'x' to an Int" +-} +map2 : (a -> b -> value) -> Result x a -> Result x b -> Result x value +map2 func ra rb = + case (ra,rb) of + (Ok a, Ok b) -> Ok (func a b) + (Err x, _) -> Err x + (_, Err x) -> Err x + + +{-|-} +map3 : (a -> b -> c -> value) -> Result x a -> Result x b -> Result x c -> Result x value +map3 func ra rb rc = + case (ra,rb,rc) of + (Ok a, Ok b, Ok c) -> Ok (func a b c) + (Err x, _, _) -> Err x + (_, Err x, _) -> Err x + (_, _, Err x) -> Err x + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x value +map4 func ra rb rc rd = + case (ra,rb,rc,rd) of + (Ok a, Ok b, Ok c, Ok d) -> Ok (func a b c d) + (Err x, _, _, _) -> Err x + (_, Err x, _, _) -> Err x + (_, _, Err x, _) -> Err x + (_, _, _, Err x) -> Err x + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x e -> Result x value +map5 func ra rb rc rd re = + case (ra,rb,rc,rd,re) of + (Ok a, Ok b, Ok c, Ok d, Ok e) -> Ok (func a b c d e) + (Err x, _, _, _, _) -> Err x + (_, Err x, _, _, _) -> Err x + (_, _, Err x, _, _) -> Err x + (_, _, _, Err x, _) -> Err x + (_, _, _, _, Err x) -> Err x + + +{-| Chain together a sequence of computations that may fail. It is helpful +to see its definition: + + andThen : (a -> Result e b) -> Result e a -> Result e b + andThen callback result = + case result of + Ok value -> callback value + Err msg -> Err msg + +This means we only continue with the callback if things are going well. For +example, say you need to use (`toInt : String -> Result String Int`) to parse +a month and make sure it is between 1 and 12: + + toValidMonth : Int -> Result String Int + toValidMonth month = + if month >= 1 && month <= 12 + then Ok month + else Err "months must be between 1 and 12" + + toMonth : String -> Result String Int + toMonth rawString = + toInt rawString + |> andThen toValidMonth + + -- toMonth "4" == Ok 4 + -- toMonth "9" == Ok 9 + -- toMonth "a" == Err "cannot parse to an Int" + -- toMonth "0" == Err "months must be between 1 and 12" + +This allows us to come out of a chain of operations with quite a specific error +message. It is often best to create a custom type that explicitly represents +the exact ways your computation may fail. This way it is easy to handle in your +code. +-} +andThen : (a -> Result x b) -> Result x a -> Result x b +andThen callback result = + case result of + Ok value -> + callback value + + Err msg -> + Err msg + + +{-| Transform an `Err` value. For example, say the errors we get have too much +information: + + parseInt : String -> Result ParseError Int + + type alias ParseError = + { message : String + , code : Int + , position : (Int,Int) + } + + mapError .message (parseInt "123") == Ok 123 + mapError .message (parseInt "abc") == Err "char 'a' is not a number" +-} +mapError : (x -> y) -> Result x a -> Result y a +mapError f result = + case result of + Ok v -> + Ok v + + Err e -> + Err (f e) + + +{-| Convert to a simpler `Maybe` if the actual error message is not needed or +you need to interact with some code that primarily uses maybes. + + parseInt : String -> Result ParseError Int + + maybeParseInt : String -> Maybe Int + maybeParseInt string = + toMaybe (parseInt string) +-} +toMaybe : Result x a -> Maybe a +toMaybe result = + case result of + Ok v -> Just v + Err _ -> Nothing + + +{-| Convert from a simple `Maybe` to interact with some code that primarily +uses `Results`. + + parseInt : String -> Maybe Int + + resultParseInt : String -> Result String Int + resultParseInt string = + fromMaybe ("error parsing string: " ++ toString string) (parseInt string) +-} +fromMaybe : x -> Maybe a -> Result x a +fromMaybe err maybe = + case maybe of + Just v -> Ok v + Nothing -> Err err diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm new file mode 100644 index 0000000..9b1914a --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm @@ -0,0 +1,168 @@ +module Set exposing + ( Set + , empty, singleton, insert, remove + , isEmpty, member, size + , foldl, foldr, map + , filter, partition + , union, intersect, diff + , toList, fromList + ) + +{-| A set of unique values. The values can be any comparable type. This +includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or lists +of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Sets +@docs Set + +# Build +@docs empty, singleton, insert, remove + +# Query +@docs isEmpty, member, size + +# Combine +@docs union, intersect, diff + +# Lists +@docs toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +-} + +import Basics exposing ((<|)) +import Dict as Dict +import List as List + + +{-| Represents a set of unique values. So `(Set Int)` is a set of integers and +`(Set String)` is a set of strings. +-} +type Set t = + Set_elm_builtin (Dict.Dict t ()) + + +{-| Create an empty set. +-} +empty : Set a +empty = + Set_elm_builtin Dict.empty + + +{-| Create a set with one value. +-} +singleton : comparable -> Set comparable +singleton k = + Set_elm_builtin <| Dict.singleton k () + + +{-| Insert a value into a set. +-} +insert : comparable -> Set comparable -> Set comparable +insert k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.insert k () d + + +{-| Remove a value from a set. If the value is not found, no changes are made. +-} +remove : comparable -> Set comparable -> Set comparable +remove k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.remove k d + + +{-| Determine if a set is empty. +-} +isEmpty : Set a -> Bool +isEmpty (Set_elm_builtin d) = + Dict.isEmpty d + + +{-| Determine if a value is in a set. +-} +member : comparable -> Set comparable -> Bool +member k (Set_elm_builtin d) = + Dict.member k d + + +{-| Determine the number of elements in a set. +-} +size : Set a -> Int +size (Set_elm_builtin d) = + Dict.size d + + +{-| Get the union of two sets. Keep all values. +-} +union : Set comparable -> Set comparable -> Set comparable +union (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.union d1 d2 + + +{-| Get the intersection of two sets. Keeps values that appear in both sets. +-} +intersect : Set comparable -> Set comparable -> Set comparable +intersect (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.intersect d1 d2 + + +{-| Get the difference between the first set and the second. Keeps values +that do not appear in the second set. +-} +diff : Set comparable -> Set comparable -> Set comparable +diff (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.diff d1 d2 + + +{-| Convert a set into a list, sorted from lowest to highest. +-} +toList : Set comparable -> List comparable +toList (Set_elm_builtin d) = + Dict.keys d + + +{-| Convert a list into a set, removing any duplicates. +-} +fromList : List comparable -> Set comparable +fromList xs = List.foldl insert empty xs + + +{-| Fold over the values in a set, in order from lowest to highest. +-} +foldl : (comparable -> b -> b) -> b -> Set comparable -> b +foldl f b (Set_elm_builtin d) = + Dict.foldl (\k _ b -> f k b) b d + + +{-| Fold over the values in a set, in order from highest to lowest. +-} +foldr : (comparable -> b -> b) -> b -> Set comparable -> b +foldr f b (Set_elm_builtin d) = + Dict.foldr (\k _ b -> f k b) b d + + +{-| Map a function onto a set, creating a new set with no duplicates. +-} +map : (comparable -> comparable2) -> Set comparable -> Set comparable2 +map f s = fromList (List.map f (toList s)) + + +{-| Create a new set consisting only of elements which satisfy a predicate. +-} +filter : (comparable -> Bool) -> Set comparable -> Set comparable +filter p (Set_elm_builtin d) = + Set_elm_builtin <| Dict.filter (\k _ -> p k) d + + +{-| Create two new sets; the first consisting of elements which satisfy a +predicate, the second consisting of elements which do not. +-} +partition : (comparable -> Bool) -> Set comparable -> (Set comparable, Set comparable) +partition p (Set_elm_builtin d) = + let + (p1, p2) = Dict.partition (\k _ -> p k) d + in + (Set_elm_builtin p1, Set_elm_builtin p2) diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm new file mode 100644 index 0000000..a648e8d --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm @@ -0,0 +1,464 @@ +module String exposing + ( isEmpty, length, reverse, repeat + , cons, uncons, fromChar, append, concat, split, join, words, lines + , slice, left, right, dropLeft, dropRight + , contains, startsWith, endsWith, indexes, indices + , toInt, toFloat, toList, fromList + , toUpper, toLower, pad, padLeft, padRight, trim, trimLeft, trimRight + , map, filter, foldl, foldr, any, all + ) + +{-| A built-in representation for efficient string manipulation. String literals +are enclosed in `"double quotes"`. Strings are *not* lists of characters. + +# Basics +@docs isEmpty, length, reverse, repeat + +# Building and Splitting +@docs cons, uncons, fromChar, append, concat, split, join, words, lines + +# Get Substrings +@docs slice, left, right, dropLeft, dropRight + +# Check for Substrings +@docs contains, startsWith, endsWith, indexes, indices + +# Conversions +@docs toInt, toFloat, toList, fromList + +# Formatting +Cosmetic operations such as padding with extra characters or trimming whitespace. + +@docs toUpper, toLower, + pad, padLeft, padRight, + trim, trimLeft, trimRight + +# Higher-Order Functions +@docs map, filter, foldl, foldr, any, all +-} + +import Native.String +import Char +import Maybe exposing (Maybe) +import Result exposing (Result) + + +{-| Determine if a string is empty. + + isEmpty "" == True + isEmpty "the world" == False +-} +isEmpty : String -> Bool +isEmpty = + Native.String.isEmpty + + +{-| Add a character to the beginning of a string. + + cons 'T' "he truth is out there" == "The truth is out there" +-} +cons : Char -> String -> String +cons = + Native.String.cons + + +{-| Create a string from a given character. + + fromChar 'a' == "a" +-} +fromChar : Char -> String +fromChar char = + cons char "" + + +{-| Split a non-empty string into its head and tail. This lets you +pattern match on strings exactly as you would with lists. + + uncons "abc" == Just ('a',"bc") + uncons "" == Nothing +-} +uncons : String -> Maybe (Char, String) +uncons = + Native.String.uncons + + +{-| Append two strings. You can also use [the `(++)` operator](Basics#++) +to do this. + + append "butter" "fly" == "butterfly" +-} +append : String -> String -> String +append = + Native.String.append + + +{-| Concatenate many strings into one. + + concat ["never","the","less"] == "nevertheless" +-} +concat : List String -> String +concat = + Native.String.concat + + +{-| Get the length of a string. + + length "innumerable" == 11 + length "" == 0 + +-} +length : String -> Int +length = + Native.String.length + + +{-| Transform every character in a string + + map (\c -> if c == '/' then '.' else c) "a/b/c" == "a.b.c" +-} +map : (Char -> Char) -> String -> String +map = + Native.String.map + + +{-| Keep only the characters that satisfy the predicate. + + filter isDigit "R2-D2" == "22" +-} +filter : (Char -> Bool) -> String -> String +filter = + Native.String.filter + + +{-| Reverse a string. + + reverse "stressed" == "desserts" +-} +reverse : String -> String +reverse = + Native.String.reverse + + +{-| Reduce a string from the left. + + foldl cons "" "time" == "emit" +-} +foldl : (Char -> b -> b) -> b -> String -> b +foldl = + Native.String.foldl + + +{-| Reduce a string from the right. + + foldr cons "" "time" == "time" +-} +foldr : (Char -> b -> b) -> b -> String -> b +foldr = + Native.String.foldr + + +{-| Split a string using a given separator. + + split "," "cat,dog,cow" == ["cat","dog","cow"] + split "/" "home/evan/Desktop/" == ["home","evan","Desktop", ""] + +Use [`Regex.split`](Regex#split) if you need something more flexible. +-} +split : String -> String -> List String +split = + Native.String.split + + +{-| Put many strings together with a given separator. + + join "a" ["H","w","ii","n"] == "Hawaiian" + join " " ["cat","dog","cow"] == "cat dog cow" + join "/" ["home","evan","Desktop"] == "home/evan/Desktop" +-} +join : String -> List String -> String +join = + Native.String.join + + +{-| Repeat a string *n* times. + + repeat 3 "ha" == "hahaha" +-} +repeat : Int -> String -> String +repeat = + Native.String.repeat + + +{-| Take a substring given a start and end index. Negative indexes +are taken starting from the *end* of the list. + + slice 7 9 "snakes on a plane!" == "on" + slice 0 6 "snakes on a plane!" == "snakes" + slice 0 -7 "snakes on a plane!" == "snakes on a" + slice -6 -1 "snakes on a plane!" == "plane" +-} +slice : Int -> Int -> String -> String +slice = + Native.String.slice + + +{-| Take *n* characters from the left side of a string. + + left 2 "Mulder" == "Mu" +-} +left : Int -> String -> String +left = + Native.String.left + + +{-| Take *n* characters from the right side of a string. + + right 2 "Scully" == "ly" +-} +right : Int -> String -> String +right = + Native.String.right + + +{-| Drop *n* characters from the left side of a string. + + dropLeft 2 "The Lone Gunmen" == "e Lone Gunmen" +-} +dropLeft : Int -> String -> String +dropLeft = + Native.String.dropLeft + + +{-| Drop *n* characters from the right side of a string. + + dropRight 2 "Cigarette Smoking Man" == "Cigarette Smoking M" +-} +dropRight : Int -> String -> String +dropRight = + Native.String.dropRight + + +{-| Pad a string on both sides until it has a given length. + + pad 5 ' ' "1" == " 1 " + pad 5 ' ' "11" == " 11 " + pad 5 ' ' "121" == " 121 " +-} +pad : Int -> Char -> String -> String +pad = + Native.String.pad + + +{-| Pad a string on the left until it has a given length. + + padLeft 5 '.' "1" == "....1" + padLeft 5 '.' "11" == "...11" + padLeft 5 '.' "121" == "..121" +-} +padLeft : Int -> Char -> String -> String +padLeft = + Native.String.padLeft + + +{-| Pad a string on the right until it has a given length. + + padRight 5 '.' "1" == "1...." + padRight 5 '.' "11" == "11..." + padRight 5 '.' "121" == "121.." +-} +padRight : Int -> Char -> String -> String +padRight = + Native.String.padRight + + +{-| Get rid of whitespace on both sides of a string. + + trim " hats \n" == "hats" +-} +trim : String -> String +trim = + Native.String.trim + + +{-| Get rid of whitespace on the left of a string. + + trimLeft " hats \n" == "hats \n" +-} +trimLeft : String -> String +trimLeft = + Native.String.trimLeft + + +{-| Get rid of whitespace on the right of a string. + + trimRight " hats \n" == " hats" +-} +trimRight : String -> String +trimRight = + Native.String.trimRight + + +{-| Break a string into words, splitting on chunks of whitespace. + + words "How are \t you? \n Good?" == ["How","are","you?","Good?"] +-} +words : String -> List String +words = + Native.String.words + + +{-| Break a string into lines, splitting on newlines. + + lines "How are you?\nGood?" == ["How are you?", "Good?"] +-} +lines : String -> List String +lines = + Native.String.lines + + +{-| Convert a string to all upper case. Useful for case-insensitive comparisons +and VIRTUAL YELLING. + + toUpper "skinner" == "SKINNER" +-} +toUpper : String -> String +toUpper = + Native.String.toUpper + + +{-| Convert a string to all lower case. Useful for case-insensitive comparisons. + + toLower "X-FILES" == "x-files" +-} +toLower : String -> String +toLower = + Native.String.toLower + + +{-| Determine whether *any* characters satisfy a predicate. + + any isDigit "90210" == True + any isDigit "R2-D2" == True + any isDigit "heart" == False +-} +any : (Char -> Bool) -> String -> Bool +any = + Native.String.any + + +{-| Determine whether *all* characters satisfy a predicate. + + all isDigit "90210" == True + all isDigit "R2-D2" == False + all isDigit "heart" == False +-} +all : (Char -> Bool) -> String -> Bool +all = + Native.String.all + + +{-| See if the second string contains the first one. + + contains "the" "theory" == True + contains "hat" "theory" == False + contains "THE" "theory" == False + +Use [`Regex.contains`](Regex#contains) if you need something more flexible. +-} +contains : String -> String -> Bool +contains = + Native.String.contains + + +{-| See if the second string starts with the first one. + + startsWith "the" "theory" == True + startsWith "ory" "theory" == False +-} +startsWith : String -> String -> Bool +startsWith = + Native.String.startsWith + + +{-| See if the second string ends with the first one. + + endsWith "the" "theory" == False + endsWith "ory" "theory" == True +-} +endsWith : String -> String -> Bool +endsWith = + Native.String.endsWith + + +{-| Get all of the indexes for a substring in another string. + + indexes "i" "Mississippi" == [1,4,7,10] + indexes "ss" "Mississippi" == [2,5] + indexes "needle" "haystack" == [] +-} +indexes : String -> String -> List Int +indexes = + Native.String.indexes + + +{-| Alias for `indexes`. -} +indices : String -> String -> List Int +indices = + Native.String.indexes + + +{-| Try to convert a string into an int, failing on improperly formatted strings. + + String.toInt "123" == Ok 123 + String.toInt "-42" == Ok -42 + String.toInt "3.1" == Err "could not convert string '3.1' to an Int" + String.toInt "31a" == Err "could not convert string '31a' to an Int" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toInt "42") == 42 + Result.withDefault 0 (String.toInt "ab") == 0 +-} +toInt : String -> Result String Int +toInt = + Native.String.toInt + + +{-| Try to convert a string into a float, failing on improperly formatted strings. + + String.toFloat "123" == Ok 123.0 + String.toFloat "-42" == Ok -42.0 + String.toFloat "3.1" == Ok 3.1 + String.toFloat "31a" == Err "could not convert string '31a' to a Float" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toFloat "42.5") == 42.5 + Result.withDefault 0 (String.toFloat "cats") == 0 +-} +toFloat : String -> Result String Float +toFloat = + Native.String.toFloat + + +{-| Convert a string to a list of characters. + + toList "abc" == ['a','b','c'] +-} +toList : String -> List Char +toList = + Native.String.toList + + +{-| Convert a list of characters into a String. Can be useful if you +want to create a string primarily by consing, perhaps for decoding +something. + + fromList ['a','b','c'] == "abc" +-} +fromList : List Char -> String +fromList = + Native.String.fromList + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm new file mode 100644 index 0000000..94fde9e --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm @@ -0,0 +1,277 @@ +effect module Task where { command = MyCmd } exposing + ( Task + , succeed, fail + , map, map2, map3, map4, map5 + , sequence + , andThen + , onError, mapError + , perform, attempt + ) + +{-| Tasks make it easy to describe asynchronous operations that may fail, like +HTTP requests or writing to a database. For more information, see the [Elm +documentation on Tasks](http://guide.elm-lang.org/error_handling/task.html). + +# Basics +@docs Task, succeed, fail + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen, sequence + +# Errors +@docs onError, mapError + +# Commands +@docs perform, attempt + +-} + +import Basics exposing (Never, (|>), (<<)) +import List exposing ((::)) +import Maybe exposing (Maybe(Just,Nothing)) +import Native.Scheduler +import Platform +import Platform.Cmd exposing (Cmd) +import Result exposing (Result(Ok,Err)) + + + +{-| Represents asynchronous effects that may fail. It is useful for stuff like +HTTP. + +For example, maybe we have a task with the type (`Task String User`). This means +that when we perform the task, it will either fail with a `String` message or +succeed with a `User`. So this could represent a task that is asking a server +for a certain user. +-} +type alias Task err ok = + Platform.Task err ok + + + +-- BASICS + + +{-| A task that succeeds immediately when run. + + succeed 42 -- results in 42 +-} +succeed : a -> Task x a +succeed = + Native.Scheduler.succeed + + +{-| A task that fails immediately when run. + + fail "file not found" : Task String a +-} +fail : x -> Task x a +fail = + Native.Scheduler.fail + + + +-- MAPPING + + +{-| Transform a task. + + map sqrt (succeed 9) -- succeed 3 +-} +map : (a -> b) -> Task x a -> Task x b +map func taskA = + taskA + |> andThen (\a -> succeed (func a)) + + +{-| Put the results of two tasks together. If either task fails, the whole +thing fails. It also runs in order so the first task will be completely +finished before the second task starts. + + map2 (+) (succeed 9) (succeed 3) -- succeed 12 +-} +map2 : (a -> b -> result) -> Task x a -> Task x b -> Task x result +map2 func taskA taskB = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> succeed (func a b))) + + +{-|-} +map3 : (a -> b -> c -> result) -> Task x a -> Task x b -> Task x c -> Task x result +map3 func taskA taskB taskC = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> succeed (func a b c)))) + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x result +map4 func taskA taskB taskC taskD = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> succeed (func a b c d))))) + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x e -> Task x result +map5 func taskA taskB taskC taskD taskE = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> taskE + |> andThen (\e -> succeed (func a b c d e)))))) + + +{-| Start with a list of tasks, and turn them into a single task that returns a +list. The tasks will be run in order one-by-one and if any task fails the whole +sequence fails. + + sequence [ succeed 1, succeed 2 ] -- succeed [ 1, 2 ] + +This can be useful if you need to make a bunch of HTTP requests one-by-one. +-} +sequence : List (Task x a) -> Task x (List a) +sequence tasks = + case tasks of + [] -> + succeed [] + + task :: remainingTasks -> + map2 (::) task (sequence remainingTasks) + + + +-- CHAINING + + +{-| Chain together a task and a callback. The first task will run, and if it is +successful, you give the result to the callback resulting in another task. This +task then gets run. + + succeed 2 + |> andThen (\n -> succeed (n + 2)) + -- succeed 4 + +This is useful for chaining tasks together. Maybe you need to get a user from +your servers *and then* lookup their picture once you know their name. +-} +andThen : (a -> Task x b) -> Task x a -> Task x b +andThen = + Native.Scheduler.andThen + + +-- ERRORS + +{-| Recover from a failure in a task. If the given task fails, we use the +callback to recover. + + fail "file not found" + |> onError (\msg -> succeed 42) + -- succeed 42 + + succeed 9 + |> onError (\msg -> succeed 42) + -- succeed 9 +-} +onError : (x -> Task y a) -> Task x a -> Task y a +onError = + Native.Scheduler.onError + + +{-| Transform the error value. This can be useful if you need a bunch of error +types to match up. + + type Error = Http Http.Error | WebGL WebGL.Error + + getResources : Task Error Resource + getResources = + sequence [ mapError Http serverTask, mapError WebGL textureTask ] +-} +mapError : (x -> y) -> Task x a -> Task y a +mapError convert task = + task + |> onError (fail << convert) + + + +-- COMMANDS + + +type MyCmd msg = + Perform (Task Never msg) + + +{-| The only way to *do* things in Elm is to give commands to the Elm runtime. +So we describe some complex behavior with a `Task` and then command the runtime +to `perform` that task. For example, getting the current time looks like this: + + import Task + import Time exposing (Time) + + type Msg = Click | NewTime Time + + update : Msg -> Model -> ( Model, Cmd Msg ) + update msg model = + case msg of + Click -> + ( model, Task.perform NewTime Time.now ) + + NewTime time -> + ... +-} +perform : (a -> msg) -> Task Never a -> Cmd msg +perform toMessage task = + command (Perform (map toMessage task)) + + +{-| Command the Elm runtime to attempt a task that might fail! +-} +attempt : (Result x a -> msg) -> Task x a -> Cmd msg +attempt resultToMessage task = + command (Perform ( + task + |> andThen (succeed << resultToMessage << Ok) + |> onError (succeed << resultToMessage << Err) + )) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap tagger (Perform task) = + Perform (map tagger task) + + + +-- MANAGER + + +init : Task Never () +init = + succeed () + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> () -> Task Never () +onEffects router commands state = + map + (\_ -> ()) + (sequence (List.map (spawnCmd router) commands)) + + +onSelfMsg : Platform.Router msg Never -> Never -> () -> Task Never () +onSelfMsg _ _ _ = + succeed () + + +spawnCmd : Platform.Router msg Never -> MyCmd msg -> Task x () +spawnCmd router (Perform task) = + Native.Scheduler.spawn ( + task + |> andThen (Platform.sendToApp router) + ) diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm new file mode 100644 index 0000000..b50cdfe --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm @@ -0,0 +1,243 @@ +effect module Time where { subscription = MySub } exposing + ( Time + , now, every + , millisecond, second, minute, hour + , inMilliseconds, inSeconds, inMinutes, inHours + ) + +{-| Library for working with time. + +# Time +@docs Time, now, every + +# Units +@docs millisecond, second, minute, hour, + inMilliseconds, inSeconds, inMinutes, inHours + +-} + + +import Basics exposing (..) +import Dict +import List exposing ((::)) +import Maybe exposing (Maybe(..)) +import Native.Scheduler +import Native.Time +import Platform +import Platform.Sub exposing (Sub) +import Task exposing (Task) + + + +-- TIMES + + +{-| Type alias to make it clearer when you are working with time values. +Using the `Time` helpers like `second` and `inSeconds` instead of raw numbers +is very highly recommended. +-} +type alias Time = Float + + +{-| Get the `Time` at the moment when this task is run. +-} +now : Task x Time +now = + Native.Time.now + + +{-| Subscribe to the current time. First you provide an interval describing how +frequently you want updates. Second, you give a tagger that turns a time into a +message for your `update` function. So if you want to hear about the current +time every second, you would say something like this: + + type Msg = Tick Time | ... + + subscriptions model = + every second Tick + +Check out the [Elm Architecture Tutorial][arch] for more info on how +subscriptions work. + +[arch]: https://github.com/evancz/elm-architecture-tutorial/ + +**Note:** this function is not for animation! You need to use something based +on `requestAnimationFrame` to get smooth animations. This is based on +`setInterval` which is better for recurring tasks like “check on something +every 30 seconds”. +-} +every : Time -> (Time -> msg) -> Sub msg +every interval tagger = + subscription (Every interval tagger) + + + +-- UNITS + + +{-| Units of time, making it easier to specify things like a half-second +`(500 * millisecond)` without remembering Elm’s underlying units of time. +-} +millisecond : Time +millisecond = + 1 + + +{-|-} +second : Time +second = + 1000 * millisecond + + +{-|-} +minute : Time +minute = + 60 * second + + +{-|-} +hour : Time +hour = + 60 * minute + + +{-|-} +inMilliseconds : Time -> Float +inMilliseconds t = + t + + +{-|-} +inSeconds : Time -> Float +inSeconds t = + t / second + + +{-|-} +inMinutes : Time -> Float +inMinutes t = + t / minute + + +{-|-} +inHours : Time -> Float +inHours t = + t / hour + + + +-- SUBSCRIPTIONS + + +type MySub msg = + Every Time (Time -> msg) + + +subMap : (a -> b) -> MySub a -> MySub b +subMap f (Every interval tagger) = + Every interval (f << tagger) + + + +-- EFFECT MANAGER + + +type alias State msg = + { taggers : Taggers msg + , processes : Processes + } + + +type alias Processes = + Dict.Dict Time Platform.ProcessId + + +type alias Taggers msg = + Dict.Dict Time (List (Time -> msg)) + + +init : Task Never (State msg) +init = + Task.succeed (State Dict.empty Dict.empty) + + +onEffects : Platform.Router msg Time -> List (MySub msg) -> State msg -> Task Never (State msg) +onEffects router subs {processes} = + let + newTaggers = + List.foldl addMySub Dict.empty subs + + leftStep interval taggers (spawnList, existingDict, killTask) = + (interval :: spawnList, existingDict, killTask) + + bothStep interval taggers id (spawnList, existingDict, killTask) = + (spawnList, Dict.insert interval id existingDict, killTask) + + rightStep _ id (spawnList, existingDict, killTask) = + ( spawnList + , existingDict + , Native.Scheduler.kill id + |> Task.andThen (\_ -> killTask) + ) + + (spawnList, existingDict, killTask) = + Dict.merge + leftStep + bothStep + rightStep + newTaggers + processes + ([], Dict.empty, Task.succeed ()) + in + killTask + |> Task.andThen (\_ -> spawnHelp router spawnList existingDict) + |> Task.andThen (\newProcesses -> Task.succeed (State newTaggers newProcesses)) + + +addMySub : MySub msg -> Taggers msg -> Taggers msg +addMySub (Every interval tagger) state = + case Dict.get interval state of + Nothing -> + Dict.insert interval [tagger] state + + Just taggers -> + Dict.insert interval (tagger :: taggers) state + + +spawnHelp : Platform.Router msg Time -> List Time -> Processes -> Task.Task x Processes +spawnHelp router intervals processes = + case intervals of + [] -> + Task.succeed processes + + interval :: rest -> + let + spawnTimer = + Native.Scheduler.spawn (setInterval interval (Platform.sendToSelf router interval)) + + spawnRest id = + spawnHelp router rest (Dict.insert interval id processes) + in + spawnTimer + |> Task.andThen spawnRest + + +onSelfMsg : Platform.Router msg Time -> Time -> State msg -> Task Never (State msg) +onSelfMsg router interval state = + case Dict.get interval state.taggers of + Nothing -> + Task.succeed state + + Just taggers -> + let + tellTaggers time = + Task.sequence (List.map (\tagger -> Platform.sendToApp router (tagger time)) taggers) + in + now + |> Task.andThen tellTaggers + |> Task.andThen (\_ -> Task.succeed state) + + +setInterval : Time -> Task Never () -> Task x Never +setInterval = + Native.Time.setInterval_ diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm new file mode 100644 index 0000000..ab4c401 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm @@ -0,0 +1,61 @@ +module Tuple exposing + ( first, second + , mapFirst, mapSecond + ) + +{-| Some helpers for working with 2-tuples. + +**Note:** For larger chunks of data, it is best to switch to using records. So +instead of representing a 3D point as `(3,4,5)` and wondering why there are no +helper functions, represent it as `{ x = 3, y = 4, z = 5 }` and use all the +built-in syntax for records. + +@docs first, second, mapFirst, mapSecond + +-} + + + +{-| Extract the first value from a tuple. + + first (3, 4) == 3 + first ("john", "doe") == "john" +-} +first : (a1, a2) -> a1 +first (x,_) = + x + + +{-| Extract the second value from a tuple. + + second (3, 4) == 4 + second ("john", "doe") == "doe" +-} +second : (a1, a2) -> a2 +second (_,y) = + y + + +{-| Transform the first value in a tuple. + + import String + + mapFirst String.reverse ("stressed", 16) == ("desserts", 16) + mapFirst String.length ("stressed", 16) == (8, 16) +-} +mapFirst : (a -> b) -> (a, a2) -> (b, a2) +mapFirst func (x,y) = + (func x, y) + + +{-| Transform the second value in a tuple. + + import String + + mapSecond sqrt ("stressed", 16) == ("stressed", 4) + mapSecond (\x -> x + 1) ("stressed", 16) == ("stressed", 17) +-} +mapSecond : (a -> b) -> (a1, a) -> (a1, b) +mapSecond func (x,y) = + (x, func y) + diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm new file mode 100644 index 0000000..0fb81c9 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm @@ -0,0 +1,50 @@ +port module Main exposing (..) + +import Basics exposing (..) +import Task exposing (..) +import Test exposing (..) +import Platform.Cmd exposing (Cmd) +import Json.Decode exposing (Value) +import Test.Runner.Node exposing (run, TestProgram) +import Test.Array as Array +import Test.Basics as Basics +import Test.Bitwise as Bitwise +import Test.Char as Char +import Test.CodeGen as CodeGen +import Test.Dict as Dict +import Test.Maybe as Maybe +import Test.Equality as Equality +import Test.Json as Json +import Test.List as List +import Test.Result as Result +import Test.Set as Set +import Test.String as String +import Test.Regex as Regex + + +tests : Test +tests = + describe "Elm Standard Library Tests" + [ Array.tests + , Basics.tests + , Bitwise.tests + , Char.tests + , CodeGen.tests + , Dict.tests + , Equality.tests + , Json.tests + , List.tests + , Result.tests + , Set.tests + , String.tests + , Regex.tests + , Maybe.tests + ] + + +main : TestProgram +main = + run emit tests + + +port emit : ( String, Value ) -> Cmd msg diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm new file mode 100644 index 0000000..e32b49d --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm @@ -0,0 +1,120 @@ +module Test.Array exposing (tests) + +import Array +import Basics exposing (..) +import List +import List exposing ((::)) +import Maybe exposing (..) +import Native.Array +import Test exposing (..) +import Expect + + +mergeSplit : Int -> Array.Array a -> Array.Array a +mergeSplit n arr = + let + left = + Array.slice 0 n arr + + right = + Array.slice n (Array.length arr) arr + in + Array.append left right + + +holeArray : Array.Array Int +holeArray = + List.foldl mergeSplit (Array.fromList (List.range 0 100)) (List.range 0 100) + + +mapArray : Array.Array a -> Array.Array a +mapArray array = + Array.indexedMap + (\i el -> + case (Array.get i array) of + Just x -> + x + + Nothing -> + el + ) + array + + +tests : Test +tests = + let + creationTests = + describe "Creation" + [ test "empty" <| \() -> Expect.equal Array.empty (Array.fromList []) + , test "initialize" <| \() -> Expect.equal (Array.initialize 4 identity) (Array.fromList [ 0, 1, 2, 3 ]) + , test "initialize 2" <| \() -> Expect.equal (Array.initialize 4 (\n -> n * n)) (Array.fromList [ 0, 1, 4, 9 ]) + , test "initialize 3" <| \() -> Expect.equal (Array.initialize 4 (always 0)) (Array.fromList [ 0, 0, 0, 0 ]) + , test "initialize Empty" <| \() -> Expect.equal (Array.initialize 0 identity) Array.empty + , test "initialize 4" <| \() -> Expect.equal (Array.initialize 2 (always 0)) (Array.fromList [ 0, 0 ]) + , test "initialize negative" <| \() -> Expect.equal (Array.initialize -1 identity) Array.empty + , test "repeat" <| \() -> Expect.equal (Array.repeat 5 40) (Array.fromList [ 40, 40, 40, 40, 40 ]) + , test "repeat 2" <| \() -> Expect.equal (Array.repeat 5 0) (Array.fromList [ 0, 0, 0, 0, 0 ]) + , test "repeat 3" <| \() -> Expect.equal (Array.repeat 3 "cat") (Array.fromList [ "cat", "cat", "cat" ]) + , test "fromList" <| \() -> Expect.equal (Array.fromList []) Array.empty + ] + + basicsTests = + describe "Basics" + [ test "length" <| \() -> Expect.equal 3 (Array.length (Array.fromList [ 1, 2, 3 ])) + , test "length - Long" <| \() -> Expect.equal 10000 (Array.length (Array.repeat 10000 0)) + , test "push" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.push 3 (Array.fromList [ 1, 2 ])) + , test "append" <| \() -> Expect.equal [ 42, 42, 81, 81, 81 ] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81))) + , test "appendEmpty 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append Array.empty (Array.fromList <| List.range 1 33))) + , test "appendEmpty 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 33) Array.empty)) + , test "appendSmall 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 30) (Array.fromList <| List.range 31 33))) + , test "appendSmall 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 3) (Array.fromList <| List.range 4 33))) + , test "appendAndSlice" <| \() -> Expect.equal (List.range 0 100) (Array.toList holeArray) + ] + + getAndSetTests = + describe "Get and Set" + [ test "get" <| \() -> Expect.equal (Just 2) (Array.get 1 (Array.fromList [ 3, 2, 1 ])) + , test "get 2" <| \() -> Expect.equal Nothing (Array.get 5 (Array.fromList [ 3, 2, 1 ])) + , test "get 3" <| \() -> Expect.equal Nothing (Array.get -1 (Array.fromList [ 3, 2, 1 ])) + , test "set" <| \() -> Expect.equal (Array.fromList [ 1, 7, 3 ]) (Array.set 1 7 (Array.fromList [ 1, 2, 3 ])) + ] + + takingArraysApartTests = + describe "Taking Arrays Apart" + [ test "toList" <| \() -> Expect.equal [ 3, 5, 8 ] (Array.toList (Array.fromList [ 3, 5, 8 ])) + , test "toIndexedList" <| \() -> Expect.equal [ ( 0, "cat" ), ( 1, "dog" ) ] (Array.toIndexedList (Array.fromList [ "cat", "dog" ])) + , test "slice 1" <| \() -> Expect.equal (Array.fromList [ 0, 1, 2 ]) (Array.slice 0 3 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 2" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 4 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 3" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 -1 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 4" <| \() -> Expect.equal (Array.fromList [ 2 ]) (Array.slice -3 -2 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 5" <| \() -> Expect.equal 63 (Array.length <| Array.slice 65 (65 + 63) <| Array.fromList (List.range 1 200)) + ] + + mappingAndFoldingTests = + describe "Mapping and Folding" + [ test "map" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.map sqrt (Array.fromList [ 1, 4, 9 ])) + , test "indexedMap 1" <| \() -> Expect.equal (Array.fromList [ 0, 5, 10 ]) (Array.indexedMap (*) (Array.fromList [ 5, 5, 5 ])) + , test "indexedMap 2" <| \() -> Expect.equal (List.range 0 99) (Array.toList (Array.indexedMap always (Array.repeat 100 0))) + , test "large indexed map" <| \() -> Expect.equal (List.range 0 <| 32768 - 1) (Array.toList <| mapArray <| Array.initialize 32768 identity) + , test "foldl 1" <| \() -> Expect.equal [ 3, 2, 1 ] (Array.foldl (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldl 2" <| \() -> Expect.equal 33 (Array.foldl (+) 0 (Array.repeat 33 1)) + , test "foldr 1" <| \() -> Expect.equal 15 (Array.foldr (+) 0 (Array.repeat 3 5)) + , test "foldr 2" <| \() -> Expect.equal [ 1, 2, 3 ] (Array.foldr (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldr 3" <| \() -> Expect.equal 53 (Array.foldr (-) 54 (Array.fromList [ 10, 11 ])) + , test "filter" <| \() -> Expect.equal (Array.fromList [ 2, 4, 6 ]) (Array.filter (\x -> x % 2 == 0) (Array.fromList <| List.range 1 6)) + ] + + nativeTests = + describe "Conversion to JS Arrays" + [ test "jsArrays" <| \() -> Expect.equal (Array.fromList <| List.range 1 1100) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList <| List.range 1 1100))) + ] + in + describe "Array" + [ creationTests + , basicsTests + , getAndSetTests + , takingArraysApartTests + , mappingAndFoldingTests + , nativeTests + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm new file mode 100644 index 0000000..56742cb --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm @@ -0,0 +1,220 @@ +module Test.Basics exposing (tests) + +import Array +import Tuple exposing (first, second) +import Basics exposing (..) +import Date +import Set +import Dict +import Test exposing (..) +import Expect +import List +import String + + +tests : Test +tests = + let + comparison = + describe "Comparison" + [ test "max" <| \() -> Expect.equal 42 (max 32 42) + , test "min" <| \() -> Expect.equal 42 (min 91 42) + , test "clamp low" <| \() -> Expect.equal 10 (clamp 10 20 5) + , test "clamp mid" <| \() -> Expect.equal 15 (clamp 10 20 15) + , test "clamp high" <| \() -> Expect.equal 20 (clamp 10 20 25) + , test "5 < 6" <| \() -> Expect.equal True (5 < 6) + , test "6 < 5" <| \() -> Expect.equal False (6 < 5) + , test "6 < 6" <| \() -> Expect.equal False (6 < 6) + , test "5 > 6" <| \() -> Expect.equal False (5 > 6) + , test "6 > 5" <| \() -> Expect.equal True (6 > 5) + , test "6 > 6" <| \() -> Expect.equal False (6 > 6) + , test "5 <= 6" <| \() -> Expect.equal True (5 <= 6) + , test "6 <= 5" <| \() -> Expect.equal False (6 <= 5) + , test "6 <= 6" <| \() -> Expect.equal True (6 <= 6) + , test "compare \"A\" \"B\"" <| \() -> Expect.equal LT (compare "A" "B") + , test "compare 'f' 'f'" <| \() -> Expect.equal EQ (compare 'f' 'f') + , test "compare (1, 2, 3, 4, 5, 6) (0, 1, 2, 3, 4, 5)" <| \() -> Expect.equal GT (compare ( 1, 2, 3, 4, 5, 6 ) ( 0, 1, 2, 3, 4, 5 )) + , test "compare ['a'] ['b']" <| \() -> Expect.equal LT (compare [ 'a' ] [ 'b' ]) + , test "array equality" <| \() -> Expect.equal (Array.fromList [ 1, 1, 1, 1 ]) (Array.repeat 4 1) + , test "set equality" <| \() -> Expect.equal (Set.fromList [ 1, 2 ]) (Set.fromList [ 2, 1 ]) + , test "dict equality" <| \() -> Expect.equal (Dict.fromList [ ( 1, 1 ), ( 2, 2 ) ]) (Dict.fromList [ ( 2, 2 ), ( 1, 1 ) ]) + , test "char equality" <| \() -> Expect.notEqual '0' '饑' + , test "date equality" <| \() -> Expect.equal (Date.fromString "2/7/1992") (Date.fromString "2/7/1992") + , test "date equality" <| \() -> Expect.notEqual (Date.fromString "11/16/1995") (Date.fromString "2/7/1992") + ] + + toStringTests = + describe "toString Tests" + [ test "toString Int" <| \() -> Expect.equal "42" (toString 42) + , test "toString Float" <| \() -> Expect.equal "42.52" (toString 42.52) + , test "toString Char" <| \() -> Expect.equal "'c'" (toString 'c') + , test "toString Char single quote" <| \() -> Expect.equal "'\\''" (toString '\'') + , test "toString Char double quote" <| \() -> Expect.equal "'\"'" (toString '"') + , test "toString String single quote" <| \() -> Expect.equal "\"not 'escaped'\"" (toString "not 'escaped'") + , test "toString String double quote" <| \() -> Expect.equal "\"are \\\"escaped\\\"\"" (toString "are \"escaped\"") + , test "toString record" <| \() -> Expect.equal "{ field = [0] }" (toString { field = [ 0 ] }) + -- TODO + --, test "toString record, special case" <| \() -> Expect.equal "{ ctor = [0] }" (toString { ctor = [ 0 ] }) + ] + + trigTests = + describe "Trigonometry Tests" + [ test "radians 0" <| \() -> Expect.equal 0 (radians 0) + , test "radians positive" <| \() -> Expect.equal 5 (radians 5) + , test "radians negative" <| \() -> Expect.equal -5 (radians -5) + , test "degrees 0" <| \() -> Expect.equal 0 (degrees 0) + , test "degrees 90" <| \() -> Expect.lessThan 0.01 (abs (1.57 - degrees 90)) + -- This should test to enough precision to know if anything's breaking + , test "degrees -145" <| \() -> Expect.lessThan 0.01 (abs (-2.53 - degrees -145)) + -- This should test to enough precision to know if anything's breaking + , test "turns 0" <| \() -> Expect.equal 0 (turns 0) + , test "turns 8" <| \() -> Expect.lessThan 0.01 (abs (50.26 - turns 8)) + -- This should test to enough precision to know if anything's breaking + , test "turns -133" <| \() -> Expect.lessThan 0.01 (abs (-835.66 - turns -133)) + -- This should test to enough precision to know if anything's breaking + , test "fromPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 0 )) + , test "fromPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (fromPolar ( 1, 0 )) + , test "fromPolar (0, 1)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 1 )) + , test "fromPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( x, y ) = + fromPolar ( 1, 1 ) + in + 0.54 - x < 0.01 && 0.84 - y < 0.01 + ) + , test "toPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (toPolar ( 0, 0 )) + , test "toPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (toPolar ( 1, 0 )) + , test "toPolar (0, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 0, 1 ) + in + r == 1 && abs (1.57 - theta) < 0.01 + ) + , test "toPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 1, 1 ) + in + abs (1.41 - r) < 0.01 && abs (0.78 - theta) < 0.01 + ) + , test "cos" <| \() -> Expect.equal 1 (cos 0) + , test "sin" <| \() -> Expect.equal 0 (sin 0) + , test "tan" <| \() -> Expect.lessThan 0.01 (abs (12.67 - tan 17.2)) + , test "acos" <| \() -> Expect.lessThan 0.01 (abs (3.14 - acos -1)) + , test "asin" <| \() -> Expect.lessThan 0.01 (abs (0.3 - asin 0.3)) + , test "atan" <| \() -> Expect.lessThan 0.01 (abs (1.57 - atan 4567.8)) + , test "atan2" <| \() -> Expect.lessThan 0.01 (abs (1.55 - atan2 36 0.65)) + , test "pi" <| \() -> Expect.lessThan 0.01 (abs (3.14 - pi)) + ] + + basicMathTests = + describe "Basic Math Tests" + [ test "add float" <| \() -> Expect.equal 159 (155.6 + 3.4) + , test "add int" <| \() -> Expect.equal 17 ((round 10) + (round 7)) + , test "subtract float" <| \() -> Expect.equal -6.3 (1 - 7.3) + , test "subtract int" <| \() -> Expect.equal 1130 ((round 9432) - (round 8302)) + , test "multiply float" <| \() -> Expect.equal 432 (96 * 4.5) + , test "multiply int" <| \() -> Expect.equal 90 ((round 10) * (round 9)) + , test "divide float" <| \() -> Expect.equal 13.175 (527 / 40) + , test "divide int" <| \() -> Expect.equal 23 (70 // 3) + , test "2 |> rem 7" <| \() -> Expect.equal 1 (2 |> rem 7) + , test "4 |> rem -1" <| \() -> Expect.equal -1 (4 |> rem -1) + , test "7 % 2" <| \() -> Expect.equal 1 (7 % 2) + , test "-1 % 4" <| \() -> Expect.equal 3 (-1 % 4) + , test "3^2" <| \() -> Expect.equal 9 (3 ^ 2) + , test "sqrt" <| \() -> Expect.equal 9 (sqrt 81) + , test "negate 42" <| \() -> Expect.equal -42 (negate 42) + , test "negate -42" <| \() -> Expect.equal 42 (negate -42) + , test "negate 0" <| \() -> Expect.equal 0 (negate 0) + , test "abs -25" <| \() -> Expect.equal 25 (abs -25) + , test "abs 76" <| \() -> Expect.equal 76 (abs 76) + , test "logBase 10 100" <| \() -> Expect.equal 2 (logBase 10 100) + , test "logBase 2 256" <| \() -> Expect.equal 8 (logBase 2 256) + , test "e" <| \() -> Expect.lessThan 0.01 (abs (2.72 - e)) + ] + + booleanTests = + describe "Boolean Tests" + [ test "False && False" <| \() -> Expect.equal False (False && False) + , test "False && True" <| \() -> Expect.equal False (False && True) + , test "True && False" <| \() -> Expect.equal False (True && False) + , test "True && True" <| \() -> Expect.equal True (True && True) + , test "False || False" <| \() -> Expect.equal False (False || False) + , test "False || True" <| \() -> Expect.equal True (False || True) + , test "True || False" <| \() -> Expect.equal True (True || False) + , test "True || True" <| \() -> Expect.equal True (True || True) + , test "xor False False" <| \() -> Expect.equal False (xor False False) + , test "xor False True" <| \() -> Expect.equal True (xor False True) + , test "xor True False" <| \() -> Expect.equal True (xor True False) + , test "xor True True" <| \() -> Expect.equal False (xor True True) + , test "not True" <| \() -> Expect.equal False (not True) + , test "not False" <| \() -> Expect.equal True (not False) + ] + + conversionTests = + describe "Conversion Tests" + [ test "round 0.6" <| \() -> Expect.equal 1 (round 0.6) + , test "round 0.4" <| \() -> Expect.equal 0 (round 0.4) + , test "round 0.5" <| \() -> Expect.equal 1 (round 0.5) + , test "truncate -2367.9267" <| \() -> Expect.equal -2367 (truncate -2367.9267) + , test "floor -2367.9267" <| \() -> Expect.equal -2368 (floor -2367.9267) + , test "ceiling 37.2" <| \() -> Expect.equal 38 (ceiling 37.2) + , test "toFloat 25" <| \() -> Expect.equal 25 (toFloat 25) + ] + + miscTests = + describe "Miscellaneous Tests" + [ test "isNaN (0/0)" <| \() -> Expect.equal True (isNaN (0 / 0)) + , test "isNaN (sqrt -1)" <| \() -> Expect.equal True (isNaN (sqrt -1)) + , test "isNaN (1/0)" <| \() -> Expect.equal False (isNaN (1 / 0)) + , test "isNaN 1" <| \() -> Expect.equal False (isNaN 1) + , test "isInfinite (0/0)" <| \() -> Expect.equal False (isInfinite (0 / 0)) + , test "isInfinite (sqrt -1)" <| \() -> Expect.equal False (isInfinite (sqrt -1)) + , test "isInfinite (1/0)" <| \() -> Expect.equal True (isInfinite (1 / 0)) + , test "isInfinite 1" <| \() -> Expect.equal False (isInfinite 1) + , test "\"hello\" ++ \"world\"" <| \() -> Expect.equal "helloworld" ("hello" ++ "world") + , test "[1, 1, 2] ++ [3, 5, 8]" <| \() -> Expect.equal [ 1, 1, 2, 3, 5, 8 ] ([ 1, 1, 2 ] ++ [ 3, 5, 8 ]) + , test "first (1, 2)" <| \() -> Expect.equal 1 (first ( 1, 2 )) + , test "second (1, 2)" <| \() -> Expect.equal 2 (second ( 1, 2 )) + ] + + higherOrderTests = + describe "Higher Order Helpers" + [ test "identity 'c'" <| \() -> Expect.equal 'c' (identity 'c') + , test "always 42 ()" <| \() -> Expect.equal 42 (always 42 ()) + , test "<|" <| \() -> Expect.equal 9 (identity <| 3 + 6) + , test "|>" <| \() -> Expect.equal 9 (3 + 6 |> identity) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , describe ">>" + [ test "with xor" <| + \() -> + (True |> xor True >> not) + |> Expect.equal True + , test "with a record accessor" <| + \() -> + [ { foo = "NaS", bar = "baz" } ] + |> List.map (.foo >> String.reverse) + |> Expect.equal [ "SaN" ] + ] + , test "flip" <| \() -> Expect.equal 10 ((flip (//)) 2 20) + , test "curry" <| \() -> Expect.equal 1 ((curry (\( a, b ) -> a + b)) -5 6) + , test "uncurry" <| \() -> Expect.equal 1 ((uncurry (+)) ( -5, 6 )) + ] + in + describe "Basics" + [ comparison + , toStringTests + , trigTests + , basicMathTests + , booleanTests + , miscTests + , higherOrderTests + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm new file mode 100644 index 0000000..844ebba --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm @@ -0,0 +1,51 @@ +module Test.Bitwise exposing (tests) + +import Basics exposing (..) +import Bitwise +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Bitwise" + [ describe "and" + [ test "and with 32 bit integers" <| \() -> Expect.equal 1 (Bitwise.and 5 3) + , test "and with 0 as first argument" <| \() -> Expect.equal 0 (Bitwise.and 0 1450) + , test "and with 0 as second argument" <| \() -> Expect.equal 0 (Bitwise.and 274 0) + , test "and with -1 as first argument" <| \() -> Expect.equal 2671 (Bitwise.and -1 2671) + , test "and with -1 as second argument" <| \() -> Expect.equal 96 (Bitwise.and 96 -1) + ] + , describe "or" + [ test "or with 32 bit integers" <| \() -> Expect.equal 15 (Bitwise.or 9 14) + , test "or with 0 as first argument" <| \() -> Expect.equal 843 (Bitwise.or 0 843) + , test "or with 0 as second argument" <| \() -> Expect.equal 19 (Bitwise.or 19 0) + , test "or with -1 as first argument" <| \() -> Expect.equal -1 (Bitwise.or -1 2360) + , test "or with -1 as second argument" <| \() -> Expect.equal -1 (Bitwise.or 3 -1) + ] + , describe "xor" + [ test "xor with 32 bit integers" <| \() -> Expect.equal 604 (Bitwise.xor 580 24) + , test "xor with 0 as first argument" <| \() -> Expect.equal 56 (Bitwise.xor 0 56) + , test "xor with 0 as second argument" <| \() -> Expect.equal -268 (Bitwise.xor -268 0) + , test "xor with -1 as first argument" <| \() -> Expect.equal -25 (Bitwise.xor -1 24) + , test "xor with -1 as second argument" <| \() -> Expect.equal 25601 (Bitwise.xor -25602 -1) + ] + , describe "complement" + [ test "complement a positive" <| \() -> Expect.equal -9 (Bitwise.complement 8) + , test "complement a negative" <| \() -> Expect.equal 278 (Bitwise.complement -279) + ] + , describe "shiftLeftBy" + [ test "8 |> shiftLeftBy 1 == 16" <| \() -> Expect.equal 16 (8 |> Bitwise.shiftLeftBy 1) + , test "8 |> shiftLeftby 2 == 32" <| \() -> Expect.equal 32 (8 |> Bitwise.shiftLeftBy 2) + ] + , describe "shiftRightBy" + [ test "32 |> shiftRight 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightBy 1) + , test "32 |> shiftRight 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightBy 2) + , test "-32 |> shiftRight 1 == -16" <| \() -> Expect.equal -16 (-32 |> Bitwise.shiftRightBy 1) + ] + , describe "shiftRightZfBy" + [ test "32 |> shiftRightZfBy 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightZfBy 1) + , test "32 |> shiftRightZfBy 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightZfBy 2) + , test "-32 |> shiftRightZfBy 1 == 2147483632" <| \() -> Expect.equal 2147483632 (-32 |> Bitwise.shiftRightZfBy 1) + ] + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm new file mode 100644 index 0000000..598aae3 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm @@ -0,0 +1,113 @@ +module Test.Char exposing (tests) + +import Basics exposing (..) +import Char exposing (..) +import List +import Test exposing (..) +import Expect + + +lower = + [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] + + +upper = + [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] + + +dec = + [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] + + +oct = + List.take 8 dec + + +hexLower = + List.take 6 lower + + +hexUpper = + List.take 6 upper + + +hex = + List.append hexLower hexUpper |> List.append dec + + +lowerCodes = + List.range 97 (97 + List.length lower - 1) + + +upperCodes = + List.range 65 (65 + List.length upper - 1) + + +decCodes = + List.range 48 (48 + List.length dec - 1) + + +oneOf : List a -> a -> Bool +oneOf = + flip List.member + + +tests : Test +tests = + describe "Char" + [ describe "toCode" + [ test "a-z" <| \() -> Expect.equal (lowerCodes) (List.map toCode lower) + , test "A-Z" <| \() -> Expect.equal (upperCodes) (List.map toCode upper) + , test "0-9" <| \() -> Expect.equal (decCodes) (List.map toCode dec) + ] + , describe "fromCode" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map fromCode lowerCodes) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map fromCode upperCodes) + , test "0-9" <| \() -> Expect.equal (dec) (List.map fromCode decCodes) + ] + , describe "toLocaleLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLocaleLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLocaleLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleLower dec) + ] + , describe "toLocaleUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleUpper dec) + ] + , describe "toLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLower dec) + ] + , describe "toUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toUpper dec) + ] + , describe "isLower" + [ test "a-z" <| \() -> Expect.equal (True) (List.all isLower lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isLower upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isLower dec) + ] + , describe "isUpper" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isUpper lower) + , test "A-Z" <| \() -> Expect.equal (True) (List.all isUpper upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isUpper dec) + ] + , describe "isDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isDigit dec) + ] + , describe "isHexDigit" + [ test "a-z" <| \() -> Expect.equal (List.map (oneOf hex) lower) (List.map isHexDigit lower) + , test "A-Z" <| \() -> Expect.equal (List.map (oneOf hex) upper) (List.map isHexDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isHexDigit dec) + ] + , describe "isOctDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isOctDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isOctDigit upper) + , test "0-9" <| \() -> Expect.equal (List.map (oneOf oct) dec) (List.map isOctDigit dec) + ] + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm new file mode 100644 index 0000000..4a89c63 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm @@ -0,0 +1,109 @@ +module Test.CodeGen exposing (tests) + +import Basics exposing (..) +import Test exposing (..) +import Expect +import Maybe +import Maybe exposing (..) + + +type Wrapper a + = Wrapper a + + +caseUnderscore : Maybe number -> number +caseUnderscore m_ = + case m_ of + Just x -> + x + + Nothing -> + 0 + + +patternUnderscore : number +patternUnderscore = + case Just 42 of + Just x_ -> + x_ + + Nothing -> + 0 + + +letQualified : number +letQualified = + let + (Wrapper x) = + Wrapper 42 + in + x + + +caseQualified : number +caseQualified = + case Just 42 of + Maybe.Just x -> + x + + Nothing -> + 0 + + +caseScope : String +caseScope = + case "Not this one!" of + string -> + case "Hi" of + string -> + string + + +tests : Test +tests = + let + -- We don't strictly speaking need annotations in this let-expression, + -- but having these here exercises the parser to avoid regressions like + -- https://github.com/elm-lang/elm-compiler/issues/1535 + underscores : Test + underscores = + describe "Underscores" + [ test "case" <| \() -> Expect.equal 42 (caseUnderscore (Just 42)) + , test "pattern" <| \() -> Expect.equal 42 patternUnderscore + ] + + qualifiedPatterns : Test + qualifiedPatterns = + describe "Qualified Patterns" + [ test "let" <| \() -> Expect.equal 42 letQualified + , test "case" <| \() -> Expect.equal 42 caseQualified + ] + + scope : Test + scope = + describe "Scoping" + [ test "case" <| \() -> Expect.equal "Hi" caseScope ] + + hex : Test + hex = + describe "Hex" + [ test "0xFFFFFFFF" <| + \() -> + 0xFFFFFFFF + |> Expect.equal 4294967295 + , test "0xD066F00D" <| + \() -> + 0xD066F00D + |> Expect.equal 3496407053 + , test "0x00" <| + \() -> + 0x00 + |> Expect.equal 0 + ] + in + describe "CodeGen" + [ underscores + , qualifiedPatterns + , scope + , hex + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm new file mode 100644 index 0000000..372b2c9 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm @@ -0,0 +1,107 @@ +module Test.Dict exposing (tests) + +import Basics exposing (..) +import Dict +import List +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +animals : Dict.Dict String String +animals = + Dict.fromList [ ( "Tom", "cat" ), ( "Jerry", "mouse" ) ] + + +tests : Test +tests = + let + buildTests = + describe "build Tests" + [ test "empty" <| \() -> Expect.equal (Dict.fromList []) (Dict.empty) + , test "singleton" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.singleton "k" "v") + , test "insert" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.insert "k" "v" Dict.empty) + , test "insert replace" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.insert "k" "vv" (Dict.singleton "k" "v")) + , test "update" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.update "k" (\v -> Just "vv") (Dict.singleton "k" "v")) + , test "update Nothing" <| \() -> Expect.equal Dict.empty (Dict.update "k" (\v -> Nothing) (Dict.singleton "k" "v")) + , test "remove" <| \() -> Expect.equal Dict.empty (Dict.remove "k" (Dict.singleton "k" "v")) + , test "remove not found" <| \() -> Expect.equal (Dict.singleton "k" "v") (Dict.remove "kk" (Dict.singleton "k" "v")) + ] + + queryTests = + describe "query Tests" + [ test "member 1" <| \() -> Expect.equal True (Dict.member "Tom" animals) + , test "member 2" <| \() -> Expect.equal False (Dict.member "Spike" animals) + , test "get 1" <| \() -> Expect.equal (Just "cat") (Dict.get "Tom" animals) + , test "get 2" <| \() -> Expect.equal Nothing (Dict.get "Spike" animals) + , test "size of empty dictionary" <| \() -> Expect.equal 0 (Dict.size Dict.empty) + , test "size of example dictionary" <| \() -> Expect.equal 2 (Dict.size animals) + ] + + combineTests = + describe "combine Tests" + [ test "union" <| \() -> Expect.equal animals (Dict.union (Dict.singleton "Jerry" "mouse") (Dict.singleton "Tom" "cat")) + , test "union collison" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.union (Dict.singleton "Tom" "cat") (Dict.singleton "Tom" "mouse")) + , test "intersect" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.intersect animals (Dict.singleton "Tom" "cat")) + , test "diff" <| \() -> Expect.equal (Dict.singleton "Jerry" "mouse") (Dict.diff animals (Dict.singleton "Tom" "cat")) + ] + + transformTests = + describe "transform Tests" + [ test "filter" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals) + , test "partition" <| \() -> Expect.equal ( Dict.singleton "Tom" "cat", Dict.singleton "Jerry" "mouse" ) (Dict.partition (\k v -> k == "Tom") animals) + ] + + mergeTests = + let + insertBoth key leftVal rightVal dict = + Dict.insert key (leftVal ++ rightVal) dict + + s1 = + Dict.empty |> Dict.insert "u1" [ 1 ] + + s2 = + Dict.empty |> Dict.insert "u2" [ 2 ] + + s23 = + Dict.empty |> Dict.insert "u2" [ 3 ] + + b1 = + List.map (\i -> ( i, [ i ] )) (List.range 1 10) |> Dict.fromList + + b2 = + List.map (\i -> ( i, [ i ] )) (List.range 5 15) |> Dict.fromList + + bExpected = + [ ( 1, [ 1 ] ), ( 2, [ 2 ] ), ( 3, [ 3 ] ), ( 4, [ 4 ] ), ( 5, [ 5, 5 ] ), ( 6, [ 6, 6 ] ), ( 7, [ 7, 7 ] ), ( 8, [ 8, 8 ] ), ( 9, [ 9, 9 ] ), ( 10, [ 10, 10 ] ), ( 11, [ 11 ] ), ( 12, [ 12 ] ), ( 13, [ 13 ] ), ( 14, [ 14 ] ), ( 15, [ 15 ] ) ] + in + describe "merge Tests" + [ test "merge empties" <| + \() -> + Expect.equal (Dict.empty) + (Dict.merge Dict.insert insertBoth Dict.insert Dict.empty Dict.empty Dict.empty) + , test "merge singletons in order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s1 s2 Dict.empty) |> Dict.toList) + , test "merge singletons out of order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s1 Dict.empty) |> Dict.toList) + , test "merge with duplicate key" <| + \() -> + Expect.equal [ ( "u2", [ 2, 3 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s23 Dict.empty) |> Dict.toList) + , test "partially overlapping" <| + \() -> + Expect.equal bExpected + ((Dict.merge Dict.insert insertBoth Dict.insert b1 b2 Dict.empty) |> Dict.toList) + ] + in + describe "Dict Tests" + [ buildTests + , queryTests + , combineTests + , transformTests + , mergeTests + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm new file mode 100644 index 0000000..1737477 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm @@ -0,0 +1,34 @@ +module Test.Equality exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +type Different + = A String + | B (List Int) + + +tests : Test +tests = + let + diffTests = + describe "ADT equality" + [ test "As eq" <| \() -> Expect.equal True (A "a" == A "a") + , test "Bs eq" <| \() -> Expect.equal True (B [ 1 ] == B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (A "a" /= B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (B [ 1 ] /= A "a") + ] + + recordTests = + describe "Record equality" + [ test "empty same" <| \() -> Expect.equal True ({} == {}) + , test "ctor same" <| \() -> Expect.equal True ({ field = Just 3 } == { field = Just 3 }) + , test "ctor same, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } == { ctor = Just 3 }) + , test "ctor diff" <| \() -> Expect.equal True ({ field = Just 3 } /= { field = Nothing }) + , test "ctor diff, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } /= { ctor = Nothing }) + ] + in + describe "Equality Tests" [ diffTests, recordTests ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm new file mode 100644 index 0000000..614a1dd --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm @@ -0,0 +1,84 @@ +module Test.Json exposing (tests) + +import Basics exposing (..) +import Result exposing (..) +import Json.Decode as Json +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Json decode" + [ intTests + , customTests + ] + + +intTests : Test +intTests = + let + testInt val str = + case Json.decodeString Json.int str of + Ok _ -> + Expect.equal val True + + Err _ -> + Expect.equal val False + in + describe "Json decode int" + [ test "whole int" <| \() -> testInt True "4" + , test "-whole int" <| \() -> testInt True "-4" + , test "whole float" <| \() -> testInt True "4.0" + , test "-whole float" <| \() -> testInt True "-4.0" + , test "large int" <| \() -> testInt True "1801439850948" + , test "-large int" <| \() -> testInt True "-1801439850948" + , test "float" <| \() -> testInt False "4.2" + , test "-float" <| \() -> testInt False "-4.2" + , test "Infinity" <| \() -> testInt False "Infinity" + , test "-Infinity" <| \() -> testInt False "-Infinity" + , test "NaN" <| \() -> testInt False "NaN" + , test "-NaN" <| \() -> testInt False "-NaN" + , test "true" <| \() -> testInt False "true" + , test "false" <| \() -> testInt False "false" + , test "string" <| \() -> testInt False "\"string\"" + , test "object" <| \() -> testInt False "{}" + , test "null" <| \() -> testInt False "null" + , test "undefined" <| \() -> testInt False "undefined" + , test "Decoder expects object finds array, was crashing runtime." <| + \() -> + Expect.equal + (Err "Expecting an object but instead got: []") + (Json.decodeString (Json.dict Json.float) "[]") + ] + + +customTests : Test +customTests = + let + jsonString = + """{ "foo": "bar" }""" + + customErrorMessage = + "I want to see this message!" + + myDecoder = + Json.field "foo" Json.string |> Json.andThen (\_ -> Json.fail customErrorMessage) + + assertion = + case Json.decodeString myDecoder jsonString of + Ok _ -> + Expect.fail "expected `customDecoder` to produce a value of type Err, but got Ok" + + Err message -> + if String.contains customErrorMessage message then + Expect.pass + else + Expect.fail <| + "expected `customDecoder` to preserve user's error message '" + ++ customErrorMessage + ++ "', but instead got: " + ++ message + in + test "customDecoder preserves user error messages" <| \() -> assertion diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm new file mode 100644 index 0000000..ed26f0f --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm @@ -0,0 +1,160 @@ +module Test.List exposing (tests) + +import Test exposing (..) +import Expect +import Basics exposing (..) +import Maybe exposing (Maybe(Nothing, Just)) +import List exposing (..) + + +tests : Test +tests = + describe "List Tests" + [ testListOfN 0 + , testListOfN 1 + , testListOfN 2 + , testListOfN 5000 + ] + + +testListOfN : Int -> Test +testListOfN n = + let + xs = + List.range 1 n + + xsOpp = + List.range -n -1 + + xsNeg = + foldl (::) [] xsOpp + + -- assume foldl and (::) work + zs = + List.range 0 n + + sumSeq k = + k * (k + 1) // 2 + + xsSum = + sumSeq n + + mid = + n // 2 + in + describe (toString n ++ " elements") + [ describe "foldl" + [ test "order" <| \() -> Expect.equal (n) (foldl (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "foldr" + [ test "order" <| \() -> Expect.equal (min 1 n) (foldr (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "map" + [ test "identity" <| \() -> Expect.equal (xs) (map identity xs) + , test "linear" <| \() -> Expect.equal (List.range 2 (n + 1)) (map ((+) 1) xs) + ] + , test "isEmpty" <| \() -> Expect.equal (n == 0) (isEmpty xs) + , test "length" <| \() -> Expect.equal (n) (length xs) + , test "reverse" <| \() -> Expect.equal (xsOpp) (reverse xsNeg) + , describe "member" + [ test "positive" <| \() -> Expect.equal (True) (member n zs) + , test "negative" <| \() -> Expect.equal (False) (member (n + 1) xs) + ] + , test "head" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (head xs) + else + Expect.equal (Just 1) (head xs) + , describe "List.filter" + [ test "none" <| \() -> Expect.equal ([]) (List.filter (\x -> x > n) xs) + , test "one" <| \() -> Expect.equal ([ n ]) (List.filter (\z -> z == n) zs) + , test "all" <| \() -> Expect.equal (xs) (List.filter (\x -> x <= n) xs) + ] + , describe "take" + [ test "none" <| \() -> Expect.equal ([]) (take 0 xs) + , test "some" <| \() -> Expect.equal (List.range 0 (n - 1)) (take n zs) + , test "all" <| \() -> Expect.equal (xs) (take n xs) + , test "all+" <| \() -> Expect.equal (xs) (take (n + 1) xs) + ] + , describe "drop" + [ test "none" <| \() -> Expect.equal (xs) (drop 0 xs) + , test "some" <| \() -> Expect.equal ([ n ]) (drop n zs) + , test "all" <| \() -> Expect.equal ([]) (drop n xs) + , test "all+" <| \() -> Expect.equal ([]) (drop (n + 1) xs) + ] + , test "repeat" <| \() -> Expect.equal (map (\x -> -1) xs) (repeat n -1) + , test "append" <| \() -> Expect.equal (xsSum * 2) (append xs xs |> foldl (+) 0) + , test "(::)" <| \() -> Expect.equal (append [ -1 ] xs) (-1 :: xs) + , test "List.concat" <| \() -> Expect.equal (append xs (append zs xs)) (List.concat [ xs, zs, xs ]) + , test "intersperse" <| + \() -> + Expect.equal + ( min -(n - 1) 0, xsSum ) + (intersperse -1 xs |> foldl (\x ( c1, c2 ) -> ( c2, c1 + x )) ( 0, 0 )) + , describe "partition" + [ test "left" <| \() -> Expect.equal ( xs, [] ) (partition (\x -> x > 0) xs) + , test "right" <| \() -> Expect.equal ( [], xs ) (partition (\x -> x < 0) xs) + , test "split" <| \() -> Expect.equal ( List.range (mid + 1) n, List.range 1 mid ) (partition (\x -> x > mid) xs) + ] + , describe "map2" + [ test "same length" <| \() -> Expect.equal (map ((*) 2) xs) (map2 (+) xs xs) + , test "long first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) zs xs) + , test "short first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) xs zs) + ] + , test "unzip" <| \() -> Expect.equal ( xsNeg, xs ) (map (\x -> ( -x, x )) xs |> unzip) + , describe "filterMap" + [ test "none" <| \() -> Expect.equal ([]) (filterMap (\x -> Nothing) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (filterMap (\x -> Just -x) xs) + , let + halve x = + if x % 2 == 0 then + Just (x // 2) + else + Nothing + in + test "some" <| \() -> Expect.equal (List.range 1 mid) (filterMap halve xs) + ] + , describe "concatMap" + [ test "none" <| \() -> Expect.equal ([]) (concatMap (\x -> []) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (concatMap (\x -> [ -x ]) xs) + ] + , test "indexedMap" <| \() -> Expect.equal (map2 (,) zs xsNeg) (indexedMap (\i x -> ( i, -x )) xs) + , test "sum" <| \() -> Expect.equal (xsSum) (sum xs) + , test "product" <| \() -> Expect.equal (0) (product zs) + , test "maximum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (maximum xs) + else + Expect.equal (Just n) (maximum xs) + , test "minimum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (minimum xs) + else + Expect.equal (Just 1) (minimum xs) + , describe "all" + [ test "false" <| \() -> Expect.equal (False) (all (\z -> z < n) zs) + , test "true" <| \() -> Expect.equal (True) (all (\x -> x <= n) xs) + ] + , describe "any" + [ test "false" <| \() -> Expect.equal (False) (any (\x -> x > n) xs) + , test "true" <| \() -> Expect.equal (True) (any (\z -> z >= n) zs) + ] + , describe "sort" + [ test "sorted" <| \() -> Expect.equal (xs) (sort xs) + , test "unsorted" <| \() -> Expect.equal (xsOpp) (sort xsNeg) + ] + , describe "sortBy" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsOpp) + ] + , describe "sortWith" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsOpp) + ] + , test "scanl" <| \() -> Expect.equal (0 :: map sumSeq xs) (scanl (+) 0 xs) + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm new file mode 100644 index 0000000..dfa8e5e --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm @@ -0,0 +1,169 @@ +module Test.Maybe exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + +tests : Test +tests = + describe "Maybe Tests" + + [ describe "Common Helpers Tests" + + [ describe "withDefault Tests" + [ test "no default used" <| + \() -> Expect.equal 0 (Maybe.withDefault 5 (Just 0)) + , test "default used" <| + \() -> Expect.equal 5 (Maybe.withDefault 5 (Nothing)) + ] + + , describe "map Tests" + ( let f = (\n -> n + 1) in + [ test "on Just" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map f (Just 0)) + , test "on Nothing" <| + \() -> + Expect.equal + Nothing + (Maybe.map f Nothing) + ] + ) + + , describe "map2 Tests" + ( let f = (+) in + [ test "on (Just, Just)" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map2 f (Just 0) (Just 1)) + , test "on (Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f (Just 0) Nothing) + , test "on (Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f Nothing (Just 0)) + ] + ) + + , describe "map3 Tests" + ( let f = (\a b c -> a + b + c) in + [ test "on (Just, Just, Just)" <| + \() -> + Expect.equal + (Just 3) + (Maybe.map3 f (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) (Just 1) Nothing) + , test "on (Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) Nothing (Just 1)) + , test "on (Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f Nothing (Just 1) (Just 1)) + ] + ) + + , describe "map4 Tests" + ( let f = (\a b c d -> a + b + c + d) in + [ test "on (Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 4) + (Maybe.map4 f (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f Nothing (Just 1) (Just 1) (Just 1)) + ] + ) + + , describe "map5 Tests" + ( let f = (\a b c d e -> a + b + c + d + e) in + [ test "on (Just, Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 5) + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Just, Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) Nothing (Just 1) (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f Nothing (Just 1) (Just 1) (Just 1) (Just 1)) + ] + ) + + ] + + , describe "Chaining Maybes Tests" + + [ describe "andThen Tests" + [ test "succeeding chain" <| + \() -> + Expect.equal + (Just 1) + (Maybe.andThen (\a -> Just a) (Just 1)) + , test "failing chain (original Maybe failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Just a) Nothing) + , test "failing chain (chained function failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Nothing) (Just 1)) + ] + ] + + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm new file mode 100644 index 0000000..478d44b --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm @@ -0,0 +1,57 @@ +module Test.Regex exposing (tests) + +import Basics exposing (..) +import Regex exposing (..) +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "split All" <| \() -> Expect.equal [ "a", "b" ] (split All (regex ",") "a,b") + , test "split" <| \() -> Expect.equal [ "a", "b,c" ] (split (AtMost 1) (regex ",") "a,b,c") + , test "split idempotent" <| + \() -> + let + findComma = + regex "," + in + Expect.equal + (split (AtMost 1) findComma "a,b,c,d,e") + (split (AtMost 1) findComma "a,b,c,d,e") + , test "find All" <| + \() -> + Expect.equal + ([ Match "a" [] 0 1, Match "b" [] 1 2 ]) + (find All (regex ".") "ab") + , test "find All" <| + \() -> + Expect.equal + ([ Match "" [] 0 1 ]) + (find All (regex ".*") "") + , test "replace AtMost 0" <| + \() -> + Expect.equal "The quick brown fox" + (replace (AtMost 0) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 1" <| + \() -> + Expect.equal "Th quick brown fox" + (replace (AtMost 1) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 2" <| + \() -> + Expect.equal "Th qick brown fox" + (replace (AtMost 2) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace All" <| + \() -> + Expect.equal "Th qck brwn fx" + (replace All (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace using index" <| + \() -> + Expect.equal "a1b3c" + (replace All (regex ",") (\match -> toString match.index) "a,b,c") + ] + in + describe "Regex" [ simpleTests ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm new file mode 100644 index 0000000..6679e7e --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm @@ -0,0 +1,70 @@ +module Test.Result exposing (tests) + +import Basics exposing (..) +import Result +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +isEven n = + if n % 2 == 0 then + Ok n + else + Err "number is odd" + + +add3 a b c = + a + b + c + + +add4 a b c d = + a + b + c + d + + +add5 a b c d e = + a + b + c + d + e + + +tests : Test +tests = + let + mapTests = + describe "map Tests" + [ test "map Ok" <| \() -> Expect.equal (Ok 3) (Result.map ((+) 1) (Ok 2)) + , test "map Err" <| \() -> Expect.equal (Err "error") (Result.map ((+) 1) (Err "error")) + ] + + mapNTests = + describe "mapN Tests" + [ test "map2 Ok" <| \() -> Expect.equal (Ok 3) (Result.map2 (+) (Ok 1) (Ok 2)) + , test "map2 Err" <| \() -> Expect.equal (Err "x") (Result.map2 (+) (Ok 1) (Err "x")) + , test "map3 Ok" <| \() -> Expect.equal (Ok 6) (Result.map3 add3 (Ok 1) (Ok 2) (Ok 3)) + , test "map3 Err" <| \() -> Expect.equal (Err "x") (Result.map3 add3 (Ok 1) (Ok 2) (Err "x")) + , test "map4 Ok" <| \() -> Expect.equal (Ok 10) (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Ok 4)) + , test "map4 Err" <| \() -> Expect.equal (Err "x") (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Err "x")) + , test "map5 Ok" <| \() -> Expect.equal (Ok 15) (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Ok 5)) + , test "map5 Err" <| \() -> Expect.equal (Err "x") (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Err "x")) + ] + + andThenTests = + describe "andThen Tests" + [ test "andThen Ok" <| \() -> Expect.equal (Ok 42) ((String.toInt "42") |> Result.andThen isEven) + , test "andThen first Err" <| + \() -> + Expect.equal + (Err "could not convert string '4.2' to an Int") + (String.toInt "4.2" |> Result.andThen isEven) + , test "andThen second Err" <| + \() -> + Expect.equal + (Err "number is odd") + (String.toInt "41" |> Result.andThen isEven) + ] + in + describe "Result Tests" + [ mapTests + , mapNTests + , andThenTests + ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm new file mode 100644 index 0000000..e98caaa --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm @@ -0,0 +1,52 @@ +module Test.Set exposing (tests) + +import Basics exposing (..) +import Set +import Set exposing (Set) +import List +import Test exposing (..) +import Expect + + +set : Set Int +set = + Set.fromList <| List.range 1 100 + + +setPart1 : Set Int +setPart1 = + Set.fromList <| List.range 1 50 + + +setPart2 : Set Int +setPart2 = + Set.fromList <| List.range 51 100 + + +pred : Int -> Bool +pred x = + x <= 50 + + +tests : Test +tests = + let + queryTests = + describe "query Tests" + [ test "size of set of 100 elements" <| + \() -> Expect.equal 100 (Set.size set) + ] + + filterTests = + describe "filter Tests" + [ test "Simple filter" <| + \() -> Expect.equal setPart1 <| Set.filter pred set + ] + + partitionTests = + describe "partition Tests" + [ test "Simple partition" <| + \() -> Expect.equal ( setPart1, setPart2 ) <| Set.partition pred set + ] + in + describe "Set Tests" [ queryTests, partitionTests, filterTests ] diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm new file mode 100644 index 0000000..f682775 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm @@ -0,0 +1,110 @@ +module Test.String exposing (tests) + +import Basics exposing (..) +import List +import Maybe exposing (..) +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "is empty" <| \() -> Expect.equal True (String.isEmpty "") + , test "is not empty" <| \() -> Expect.equal True (not (String.isEmpty ("the world"))) + , test "length" <| \() -> Expect.equal 11 (String.length "innumerable") + , test "endsWith" <| \() -> Expect.equal True <| String.endsWith "ship" "spaceship" + , test "reverse" <| \() -> Expect.equal "desserts" (String.reverse "stressed") + , test "repeat" <| \() -> Expect.equal "hahaha" (String.repeat 3 "ha") + , test "indexes" <| \() -> Expect.equal [ 0, 2 ] (String.indexes "a" "aha") + , test "empty indexes" <| \() -> Expect.equal [] (String.indexes "" "aha") + ] + + combiningTests = + describe "Combining Strings" + [ test "uncons non-empty" <| \() -> Expect.equal (Just ( 'a', "bc" )) (String.uncons "abc") + , test "uncons empty" <| \() -> Expect.equal Nothing (String.uncons "") + , test "append 1" <| \() -> Expect.equal "butterfly" (String.append "butter" "fly") + , test "append 2" <| \() -> Expect.equal "butter" (String.append "butter" "") + , test "append 3" <| \() -> Expect.equal "butter" (String.append "" "butter") + , test "concat" <| \() -> Expect.equal "nevertheless" (String.concat [ "never", "the", "less" ]) + , test "split commas" <| \() -> Expect.equal [ "cat", "dog", "cow" ] (String.split "," "cat,dog,cow") + , test "split slashes" <| \() -> Expect.equal [ "home", "steve", "Desktop", "" ] (String.split "/" "home/steve/Desktop/") + , test "join spaces" <| \() -> Expect.equal "cat dog cow" (String.join " " [ "cat", "dog", "cow" ]) + , test "join slashes" <| \() -> Expect.equal "home/steve/Desktop" (String.join "/" [ "home", "steve", "Desktop" ]) + , test "slice 1" <| \() -> Expect.equal "c" (String.slice 2 3 "abcd") + , test "slice 2" <| \() -> Expect.equal "abc" (String.slice 0 3 "abcd") + , test "slice 3" <| \() -> Expect.equal "abc" (String.slice 0 -1 "abcd") + , test "slice 4" <| \() -> Expect.equal "cd" (String.slice -2 4 "abcd") + ] + + intTests = + describe "String.toInt" + [ goodInt "1234" 1234 + , goodInt "+1234" 1234 + , goodInt "-1234" -1234 + , badInt "1.34" + , badInt "1e31" + , badInt "123a" + , goodInt "0123" 123 + , goodInt "0x001A" 26 + , goodInt "0x001a" 26 + , goodInt "0xBEEF" 48879 + , badInt "0x12.0" + , badInt "0x12an" + ] + + floatTests = + describe "String.toFloat" + [ goodFloat "123" 123 + , goodFloat "3.14" 3.14 + , goodFloat "+3.14" 3.14 + , goodFloat "-3.14" -3.14 + , goodFloat "0.12" 0.12 + , goodFloat ".12" 0.12 + , goodFloat "1e-42" 1e-42 + , goodFloat "6.022e23" 6.022e23 + , goodFloat "6.022E23" 6.022e23 + , goodFloat "6.022e+23" 6.022e23 + , badFloat "6.022e" + , badFloat "6.022n" + , badFloat "6.022.31" + ] + in + describe "String" [ simpleTests, combiningTests, intTests, floatTests ] + + + +-- NUMBER HELPERS + + +goodInt : String -> Int -> Test +goodInt str int = + test str <| \_ -> + Expect.equal (Ok int) (String.toInt str) + + +badInt : String -> Test +badInt str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to an Int")) + (String.toInt str) + + +goodFloat : String -> Float -> Test +goodFloat str float = + test str <| \_ -> + Expect.equal (Ok float) (String.toFloat str) + + +badFloat : String -> Test +badFloat str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to a Float")) + (String.toFloat str) diff --git a/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json new file mode 100644 index 0000000..e27cfa4 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "1.1.1", + "summary": "Tests for Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [ ], + "native-modules": true, + "dependencies": { + "elm-community/elm-test": "3.1.0 <= v < 4.0.0", + "rtfeldman/node-test-runner": "3.0.0 <= v < 4.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore b/part1/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore new file mode 100644 index 0000000..e185314 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore @@ -0,0 +1 @@ +elm-stuff \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE b/part1/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json b/part1/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json new file mode 100644 index 0000000..952aed5 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "summary": "Fast HTML, rendered with virtual DOM diffing", + "repository": "https://github.com/elm-lang/html.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Html", + "Html.Attributes", + "Html.Events", + "Html.Keyed", + "Html.Lazy" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/virtual-dom": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm new file mode 100644 index 0000000..b872a3b --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm @@ -0,0 +1,923 @@ +module Html exposing + ( Html, Attribute + , text, node, map + , beginnerProgram, program, programWithFlags + , h1, h2, h3, h4, h5, h6 + , div, p, hr, pre, blockquote + , span, a, code, em, strong, i, b, u, sub, sup, br + , ol, ul, li, dl, dt, dd + , img, iframe, canvas, math + , form, input, textarea, button, select, option + , section, nav, article, aside, header, footer, address, main_, body + , figure, figcaption + , table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + , fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + , audio, video, source, track + , embed, object, param + , ins, del + , small, cite, dfn, abbr, time, var, samp, kbd, s, q + , mark, ruby, rt, rp, bdi, bdo, wbr + , details, summary, menuitem, menu + ) + +{-| This file is organized roughly in order of popularity. The tags which you'd +expect to use frequently will be closer to the top. + +# Primitives +@docs Html, Attribute, text, node, map + +# Programs +@docs beginnerProgram, program, programWithFlags + +# Tags + +## Headers +@docs h1, h2, h3, h4, h5, h6 + +## Grouping Content +@docs div, p, hr, pre, blockquote + +## Text +@docs span, a, code, em, strong, i, b, u, sub, sup, br + +## Lists +@docs ol, ul, li, dl, dt, dd + +## Emdedded Content +@docs img, iframe, canvas, math + +## Inputs +@docs form, input, textarea, button, select, option + +## Sections +@docs section, nav, article, aside, header, footer, address, main_, body + +## Figures +@docs figure, figcaption + +## Tables +@docs table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + + +## Less Common Elements + +### Less Common Inputs +@docs fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + +### Audio and Video +@docs audio, video, source, track + +### Embedded Objects +@docs embed, object, param + +### Text Edits +@docs ins, del + +### Semantic Text +@docs small, cite, dfn, abbr, time, var, samp, kbd, s, q + +### Less Common Text Tags +@docs mark, ruby, rt, rp, bdi, bdo, wbr + +## Interactive Elements +@docs details, summary, menuitem, menu + +-} + +import VirtualDom + + + +-- CORE TYPES + + +{-| The core building block used to build up HTML. Here we create an `Html` +value with no attributes and one child: + + hello : Html msg + hello = + div [] [ text "Hello!" ] +-} +type alias Html msg = VirtualDom.Node msg + + +{-| Set attributes on your `Html`. Learn more in the +[`Html.Attributes`](Html-Attributes) module. +-} +type alias Attribute msg = VirtualDom.Property msg + + + +-- PRIMITIVES + + +{-| General way to create HTML nodes. It is used to define all of the helper +functions in this library. + + div : List (Attribute msg) -> List (Html msg) -> Html msg + div attributes children = + node "div" attributes children + +You can use this to create custom nodes if you need to create something that +is not covered by the helper functions in this library. +-} +node : String -> List (Attribute msg) -> List (Html msg) -> Html msg +node = + VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Html msg +text = + VirtualDom.text + + + +-- NESTING VIEWS + + +{-| Transform the messages produced by some `Html`. In the following example, +we have `viewButton` that produces `()` messages, and we transform those values +into `Msg` values in `view`. + + type Msg = Left | Right + + view : model -> Html Msg + view model = + div [] + [ map (\_ -> Left) (viewButton "Left") + , map (\_ -> Right) (viewButton "Right") + ] + + viewButton : String -> Html () + viewButton name = + button [ onClick () ] [ text name ] + +This should not come in handy too often. Definitely read [this][reuse] before +deciding if this is what you want. + +[reuse]: https://guide.elm-lang.org/reuse/ +-} +map : (a -> msg) -> Html a -> Html msg +map = + VirtualDom.map + + + +-- CREATING PROGRAMS + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +The additional context is very worthwhile! (Honestly, it is best to just read +that guide from front to back instead of muddling around and reading it +piecemeal.) + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +beginnerProgram + : { model : model + , view : model -> Html msg + , update : msg -> model -> model + } + -> Program Never model msg +beginnerProgram {model, view, update} = + program + { init = model ! [] + , update = \msg model -> update msg model ! [] + , view = view + , subscriptions = \_ -> Sub.none + } + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +Commands and subscriptions make way more sense when you work up to them +gradually and see them in context with examples. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program Never model msg +program = + VirtualDom.program + + +{-| Create a [`Program`][program] that describes how your whole app works. + +It works just like `program` but you can provide “flags” from +JavaScript to configure your application. Read more about that [here][]. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[here]: https://guide.elm-lang.org/interop/javascript.html +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program flags model msg +programWithFlags = + VirtualDom.programWithFlags + + + +-- SECTIONS + + +{-| Represents the content of an HTML document. There is only one `body` +element in a document. +-} +body : List (Attribute msg) -> List (Html msg) -> Html msg +body = + node "body" + + +{-| Defines a section in a document. +-} +section : List (Attribute msg) -> List (Html msg) -> Html msg +section = + node "section" + + +{-| Defines a section that contains only navigation links. +-} +nav : List (Attribute msg) -> List (Html msg) -> Html msg +nav = + node "nav" + + +{-| Defines self-contained content that could exist independently of the rest +of the content. +-} +article : List (Attribute msg) -> List (Html msg) -> Html msg +article = + node "article" + + +{-| Defines some content loosely related to the page content. If it is removed, +the remaining content still makes sense. +-} +aside : List (Attribute msg) -> List (Html msg) -> Html msg +aside = + node "aside" + + +{-|-} +h1 : List (Attribute msg) -> List (Html msg) -> Html msg +h1 = + node "h1" + + +{-|-} +h2 : List (Attribute msg) -> List (Html msg) -> Html msg +h2 = + node "h2" + + +{-|-} +h3 : List (Attribute msg) -> List (Html msg) -> Html msg +h3 = + node "h3" + + +{-|-} +h4 : List (Attribute msg) -> List (Html msg) -> Html msg +h4 = + node "h4" + + +{-|-} +h5 : List (Attribute msg) -> List (Html msg) -> Html msg +h5 = + node "h5" + + +{-|-} +h6 : List (Attribute msg) -> List (Html msg) -> Html msg +h6 = + node "h6" + + +{-| Defines the header of a page or section. It often contains a logo, the +title of the web site, and a navigational table of content. +-} +header : List (Attribute msg) -> List (Html msg) -> Html msg +header = + node "header" + + +{-| Defines the footer for a page or section. It often contains a copyright +notice, some links to legal information, or addresses to give feedback. +-} +footer : List (Attribute msg) -> List (Html msg) -> Html msg +footer = + node "footer" + + +{-| Defines a section containing contact information. -} +address : List (Attribute msg) -> List (Html msg) -> Html msg +address = + node "address" + + +{-| Defines the main or important content in the document. There is only one +`main` element in the document. +-} +main_ : List (Attribute msg) -> List (Html msg) -> Html msg +main_ = + node "main" + + +-- GROUPING CONTENT + +{-| Defines a portion that should be displayed as a paragraph. -} +p : List (Attribute msg) -> List (Html msg) -> Html msg +p = + node "p" + + +{-| Represents a thematic break between paragraphs of a section or article or +any longer content. +-} +hr : List (Attribute msg) -> List (Html msg) -> Html msg +hr = + node "hr" + + +{-| Indicates that its content is preformatted and that this format must be +preserved. +-} +pre : List (Attribute msg) -> List (Html msg) -> Html msg +pre = + node "pre" + + +{-| Represents a content that is quoted from another source. -} +blockquote : List (Attribute msg) -> List (Html msg) -> Html msg +blockquote = + node "blockquote" + + +{-| Defines an ordered list of items. -} +ol : List (Attribute msg) -> List (Html msg) -> Html msg +ol = + node "ol" + + +{-| Defines an unordered list of items. -} +ul : List (Attribute msg) -> List (Html msg) -> Html msg +ul = + node "ul" + + +{-| Defines a item of an enumeration list. -} +li : List (Attribute msg) -> List (Html msg) -> Html msg +li = + node "li" + + +{-| Defines a definition list, that is, a list of terms and their associated +definitions. +-} +dl : List (Attribute msg) -> List (Html msg) -> Html msg +dl = + node "dl" + + +{-| Represents a term defined by the next `dd`. -} +dt : List (Attribute msg) -> List (Html msg) -> Html msg +dt = + node "dt" + + +{-| Represents the definition of the terms immediately listed before it. -} +dd : List (Attribute msg) -> List (Html msg) -> Html msg +dd = + node "dd" + + +{-| Represents a figure illustrated as part of the document. -} +figure : List (Attribute msg) -> List (Html msg) -> Html msg +figure = + node "figure" + + +{-| Represents the legend of a figure. -} +figcaption : List (Attribute msg) -> List (Html msg) -> Html msg +figcaption = + node "figcaption" + + +{-| Represents a generic container with no special meaning. -} +div : List (Attribute msg) -> List (Html msg) -> Html msg +div = + node "div" + + +-- TEXT LEVEL SEMANTIC + +{-| Represents a hyperlink, linking to another resource. -} +a : List (Attribute msg) -> List (Html msg) -> Html msg +a = + node "a" + + +{-| Represents emphasized text, like a stress accent. -} +em : List (Attribute msg) -> List (Html msg) -> Html msg +em = + node "em" + + +{-| Represents especially important text. -} +strong : List (Attribute msg) -> List (Html msg) -> Html msg +strong = + node "strong" + + +{-| Represents a side comment, that is, text like a disclaimer or a +copyright, which is not essential to the comprehension of the document. +-} +small : List (Attribute msg) -> List (Html msg) -> Html msg +small = + node "small" + + +{-| Represents content that is no longer accurate or relevant. -} +s : List (Attribute msg) -> List (Html msg) -> Html msg +s = + node "s" + + +{-| Represents the title of a work. -} +cite : List (Attribute msg) -> List (Html msg) -> Html msg +cite = + node "cite" + + +{-| Represents an inline quotation. -} +q : List (Attribute msg) -> List (Html msg) -> Html msg +q = + node "q" + + +{-| Represents a term whose definition is contained in its nearest ancestor +content. +-} +dfn : List (Attribute msg) -> List (Html msg) -> Html msg +dfn = + node "dfn" + + +{-| Represents an abbreviation or an acronym; the expansion of the +abbreviation can be represented in the title attribute. +-} +abbr : List (Attribute msg) -> List (Html msg) -> Html msg +abbr = + node "abbr" + + +{-| Represents a date and time value; the machine-readable equivalent can be +represented in the datetime attribute. +-} +time : List (Attribute msg) -> List (Html msg) -> Html msg +time = + node "time" + + +{-| Represents computer code. -} +code : List (Attribute msg) -> List (Html msg) -> Html msg +code = + node "code" + + +{-| Represents a variable. Specific cases where it should be used include an +actual mathematical expression or programming context, an identifier +representing a constant, a symbol identifying a physical quantity, a function +parameter, or a mere placeholder in prose. +-} +var : List (Attribute msg) -> List (Html msg) -> Html msg +var = + node "var" + + +{-| Represents the output of a program or a computer. -} +samp : List (Attribute msg) -> List (Html msg) -> Html msg +samp = + node "samp" + + +{-| Represents user input, often from the keyboard, but not necessarily; it +may represent other input, like transcribed voice commands. +-} +kbd : List (Attribute msg) -> List (Html msg) -> Html msg +kbd = + node "kbd" + + +{-| Represent a subscript. -} +sub : List (Attribute msg) -> List (Html msg) -> Html msg +sub = + node "sub" + + +{-| Represent a superscript. -} +sup : List (Attribute msg) -> List (Html msg) -> Html msg +sup = + node "sup" + + +{-| Represents some text in an alternate voice or mood, or at least of +different quality, such as a taxonomic designation, a technical term, an +idiomatic phrase, a thought, or a ship name. +-} +i : List (Attribute msg) -> List (Html msg) -> Html msg +i = + node "i" + + +{-| Represents a text which to which attention is drawn for utilitarian +purposes. It doesn't convey extra importance and doesn't imply an alternate +voice. +-} +b : List (Attribute msg) -> List (Html msg) -> Html msg +b = + node "b" + + +{-| Represents a non-textual annoatation for which the conventional +presentation is underlining, such labeling the text as being misspelt or +labeling a proper name in Chinese text. +-} +u : List (Attribute msg) -> List (Html msg) -> Html msg +u = + node "u" + + +{-| Represents text highlighted for reference purposes, that is for its +relevance in another context. +-} +mark : List (Attribute msg) -> List (Html msg) -> Html msg +mark = + node "mark" + + +{-| Represents content to be marked with ruby annotations, short runs of text +presented alongside the text. This is often used in conjunction with East Asian +language where the annotations act as a guide for pronunciation, like the +Japanese furigana. +-} +ruby : List (Attribute msg) -> List (Html msg) -> Html msg +ruby = + node "ruby" + + +{-| Represents the text of a ruby annotation. -} +rt : List (Attribute msg) -> List (Html msg) -> Html msg +rt = + node "rt" + + +{-| Represents parenthesis around a ruby annotation, used to display the +annotation in an alternate way by browsers not supporting the standard display +for annotations. +-} +rp : List (Attribute msg) -> List (Html msg) -> Html msg +rp = + node "rp" + + +{-| Represents text that must be isolated from its surrounding for +bidirectional text formatting. It allows embedding a span of text with a +different, or unknown, directionality. +-} +bdi : List (Attribute msg) -> List (Html msg) -> Html msg +bdi = + node "bdi" + + +{-| Represents the directionality of its children, in order to explicitly +override the Unicode bidirectional algorithm. +-} +bdo : List (Attribute msg) -> List (Html msg) -> Html msg +bdo = + node "bdo" + + +{-| Represents text with no specific meaning. This has to be used when no other +text-semantic element conveys an adequate meaning, which, in this case, is +often brought by global attributes like `class`, `lang`, or `dir`. +-} +span : List (Attribute msg) -> List (Html msg) -> Html msg +span = + node "span" + + +{-| Represents a line break. -} +br : List (Attribute msg) -> List (Html msg) -> Html msg +br = + node "br" + + +{-| Represents a line break opportunity, that is a suggested point for +wrapping text in order to improve readability of text split on several lines. +-} +wbr : List (Attribute msg) -> List (Html msg) -> Html msg +wbr = + node "wbr" + + +-- EDITS + +{-| Defines an addition to the document. -} +ins : List (Attribute msg) -> List (Html msg) -> Html msg +ins = + node "ins" + + +{-| Defines a removal from the document. -} +del : List (Attribute msg) -> List (Html msg) -> Html msg +del = + node "del" + + +-- EMBEDDED CONTENT + +{-| Represents an image. -} +img : List (Attribute msg) -> List (Html msg) -> Html msg +img = + node "img" + + +{-| Embedded an HTML document. -} +iframe : List (Attribute msg) -> List (Html msg) -> Html msg +iframe = + node "iframe" + + +{-| Represents a integration point for an external, often non-HTML, +application or interactive content. +-} +embed : List (Attribute msg) -> List (Html msg) -> Html msg +embed = + node "embed" + + +{-| Represents an external resource, which is treated as an image, an HTML +sub-document, or an external resource to be processed by a plug-in. +-} +object : List (Attribute msg) -> List (Html msg) -> Html msg +object = + node "object" + + +{-| Defines parameters for use by plug-ins invoked by `object` elements. -} +param : List (Attribute msg) -> List (Html msg) -> Html msg +param = + node "param" + + +{-| Represents a video, the associated audio and captions, and controls. -} +video : List (Attribute msg) -> List (Html msg) -> Html msg +video = + node "video" + + +{-| Represents a sound or audio stream. -} +audio : List (Attribute msg) -> List (Html msg) -> Html msg +audio = + node "audio" + + +{-| Allows authors to specify alternative media resources for media elements +like `video` or `audio`. +-} +source : List (Attribute msg) -> List (Html msg) -> Html msg +source = + node "source" + + +{-| Allows authors to specify timed text track for media elements like `video` +or `audio`. +-} +track : List (Attribute msg) -> List (Html msg) -> Html msg +track = + node "track" + + +{-| Represents a bitmap area for graphics rendering. -} +canvas : List (Attribute msg) -> List (Html msg) -> Html msg +canvas = + node "canvas" + + +{-| Defines a mathematical formula. -} +math : List (Attribute msg) -> List (Html msg) -> Html msg +math = + node "math" + + +-- TABULAR DATA + +{-| Represents data with more than one dimension. -} +table : List (Attribute msg) -> List (Html msg) -> Html msg +table = + node "table" + + +{-| Represents the title of a table. -} +caption : List (Attribute msg) -> List (Html msg) -> Html msg +caption = + node "caption" + + +{-| Represents a set of one or more columns of a table. -} +colgroup : List (Attribute msg) -> List (Html msg) -> Html msg +colgroup = + node "colgroup" + + +{-| Represents a column of a table. -} +col : List (Attribute msg) -> List (Html msg) -> Html msg +col = + node "col" + + +{-| Represents the block of rows that describes the concrete data of a table. +-} +tbody : List (Attribute msg) -> List (Html msg) -> Html msg +tbody = + node "tbody" + + +{-| Represents the block of rows that describes the column labels of a table. +-} +thead : List (Attribute msg) -> List (Html msg) -> Html msg +thead = + node "thead" + + +{-| Represents the block of rows that describes the column summaries of a table. +-} +tfoot : List (Attribute msg) -> List (Html msg) -> Html msg +tfoot = + node "tfoot" + + +{-| Represents a row of cells in a table. -} +tr : List (Attribute msg) -> List (Html msg) -> Html msg +tr = + node "tr" + + +{-| Represents a data cell in a table. -} +td : List (Attribute msg) -> List (Html msg) -> Html msg +td = + node "td" + + +{-| Represents a header cell in a table. -} +th : List (Attribute msg) -> List (Html msg) -> Html msg +th = + node "th" + + +-- FORMS + +{-| Represents a form, consisting of controls, that can be submitted to a +server for processing. +-} +form : List (Attribute msg) -> List (Html msg) -> Html msg +form = + node "form" + + +{-| Represents a set of controls. -} +fieldset : List (Attribute msg) -> List (Html msg) -> Html msg +fieldset = + node "fieldset" + + +{-| Represents the caption for a `fieldset`. -} +legend : List (Attribute msg) -> List (Html msg) -> Html msg +legend = + node "legend" + + +{-| Represents the caption of a form control. -} +label : List (Attribute msg) -> List (Html msg) -> Html msg +label = + node "label" + + +{-| Represents a typed data field allowing the user to edit the data. -} +input : List (Attribute msg) -> List (Html msg) -> Html msg +input = + node "input" + + +{-| Represents a button. -} +button : List (Attribute msg) -> List (Html msg) -> Html msg +button = + node "button" + + +{-| Represents a control allowing selection among a set of options. -} +select : List (Attribute msg) -> List (Html msg) -> Html msg +select = + node "select" + + +{-| Represents a set of predefined options for other controls. -} +datalist : List (Attribute msg) -> List (Html msg) -> Html msg +datalist = + node "datalist" + + +{-| Represents a set of options, logically grouped. -} +optgroup : List (Attribute msg) -> List (Html msg) -> Html msg +optgroup = + node "optgroup" + + +{-| Represents an option in a `select` element or a suggestion of a `datalist` +element. +-} +option : List (Attribute msg) -> List (Html msg) -> Html msg +option = + node "option" + + +{-| Represents a multiline text edit control. -} +textarea : List (Attribute msg) -> List (Html msg) -> Html msg +textarea = + node "textarea" + + +{-| Represents a key-pair generator control. -} +keygen : List (Attribute msg) -> List (Html msg) -> Html msg +keygen = + node "keygen" + + +{-| Represents the result of a calculation. -} +output : List (Attribute msg) -> List (Html msg) -> Html msg +output = + node "output" + + +{-| Represents the completion progress of a task. -} +progress : List (Attribute msg) -> List (Html msg) -> Html msg +progress = + node "progress" + + +{-| Represents a scalar measurement (or a fractional value), within a known +range. +-} +meter : List (Attribute msg) -> List (Html msg) -> Html msg +meter = + node "meter" + + +-- INTERACTIVE ELEMENTS + +{-| Represents a widget from which the user can obtain additional information +or controls. +-} +details : List (Attribute msg) -> List (Html msg) -> Html msg +details = + node "details" + + +{-| Represents a summary, caption, or legend for a given `details`. -} +summary : List (Attribute msg) -> List (Html msg) -> Html msg +summary = + node "summary" + + +{-| Represents a command that the user can invoke. -} +menuitem : List (Attribute msg) -> List (Html msg) -> Html msg +menuitem = + node "menuitem" + + +{-| Represents a list of commands. -} +menu : List (Attribute msg) -> List (Html msg) -> Html msg +menu = + node "menu" + diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm new file mode 100644 index 0000000..4cdba44 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm @@ -0,0 +1,1009 @@ +module Html.Attributes exposing + ( style, property, attribute, map + , class, classList, id, title, hidden + , type_, value, defaultValue, checked, placeholder, selected + , accept, acceptCharset, action, autocomplete, autofocus + , disabled, enctype, formaction, list, maxlength, minlength, method, multiple + , name, novalidate, pattern, readonly, required, size, for, form + , max, min, step + , cols, rows, wrap + , href, target, download, downloadAs, hreflang, media, ping, rel + , ismap, usemap, shape, coords + , src, height, width, alt + , autoplay, controls, loop, preload, poster, default, kind, srclang + , sandbox, seamless, srcdoc + , reversed, start + , align, colspan, rowspan, headers, scope + , async, charset, content, defer, httpEquiv, language, scoped + , accesskey, contenteditable, contextmenu, dir, draggable, dropzone + , itemprop, lang, spellcheck, tabindex + , challenge, keytype + , cite, datetime, pubdate, manifest + ) + +{-| Helper functions for HTML attributes. They are organized roughly by +category. Each attribute is labeled with the HTML tags it can be used with, so +just search the page for `video` if you want video stuff. + +If you cannot find what you are looking for, go to the [Custom +Attributes](#custom-attributes) section to learn how to create new helpers. + +# Primitives +@docs style, property, attribute, map + +# Super Common Attributes +@docs class, classList, id, title, hidden + +# Inputs +@docs type_, value, defaultValue, checked, placeholder, selected + +## Input Helpers +@docs accept, acceptCharset, action, autocomplete, autofocus, + disabled, enctype, formaction, list, maxlength, minlength, method, multiple, + name, novalidate, pattern, readonly, required, size, for, form + +## Input Ranges +@docs max, min, step + +## Input Text Areas +@docs cols, rows, wrap + + +# Links and Areas +@docs href, target, download, downloadAs, hreflang, media, ping, rel + +## Maps +@docs ismap, usemap, shape, coords + + +# Embedded Content +@docs src, height, width, alt + +## Audio and Video +@docs autoplay, controls, loop, preload, poster, default, kind, srclang + +## iframes +@docs sandbox, seamless, srcdoc + +# Ordered Lists +@docs reversed, start + +# Tables +@docs align, colspan, rowspan, headers, scope + +# Header Stuff +@docs async, charset, content, defer, httpEquiv, language, scoped + +# Less Common Global Attributes +Attributes that can be attached to any HTML tag but are less commonly used. +@docs accesskey, contenteditable, contextmenu, dir, draggable, dropzone, + itemprop, lang, spellcheck, tabindex + +# Key Generation +@docs challenge, keytype + +# Miscellaneous +@docs cite, datetime, pubdate, manifest + +-} + +import Html exposing (Attribute) +import Json.Encode as Json +import VirtualDom + + +-- This library does not include low, high, or optimum because the idea of a +-- `meter` is just too crazy. + + + +-- PRIMITIVES + + +{-| Specify a list of styles. + + myStyle : Attribute msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Html msg + greeting = + div [ myStyle ] [ text "Hello!" ] + +There is no `Html.Styles` module because best practices for working with HTML +suggest that this should primarily be specified in CSS files. So the general +recommendation is to use this function lightly. +-} +style : List (String, String) -> Attribute msg +style = + VirtualDom.style + + +{-| This function makes it easier to build a space-separated class attribute. +Each class can easily be added and removed depending on the boolean value it +is paired with. For example, maybe we want a way to view notices: + + viewNotice : Notice -> Html msg + viewNotice notice = + div + [ classList + [ ("notice", True) + , ("notice-important", notice.isImportant) + , ("notice-seen", notice.isSeen) + ] + ] + [ text notice.content ] +-} +classList : List (String, Bool) -> Attribute msg +classList list = + list + |> List.filter Tuple.second + |> List.map Tuple.first + |> String.join " " + |> class + + + +-- CUSTOM ATTRIBUTES + + +{-| Create *properties*, like saying `domNode.className = 'greeting'` in +JavaScript. + + import Json.Encode as Encode + + class : String -> Attribute msg + class name = + property "className" (Encode.string name) + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +property : String -> Json.Value -> Attribute msg +property = + VirtualDom.property + + +stringProperty : String -> String -> Attribute msg +stringProperty name string = + property name (Json.string string) + + +boolProperty : String -> Bool -> Attribute msg +boolProperty name bool = + property name (Json.bool bool) + + +{-| Create *attributes*, like saying `domNode.setAttribute('class', 'greeting')` +in JavaScript. + + class : String -> Attribute msg + class name = + attribute "class" name + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +attribute : String -> String -> Attribute msg +attribute = + VirtualDom.attribute + + +{-| Transform the messages produced by an `Attribute`. +-} +map : (a -> msg) -> Attribute a -> Attribute msg +map = + VirtualDom.mapProperty + + + +-- GLOBAL ATTRIBUTES + + +{-| Often used with CSS to style elements with common properties. -} +class : String -> Attribute msg +class name = + stringProperty "className" name + + +{-| Indicates the relevance of an element. -} +hidden : Bool -> Attribute msg +hidden bool = + boolProperty "hidden" bool + + +{-| Often used with CSS to style a specific element. The value of this +attribute must be unique. +-} +id : String -> Attribute msg +id name = + stringProperty "id" name + + +{-| Text to be displayed in a tooltip when hovering over the element. -} +title : String -> Attribute msg +title name = + stringProperty "title" name + + + +-- LESS COMMON GLOBAL ATTRIBUTES + + +{-| Defines a keyboard shortcut to activate or add focus to the element. -} +accesskey : Char -> Attribute msg +accesskey char = + stringProperty "accessKey" (String.fromChar char) + + +{-| Indicates whether the element's content is editable. -} +contenteditable : Bool -> Attribute msg +contenteditable bool = + boolProperty "contentEditable" bool + + +{-| Defines the ID of a `menu` element which will serve as the element's +context menu. +-} +contextmenu : String -> Attribute msg +contextmenu value = + attribute "contextmenu" value + + +{-| Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl +(Right-To-Left). +-} +dir : String -> Attribute msg +dir value = + stringProperty "dir" value + + +{-| Defines whether the element can be dragged. -} +draggable : String -> Attribute msg +draggable value = + attribute "draggable" value + + +{-| Indicates that the element accept the dropping of content on it. -} +dropzone : String -> Attribute msg +dropzone value = + stringProperty "dropzone" value + + +{-|-} +itemprop : String -> Attribute msg +itemprop value = + attribute "itemprop" value + + +{-| Defines the language used in the element. -} +lang : String -> Attribute msg +lang value = + stringProperty "lang" value + + +{-| Indicates whether spell checking is allowed for the element. -} +spellcheck : Bool -> Attribute msg +spellcheck bool = + boolProperty "spellcheck" bool + + +{-| Overrides the browser's default tab order and follows the one specified +instead. +-} +tabindex : Int -> Attribute msg +tabindex n = + attribute "tabIndex" (toString n) + + + +-- HEADER STUFF + + +{-| Indicates that the `script` should be executed asynchronously. -} +async : Bool -> Attribute msg +async bool = + boolProperty "async" bool + + +{-| Declares the character encoding of the page or script. Common values include: + + * UTF-8 - Character encoding for Unicode + * ISO-8859-1 - Character encoding for the Latin alphabet + +For `meta` and `script`. +-} +charset : String -> Attribute msg +charset value = + attribute "charset" value + + +{-| A value associated with http-equiv or name depending on the context. For +`meta`. +-} +content : String -> Attribute msg +content value = + stringProperty "content" value + + +{-| Indicates that a `script` should be executed after the page has been +parsed. +-} +defer : Bool -> Attribute msg +defer bool = + boolProperty "defer" bool + + +{-| This attribute is an indicator that is paired with the `content` attribute, +indicating what that content means. `httpEquiv` can take on three different +values: content-type, default-style, or refresh. For `meta`. +-} +httpEquiv : String -> Attribute msg +httpEquiv value = + stringProperty "httpEquiv" value + + +{-| Defines the script language used in a `script`. -} +language : String -> Attribute msg +language value = + stringProperty "language" value + + +{-| Indicates that a `style` should only apply to its parent and all of the +parents children. +-} +scoped : Bool -> Attribute msg +scoped bool = + boolProperty "scoped" bool + + + +-- EMBEDDED CONTENT + + +{-| The URL of the embeddable content. For `audio`, `embed`, `iframe`, `img`, +`input`, `script`, `source`, `track`, and `video`. +-} +src : String -> Attribute msg +src value = + stringProperty "src" value + + +{-| Declare the height of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +height : Int -> Attribute msg +height value = + attribute "height" (toString value) + + +{-| Declare the width of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +width : Int -> Attribute msg +width value = + attribute "width" (toString value) + + +{-| Alternative text in case an image can't be displayed. Works with `img`, +`area`, and `input`. +-} +alt : String -> Attribute msg +alt value = + stringProperty "alt" value + + + +-- AUDIO and VIDEO + + +{-| The `audio` or `video` should play as soon as possible. -} +autoplay : Bool -> Attribute msg +autoplay bool = + boolProperty "autoplay" bool + + +{-| Indicates whether the browser should show playback controls for the `audio` +or `video`. +-} +controls : Bool -> Attribute msg +controls bool = + boolProperty "controls" bool + + +{-| Indicates whether the `audio` or `video` should start playing from the +start when it's finished. +-} +loop : Bool -> Attribute msg +loop bool = + boolProperty "loop" bool + + +{-| Control how much of an `audio` or `video` resource should be preloaded. -} +preload : String -> Attribute msg +preload value = + stringProperty "preload" value + + +{-| A URL indicating a poster frame to show until the user plays or seeks the +`video`. +-} +poster : String -> Attribute msg +poster value = + stringProperty "poster" value + + +{-| Indicates that the `track` should be enabled unless the user's preferences +indicate something different. +-} +default : Bool -> Attribute msg +default bool = + boolProperty "default" bool + + +{-| Specifies the kind of text `track`. -} +kind : String -> Attribute msg +kind value = + stringProperty "kind" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| Specifies a user-readable title of the text `track`. -} +label : String -> Attribute msg +label value = + stringProperty "label" value +--} + +{-| A two letter language code indicating the language of the `track` text data. +-} +srclang : String -> Attribute msg +srclang value = + stringProperty "srclang" value + + + +-- IFRAMES + + +{-| A space separated list of security restrictions you'd like to lift for an +`iframe`. +-} +sandbox : String -> Attribute msg +sandbox value = + stringProperty "sandbox" value + + +{-| Make an `iframe` look like part of the containing document. -} +seamless : Bool -> Attribute msg +seamless bool = + boolProperty "seamless" bool + + +{-| An HTML document that will be displayed as the body of an `iframe`. It will +override the content of the `src` attribute if it has been specified. +-} +srcdoc : String -> Attribute msg +srcdoc value = + stringProperty "srcdoc" value + + + +-- INPUT + + +{-| Defines the type of a `button`, `input`, `embed`, `object`, `script`, +`source`, `style`, or `menu`. +-} +type_ : String -> Attribute msg +type_ value = + stringProperty "type" value + + +{-| Defines a default value which will be displayed in a `button`, `option`, +`input`, `li`, `meter`, `progress`, or `param`. +-} +value : String -> Attribute msg +value value = + stringProperty "value" value + + +{-| Defines an initial value which will be displayed in an `input` when that +`input` is added to the DOM. Unlike `value`, altering `defaultValue` after the +`input` element has been added to the DOM has no effect. +-} +defaultValue : String -> Attribute msg +defaultValue value = + stringProperty "defaultValue" value + + +{-| Indicates whether an `input` of type checkbox is checked. -} +checked : Bool -> Attribute msg +checked bool = + boolProperty "checked" bool + + +{-| Provides a hint to the user of what can be entered into an `input` or +`textarea`. +-} +placeholder : String -> Attribute msg +placeholder value = + stringProperty "placeholder" value + + +{-| Defines which `option` will be selected on page load. -} +selected : Bool -> Attribute msg +selected bool = + boolProperty "selected" bool + + + +-- INPUT HELPERS + + +{-| List of types the server accepts, typically a file type. +For `form` and `input`. +-} +accept : String -> Attribute msg +accept value = + stringProperty "accept" value + + +{-| List of supported charsets in a `form`. +-} +acceptCharset : String -> Attribute msg +acceptCharset value = + stringProperty "acceptCharset" value + + +{-| The URI of a program that processes the information submitted via a `form`. +-} +action : String -> Attribute msg +action value = + stringProperty "action" value + + +{-| Indicates whether a `form` or an `input` can have their values automatically +completed by the browser. +-} +autocomplete : Bool -> Attribute msg +autocomplete bool = + stringProperty "autocomplete" (if bool then "on" else "off") + + +{-| The element should be automatically focused after the page loaded. +For `button`, `input`, `keygen`, `select`, and `textarea`. +-} +autofocus : Bool -> Attribute msg +autofocus bool = + boolProperty "autofocus" bool + + +{-| Indicates whether the user can interact with a `button`, `fieldset`, +`input`, `keygen`, `optgroup`, `option`, `select` or `textarea`. +-} +disabled : Bool -> Attribute msg +disabled bool = + boolProperty "disabled" bool + + +{-| How `form` data should be encoded when submitted with the POST method. +Options include: application/x-www-form-urlencoded, multipart/form-data, and +text/plain. +-} +enctype : String -> Attribute msg +enctype value = + stringProperty "enctype" value + + +{-| Indicates the action of an `input` or `button`. This overrides the action +defined in the surrounding `form`. +-} +formaction : String -> Attribute msg +formaction value = + attribute "formAction" value + + +{-| Associates an `input` with a `datalist` tag. The datalist gives some +pre-defined options to suggest to the user as they interact with an input. +The value of the list attribute must match the id of a `datalist` node. +For `input`. +-} +list : String -> Attribute msg +list value = + attribute "list" value + + +{-| Defines the minimum number of characters allowed in an `input` or +`textarea`. +-} +minlength : Int -> Attribute msg +minlength n = + attribute "minLength" (toString n) + + +{-| Defines the maximum number of characters allowed in an `input` or +`textarea`. +-} +maxlength : Int -> Attribute msg +maxlength n = + attribute "maxlength" (toString n) + + +{-| Defines which HTTP method to use when submitting a `form`. Can be GET +(default) or POST. +-} +method : String -> Attribute msg +method value = + stringProperty "method" value + + +{-| Indicates whether multiple values can be entered in an `input` of type +email or file. Can also indicate that you can `select` many options. +-} +multiple : Bool -> Attribute msg +multiple bool = + boolProperty "multiple" bool + + +{-| Name of the element. For example used by the server to identify the fields +in form submits. For `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, +`object`, `output`, `select`, `textarea`, `map`, `meta`, and `param`. +-} +name : String -> Attribute msg +name value = + stringProperty "name" value + + +{-| This attribute indicates that a `form` shouldn't be validated when +submitted. +-} +novalidate : Bool -> Attribute msg +novalidate bool = + boolProperty "noValidate" bool + + +{-| Defines a regular expression which an `input`'s value will be validated +against. +-} +pattern : String -> Attribute msg +pattern value = + stringProperty "pattern" value + + +{-| Indicates whether an `input` or `textarea` can be edited. -} +readonly : Bool -> Attribute msg +readonly bool = + boolProperty "readOnly" bool + + +{-| Indicates whether this element is required to fill out or not. +For `input`, `select`, and `textarea`. +-} +required : Bool -> Attribute msg +required bool = + boolProperty "required" bool + + +{-| For `input` specifies the width of an input in characters. + +For `select` specifies the number of visible options in a drop-down list. +-} +size : Int -> Attribute msg +size n = + attribute "size" (toString n) + + +{-| The element ID described by this `label` or the element IDs that are used +for an `output`. +-} +for : String -> Attribute msg +for value = + stringProperty "htmlFor" value + + +{-| Indicates the element ID of the `form` that owns this particular `button`, +`fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, +`progress`, `select`, or `textarea`. +-} +form : String -> Attribute msg +form value = + attribute "form" value + + + +-- RANGES + + +{-| Indicates the maximum value allowed. When using an input of type number or +date, the max value must be a number or date. For `input`, `meter`, and `progress`. +-} +max : String -> Attribute msg +max value = + stringProperty "max" value + + +{-| Indicates the minimum value allowed. When using an input of type number or +date, the min value must be a number or date. For `input` and `meter`. +-} +min : String -> Attribute msg +min value = + stringProperty "min" value + + +{-| Add a step size to an `input`. Use `step "any"` to allow any floating-point +number to be used in the input. +-} +step : String -> Attribute msg +step n = + stringProperty "step" n + + +-------------------------- + + +{-| Defines the number of columns in a `textarea`. -} +cols : Int -> Attribute msg +cols n = + attribute "cols" (toString n) + + +{-| Defines the number of rows in a `textarea`. -} +rows : Int -> Attribute msg +rows n = + attribute "rows" (toString n) + + +{-| Indicates whether the text should be wrapped in a `textarea`. Possible +values are "hard" and "soft". +-} +wrap : String -> Attribute msg +wrap value = + stringProperty "wrap" value + + + +-- MAPS + + +{-| When an `img` is a descendent of an `a` tag, the `ismap` attribute +indicates that the click location should be added to the parent `a`'s href as +a query string. +-} +ismap : Bool -> Attribute msg +ismap value = + boolProperty "isMap" value + + +{-| Specify the hash name reference of a `map` that should be used for an `img` +or `object`. A hash name reference is a hash symbol followed by the element's name or id. +E.g. `"#planet-map"`. +-} +usemap : String -> Attribute msg +usemap value = + stringProperty "useMap" value + + +{-| Declare the shape of the clickable area in an `a` or `area`. Valid values +include: default, rect, circle, poly. This attribute can be paired with +`coords` to create more particular shapes. +-} +shape : String -> Attribute msg +shape value = + stringProperty "shape" value + + +{-| A set of values specifying the coordinates of the hot-spot region in an +`area`. Needs to be paired with a `shape` attribute to be meaningful. +-} +coords : String -> Attribute msg +coords value = + stringProperty "coords" value + + + +-- KEY GEN + + +{-| A challenge string that is submitted along with the public key in a `keygen`. +-} +challenge : String -> Attribute msg +challenge value = + attribute "challenge" value + + +{-| Specifies the type of key generated by a `keygen`. Possible values are: +rsa, dsa, and ec. +-} +keytype : String -> Attribute msg +keytype value = + stringProperty "keytype" value + + + +-- REAL STUFF + + +{-| Specifies the horizontal alignment of a `caption`, `col`, `colgroup`, +`hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, or +`tr`. +-} +align : String -> Attribute msg +align value = + stringProperty "align" value + + +{-| Contains a URI which points to the source of the quote or change in a +`blockquote`, `del`, `ins`, or `q`. +-} +cite : String -> Attribute msg +cite value = + stringProperty "cite" value + + + + +-- LINKS AND AREAS + + +{-| The URL of a linked resource, such as `a`, `area`, `base`, or `link`. -} +href : String -> Attribute msg +href value = + stringProperty "href" value + + +{-| Specify where the results of clicking an `a`, `area`, `base`, or `form` +should appear. Possible special values include: + + * _blank — a new window or tab + * _self — the same frame (this is default) + * _parent — the parent frame + * _top — the full body of the window + +You can also give the name of any `frame` you have created. +-} +target : String -> Attribute msg +target value = + stringProperty "target" value + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly. +-} +download : Bool -> Attribute msg +download bool = + boolProperty "download" bool + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly, and that the downloaded resource with have the given filename. +-} +downloadAs : String -> Attribute msg +downloadAs value = + stringProperty "download" value + + +{-| Two-letter language code of the linked resource of an `a`, `area`, or `link`. +-} +hreflang : String -> Attribute msg +hreflang value = + stringProperty "hreflang" value + + +{-| Specifies a hint of the target media of a `a`, `area`, `link`, `source`, +or `style`. +-} +media : String -> Attribute msg +media value = + attribute "media" value + + +{-| Specify a URL to send a short POST request to when the user clicks on an +`a` or `area`. Useful for monitoring and tracking. +-} +ping : String -> Attribute msg +ping value = + stringProperty "ping" value + + +{-| Specifies the relationship of the target object to the link object. +For `a`, `area`, `link`. +-} +rel : String -> Attribute msg +rel value = + attribute "rel" value + + + +-- CRAZY STUFF + + +{-| Indicates the date and time associated with the element. +For `del`, `ins`, `time`. +-} +datetime : String -> Attribute msg +datetime value = + attribute "datetime" value + + +{-| Indicates whether this date and time is the date of the nearest `article` +ancestor element. For `time`. +-} +pubdate : String -> Attribute msg +pubdate value = + attribute "pubdate" value + + + +-- ORDERED LISTS + + +{-| Indicates whether an ordered list `ol` should be displayed in a descending +order instead of a ascending. +-} +reversed : Bool -> Attribute msg +reversed bool = + boolProperty "reversed" bool + + +{-| Defines the first number of an ordered list if you want it to be something +besides 1. +-} +start : Int -> Attribute msg +start n = + stringProperty "start" (toString n) + + + +-- TABLES + + +{-| The colspan attribute defines the number of columns a cell should span. +For `td` and `th`. +-} +colspan : Int -> Attribute msg +colspan n = + attribute "colspan" (toString n) + + +{-| A space separated list of element IDs indicating which `th` elements are +headers for this cell. For `td` and `th`. +-} +headers : String -> Attribute msg +headers value = + stringProperty "headers" value + + +{-| Defines the number of rows a table cell should span over. +For `td` and `th`. +-} +rowspan : Int -> Attribute msg +rowspan n = + attribute "rowspan" (toString n) + + +{-| Specifies the scope of a header cell `th`. Possible values are: col, row, +colgroup, rowgroup. +-} +scope : String -> Attribute msg +scope value = + stringProperty "scope" value + + +{-| Specifies the URL of the cache manifest for an `html` tag. -} +manifest : String -> Attribute msg +manifest value = + attribute "manifest" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| The number of columns a `col` or `colgroup` should span. -} +span : Int -> Attribute msg +span n = + stringProperty "span" (toString n) +--} diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm new file mode 100644 index 0000000..ff5c1fe --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm @@ -0,0 +1,269 @@ +module Html.Events exposing + ( onClick, onDoubleClick + , onMouseDown, onMouseUp + , onMouseEnter, onMouseLeave + , onMouseOver, onMouseOut + , onInput, onCheck, onSubmit + , onBlur, onFocus + , on, onWithOptions, Options, defaultOptions + , targetValue, targetChecked, keyCode + ) + +{-| +It is often helpful to create an [Union Type][] so you can have many different kinds +of events as seen in the [TodoMVC][] example. + +[Union Type]: http://elm-lang.org/learn/Union-Types.elm +[TodoMVC]: https://github.com/evancz/elm-todomvc/blob/master/Todo.elm + +# Mouse Helpers +@docs onClick, onDoubleClick, + onMouseDown, onMouseUp, + onMouseEnter, onMouseLeave, + onMouseOver, onMouseOut + +# Form Helpers +@docs onInput, onCheck, onSubmit + +# Focus Helpers +@docs onBlur, onFocus + +# Custom Event Handlers +@docs on, onWithOptions, Options, defaultOptions + +# Custom Decoders +@docs targetValue, targetChecked, keyCode +-} + +import Html exposing (Attribute) +import Json.Decode as Json +import VirtualDom + + + +-- MOUSE EVENTS + + +{-|-} +onClick : msg -> Attribute msg +onClick msg = + on "click" (Json.succeed msg) + + +{-|-} +onDoubleClick : msg -> Attribute msg +onDoubleClick msg = + on "dblclick" (Json.succeed msg) + + +{-|-} +onMouseDown : msg -> Attribute msg +onMouseDown msg = + on "mousedown" (Json.succeed msg) + + +{-|-} +onMouseUp : msg -> Attribute msg +onMouseUp msg = + on "mouseup" (Json.succeed msg) + + +{-|-} +onMouseEnter : msg -> Attribute msg +onMouseEnter msg = + on "mouseenter" (Json.succeed msg) + + +{-|-} +onMouseLeave : msg -> Attribute msg +onMouseLeave msg = + on "mouseleave" (Json.succeed msg) + + +{-|-} +onMouseOver : msg -> Attribute msg +onMouseOver msg = + on "mouseover" (Json.succeed msg) + + +{-|-} +onMouseOut : msg -> Attribute msg +onMouseOut msg = + on "mouseout" (Json.succeed msg) + + + +-- FORM EVENTS + + +{-| Capture [input](https://developer.mozilla.org/en-US/docs/Web/Events/input) +events for things like text fields or text areas. + +It grabs the **string** value at `event.target.value`, so it will not work if +you need some other type of information. For example, if you want to track +inputs on a range slider, make a custom handler with [`on`](#on). + +For more details on how `onInput` works, check out [targetValue](#targetValue). +-} +onInput : (String -> msg) -> Attribute msg +onInput tagger = + on "input" (Json.map tagger targetValue) + + +{-| Capture [change](https://developer.mozilla.org/en-US/docs/Web/Events/change) +events on checkboxes. It will grab the boolean value from `event.target.checked` +on any input event. + +Check out [targetChecked](#targetChecked) for more details on how this works. +-} +onCheck : (Bool -> msg) -> Attribute msg +onCheck tagger = + on "change" (Json.map tagger targetChecked) + + +{-| Capture a [submit](https://developer.mozilla.org/en-US/docs/Web/Events/submit) +event with [`preventDefault`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) +in order to prevent the form from changing the page’s location. If you need +different behavior, use `onWithOptions` to create a customized version of +`onSubmit`. +-} +onSubmit : msg -> Attribute msg +onSubmit msg = + onWithOptions "submit" onSubmitOptions (Json.succeed msg) + + +onSubmitOptions : Options +onSubmitOptions = + { defaultOptions | preventDefault = True } + + +-- FOCUS EVENTS + + +{-|-} +onBlur : msg -> Attribute msg +onBlur msg = + on "blur" (Json.succeed msg) + + +{-|-} +onFocus : msg -> Attribute msg +onFocus msg = + on "focus" (Json.succeed msg) + + + +-- CUSTOM EVENTS + + +{-| Create a custom event listener. Normally this will not be necessary, but +you have the power! Here is how `onClick` is defined for example: + + import Json.Decode as Json + + onClick : msg -> Attribute msg + onClick message = + on "click" (Json.succeed message) + +The first argument is the event name in the same format as with JavaScript's +[`addEventListener`][aEL] function. + +The second argument is a JSON decoder. Read more about these [here][decoder]. +When an event occurs, the decoder tries to turn the event object into an Elm +value. If successful, the value is routed to your `update` function. In the +case of `onClick` we always just succeed with the given `message`. + +If this is confusing, work through the [Elm Architecture Tutorial][tutorial]. +It really does help! + +[aEL]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener +[decoder]: http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode +[tutorial]: https://github.com/evancz/elm-architecture-tutorial/ +-} +on : String -> Json.Decoder msg -> Attribute msg +on = + VirtualDom.on + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Attribute msg +onWithOptions = + VirtualDom.onWithOptions + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + VirtualDom.defaultOptions + + + +-- COMMON DECODERS + + +{-| A `Json.Decoder` for grabbing `event.target.value`. We use this to define +`onInput` as follows: + + import Json.Decode as Json + + onInput : (String -> msg) -> Attribute msg + onInput tagger = + on "input" (Json.map tagger targetValue) + +You probably will never need this, but hopefully it gives some insights into +how to make custom event handlers. +-} +targetValue : Json.Decoder String +targetValue = + Json.at ["target", "value"] Json.string + + +{-| A `Json.Decoder` for grabbing `event.target.checked`. We use this to define +`onCheck` as follows: + + import Json.Decode as Json + + onCheck : (Bool -> msg) -> Attribute msg + onCheck tagger = + on "input" (Json.map tagger targetChecked) +-} +targetChecked : Json.Decoder Bool +targetChecked = + Json.at ["target", "checked"] Json.bool + + +{-| A `Json.Decoder` for grabbing `event.keyCode`. This helps you define +keyboard listeners like this: + + import Json.Decode as Json + + onKeyUp : (Int -> msg) -> Attribute msg + onKeyUp tagger = + on "keyup" (Json.map tagger keyCode) + +**Note:** It looks like the spec is moving away from `event.keyCode` and +towards `event.key`. Once this is supported in more browsers, we may add +helpers here for `onKeyUp`, `onKeyDown`, `onKeyPress`, etc. +-} +keyCode : Json.Decoder Int +keyCode = + Json.field "keyCode" Json.int diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm new file mode 100644 index 0000000..debd710 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm @@ -0,0 +1,48 @@ +module Html.Keyed exposing + ( node + , ol + , ul + ) +{-| A keyed node helps optimize cases where children are getting added, moved, +removed, etc. Common examples include: + + - The user can delete items from a list. + - The user can create new items in a list. + - You can sort a list based on name or date or whatever. + +When you use a keyed node, every child is paired with a string identifier. This +makes it possible for the underlying diffing algorithm to reuse nodes more +efficiently. + +# Keyed Nodes +@docs node + +# Commonly Keyed Nodes +@docs ol, ul +-} + + +import Html exposing (Attribute, Html) +import VirtualDom + + +{-| Works just like `Html.node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +node : String -> List (Attribute msg) -> List ( String, Html msg ) -> Html msg +node = + VirtualDom.keyedNode + + +{-|-} +ol : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ol = + node "ol" + + +{-|-} +ul : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ul = + node "ul" diff --git a/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm new file mode 100644 index 0000000..f027ffc --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm @@ -0,0 +1,48 @@ +module Html.Lazy exposing + ( lazy, lazy2, lazy3 + ) + +{-| Since all Elm functions are pure we have a guarantee that the same input +will always result in the same output. This module gives us tools to be lazy +about building `Html` that utilize this fact. + +Rather than immediately applying functions to their arguments, the `lazy` +functions just bundle the function and arguments up for later. When diffing +the old and new virtual DOM, it checks to see if all the arguments are equal. +If so, it skips calling the function! + +This is a really cheap test and often makes things a lot faster, but definitely +benchmark to be sure! + +@docs lazy, lazy2, lazy3 +-} + +import Html exposing (Html) +import VirtualDom + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Html msg) -> a -> Html msg +lazy = + VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Html msg) -> a -> b -> Html msg +lazy2 = + VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg +lazy3 = + VirtualDom.lazy3 diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore new file mode 100644 index 0000000..f6a4e83 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore @@ -0,0 +1,3 @@ +node_modules +elm-stuff +tests/build diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE new file mode 100644 index 0000000..0edfd04 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json new file mode 100644 index 0000000..353986f --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.4", + "summary": "Core virtual DOM implementation, basis for HTML and SVG libraries", + "repository": "https://github.com/elm-lang/virtual-dom.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "VirtualDom" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js new file mode 100644 index 0000000..729f171 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js @@ -0,0 +1,280 @@ +var _elm_lang$virtual_dom$Native_Debug = function() { + + +// IMPORT / EXPORT + +function unsafeCoerce(value) +{ + return value; +} + +var upload = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + var element = document.createElement('input'); + element.setAttribute('type', 'file'); + element.setAttribute('accept', 'text/json'); + element.style.display = 'none'; + element.addEventListener('change', function(event) + { + var fileReader = new FileReader(); + fileReader.onload = function(e) + { + callback(_elm_lang$core$Native_Scheduler.succeed(e.target.result)); + }; + fileReader.readAsText(event.target.files[0]); + document.body.removeChild(element); + }); + document.body.appendChild(element); + element.click(); +}); + +function download(historyLength, json) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var fileName = 'history-' + historyLength + '.txt'; + var jsonString = JSON.stringify(json); + var mime = 'text/plain;charset=utf-8'; + var done = _elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0); + + // for IE10+ + if (navigator.msSaveBlob) + { + navigator.msSaveBlob(new Blob([jsonString], {type: mime}), fileName); + return callback(done); + } + + // for HTML5 + var element = document.createElement('a'); + element.setAttribute('href', 'data:' + mime + ',' + encodeURIComponent(jsonString)); + element.setAttribute('download', fileName); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + callback(done); + }); +} + + +// POPOUT + +function messageToString(value) +{ + switch (typeof value) + { + case 'boolean': + return value ? 'True' : 'False'; + case 'number': + return value + ''; + case 'string': + return '"' + addSlashes(value, false) + '"'; + } + if (value instanceof String) + { + return '\'' + addSlashes(value, true) + '\''; + } + if (typeof value !== 'object' || value === null || !('ctor' in value)) + { + return '…'; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Tupl' || ctorStarter === '_Task') + { + return '…' + } + if (['_Array', '', '_Process', '::', '[]', 'Set_elm_builtin', 'RBNode_elm_builtin', 'RBEmpty_elm_builtin'].indexOf(value.ctor) >= 0) + { + return '…'; + } + + var keys = Object.keys(value); + switch (keys.length) + { + case 1: + return value.ctor; + case 2: + return value.ctor + ' ' + messageToString(value._0); + default: + return value.ctor + ' … ' + messageToString(value[keys[keys.length - 1]]); + } +} + + +function primitive(str) +{ + return { ctor: 'Primitive', _0: str }; +} + + +function init(value) +{ + var type = typeof value; + + if (type === 'boolean') + { + return { + ctor: 'Constructor', + _0: _elm_lang$core$Maybe$Just(value ? 'True' : 'False'), + _1: true, + _2: _elm_lang$core$Native_List.Nil + }; + } + + if (type === 'number') + { + return primitive(value + ''); + } + + if (type === 'string') + { + return { ctor: 'S', _0: '"' + addSlashes(value, false) + '"' }; + } + + if (value instanceof String) + { + return { ctor: 'S', _0: "'" + addSlashes(value, true) + "'" }; + } + + if (value instanceof Date) + { + return primitive('<' + value.toString() + '>'); + } + + if (value === null) + { + return primitive('XXX'); + } + + if (type === 'object' && 'ctor' in value) + { + var ctor = value.ctor; + + if (ctor === '::' || ctor === '[]') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ListSeq'}, + _1: true, + _2: A2(_elm_lang$core$List$map, init, value) + }; + } + + if (ctor === 'Set_elm_builtin') + { + return { + ctor: 'Sequence', + _0: {ctor: 'SetSeq'}, + _1: true, + _2: A3(_elm_lang$core$Set$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === 'RBNode_elm_builtin' || ctor == 'RBEmpty_elm_builtin') + { + return { + ctor: 'Dictionary', + _0: true, + _1: A3(_elm_lang$core$Dict$foldr, initKeyValueCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === '_Array') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ArraySeq'}, + _1: true, + _2: A3(_elm_lang$core$Array$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Task') + { + return primitive(''); + } + + if (ctor === '') + { + return primitive(ctor); + } + + if (ctor === '_Process') + { + return primitive(''); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i in value) + { + if (i === 'ctor') continue; + list = _elm_lang$core$Native_List.Cons(init(value[i]), list); + } + return { + ctor: 'Constructor', + _0: ctorStarter === '_Tupl' ? _elm_lang$core$Maybe$Nothing : _elm_lang$core$Maybe$Just(ctor), + _1: true, + _2: _elm_lang$core$List$reverse(list) + }; + } + + if (type === 'object') + { + var dict = _elm_lang$core$Dict$empty; + for (var i in value) + { + dict = A3(_elm_lang$core$Dict$insert, i, init(value[i]), dict); + } + return { ctor: 'Record', _0: true, _1: dict }; + } + + return primitive('XXX'); +} + +var initCons = F2(initConsHelp); + +function initConsHelp(value, list) +{ + return _elm_lang$core$Native_List.Cons(init(value), list); +} + +var initKeyValueCons = F3(initKeyValueConsHelp); + +function initKeyValueConsHelp(key, value, list) +{ + return _elm_lang$core$Native_List.Cons( + _elm_lang$core$Native_Utils.Tuple2(init(key), init(value)), + list + ); +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + upload: upload, + download: F2(download), + unsafeCoerce: unsafeCoerce, + messageToString: messageToString, + init: init +} + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js new file mode 100644 index 0000000..98d4750 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js @@ -0,0 +1,1881 @@ +var _elm_lang$virtual_dom$VirtualDom_Debug$wrap; +var _elm_lang$virtual_dom$VirtualDom_Debug$wrapWithFlags; + +var _elm_lang$virtual_dom$Native_VirtualDom = function() { + +var STYLE_KEY = 'STYLE'; +var EVENT_KEY = 'EVENT'; +var ATTR_KEY = 'ATTR'; +var ATTR_NS_KEY = 'ATTR_NS'; + +var localDoc = typeof document !== 'undefined' ? document : {}; + + +//////////// VIRTUAL DOM NODES //////////// + + +function text(string) +{ + return { + type: 'text', + text: string + }; +} + + +function node(tag) +{ + return F2(function(factList, kidList) { + return nodeHelp(tag, factList, kidList); + }); +} + + +function nodeHelp(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function keyedNode(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid._1.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'keyed-node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function custom(factList, model, impl) +{ + var facts = organizeFacts(factList).facts; + + return { + type: 'custom', + facts: facts, + model: model, + impl: impl + }; +} + + +function map(tagger, node) +{ + return { + type: 'tagger', + tagger: tagger, + node: node, + descendantsCount: 1 + (node.descendantsCount || 0) + }; +} + + +function thunk(func, args, thunk) +{ + return { + type: 'thunk', + func: func, + args: args, + thunk: thunk, + node: undefined + }; +} + +function lazy(fn, a) +{ + return thunk(fn, [a], function() { + return fn(a); + }); +} + +function lazy2(fn, a, b) +{ + return thunk(fn, [a,b], function() { + return A2(fn, a, b); + }); +} + +function lazy3(fn, a, b, c) +{ + return thunk(fn, [a,b,c], function() { + return A3(fn, a, b, c); + }); +} + + + +// FACTS + + +function organizeFacts(factList) +{ + var namespace, facts = {}; + + while (factList.ctor !== '[]') + { + var entry = factList._0; + var key = entry.key; + + if (key === ATTR_KEY || key === ATTR_NS_KEY || key === EVENT_KEY) + { + var subFacts = facts[key] || {}; + subFacts[entry.realKey] = entry.value; + facts[key] = subFacts; + } + else if (key === STYLE_KEY) + { + var styles = facts[key] || {}; + var styleList = entry.value; + while (styleList.ctor !== '[]') + { + var style = styleList._0; + styles[style._0] = style._1; + styleList = styleList._1; + } + facts[key] = styles; + } + else if (key === 'namespace') + { + namespace = entry.value; + } + else if (key === 'className') + { + var classes = facts[key]; + facts[key] = typeof classes === 'undefined' + ? entry.value + : classes + ' ' + entry.value; + } + else + { + facts[key] = entry.value; + } + factList = factList._1; + } + + return { + facts: facts, + namespace: namespace + }; +} + + + +//////////// PROPERTIES AND ATTRIBUTES //////////// + + +function style(value) +{ + return { + key: STYLE_KEY, + value: value + }; +} + + +function property(key, value) +{ + return { + key: key, + value: value + }; +} + + +function attribute(key, value) +{ + return { + key: ATTR_KEY, + realKey: key, + value: value + }; +} + + +function attributeNS(namespace, key, value) +{ + return { + key: ATTR_NS_KEY, + realKey: key, + value: { + value: value, + namespace: namespace + } + }; +} + + +function on(name, options, decoder) +{ + return { + key: EVENT_KEY, + realKey: name, + value: { + options: options, + decoder: decoder + } + }; +} + + +function equalEvents(a, b) +{ + if (a.options !== b.options) + { + if (a.options.stopPropagation !== b.options.stopPropagation || a.options.preventDefault !== b.options.preventDefault) + { + return false; + } + } + return _elm_lang$core$Native_Json.equality(a.decoder, b.decoder); +} + + +function mapProperty(func, property) +{ + if (property.key !== EVENT_KEY) + { + return property; + } + return on( + property.realKey, + property.value.options, + A2(_elm_lang$core$Json_Decode$map, func, property.value.decoder) + ); +} + + +//////////// RENDER //////////// + + +function render(vNode, eventNode) +{ + switch (vNode.type) + { + case 'thunk': + if (!vNode.node) + { + vNode.node = vNode.thunk(); + } + return render(vNode.node, eventNode); + + case 'tagger': + var subNode = vNode.node; + var tagger = vNode.tagger; + + while (subNode.type === 'tagger') + { + typeof tagger !== 'object' + ? tagger = [tagger, subNode.tagger] + : tagger.push(subNode.tagger); + + subNode = subNode.node; + } + + var subEventRoot = { tagger: tagger, parent: eventNode }; + var domNode = render(subNode, subEventRoot); + domNode.elm_event_node_ref = subEventRoot; + return domNode; + + case 'text': + return localDoc.createTextNode(vNode.text); + + case 'node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i], eventNode)); + } + + return domNode; + + case 'keyed-node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i]._1, eventNode)); + } + + return domNode; + + case 'custom': + var domNode = vNode.impl.render(vNode.model); + applyFacts(domNode, eventNode, vNode.facts); + return domNode; + } +} + + + +//////////// APPLY FACTS //////////// + + +function applyFacts(domNode, eventNode, facts) +{ + for (var key in facts) + { + var value = facts[key]; + + switch (key) + { + case STYLE_KEY: + applyStyles(domNode, value); + break; + + case EVENT_KEY: + applyEvents(domNode, eventNode, value); + break; + + case ATTR_KEY: + applyAttrs(domNode, value); + break; + + case ATTR_NS_KEY: + applyAttrsNS(domNode, value); + break; + + case 'value': + if (domNode[key] !== value) + { + domNode[key] = value; + } + break; + + default: + domNode[key] = value; + break; + } + } +} + +function applyStyles(domNode, styles) +{ + var domNodeStyle = domNode.style; + + for (var key in styles) + { + domNodeStyle[key] = styles[key]; + } +} + +function applyEvents(domNode, eventNode, events) +{ + var allHandlers = domNode.elm_handlers || {}; + + for (var key in events) + { + var handler = allHandlers[key]; + var value = events[key]; + + if (typeof value === 'undefined') + { + domNode.removeEventListener(key, handler); + allHandlers[key] = undefined; + } + else if (typeof handler === 'undefined') + { + var handler = makeEventHandler(eventNode, value); + domNode.addEventListener(key, handler); + allHandlers[key] = handler; + } + else + { + handler.info = value; + } + } + + domNode.elm_handlers = allHandlers; +} + +function makeEventHandler(eventNode, info) +{ + function eventHandler(event) + { + var info = eventHandler.info; + + var value = A2(_elm_lang$core$Native_Json.run, info.decoder, event); + + if (value.ctor === 'Ok') + { + var options = info.options; + if (options.stopPropagation) + { + event.stopPropagation(); + } + if (options.preventDefault) + { + event.preventDefault(); + } + + var message = value._0; + + var currentEventNode = eventNode; + while (currentEventNode) + { + var tagger = currentEventNode.tagger; + if (typeof tagger === 'function') + { + message = tagger(message); + } + else + { + for (var i = tagger.length; i--; ) + { + message = tagger[i](message); + } + } + currentEventNode = currentEventNode.parent; + } + } + }; + + eventHandler.info = info; + + return eventHandler; +} + +function applyAttrs(domNode, attrs) +{ + for (var key in attrs) + { + var value = attrs[key]; + if (typeof value === 'undefined') + { + domNode.removeAttribute(key); + } + else + { + domNode.setAttribute(key, value); + } + } +} + +function applyAttrsNS(domNode, nsAttrs) +{ + for (var key in nsAttrs) + { + var pair = nsAttrs[key]; + var namespace = pair.namespace; + var value = pair.value; + + if (typeof value === 'undefined') + { + domNode.removeAttributeNS(namespace, key); + } + else + { + domNode.setAttributeNS(namespace, key, value); + } + } +} + + + +//////////// DIFF //////////// + + +function diff(a, b) +{ + var patches = []; + diffHelp(a, b, patches, 0); + return patches; +} + + +function makePatch(type, index, data) +{ + return { + index: index, + type: type, + data: data, + domNode: undefined, + eventNode: undefined + }; +} + + +function diffHelp(a, b, patches, index) +{ + if (a === b) + { + return; + } + + var aType = a.type; + var bType = b.type; + + // Bail if you run into different types of nodes. Implies that the + // structure has changed significantly and it's not worth a diff. + if (aType !== bType) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // Now we know that both nodes are the same type. + switch (bType) + { + case 'thunk': + var aArgs = a.args; + var bArgs = b.args; + var i = aArgs.length; + var same = a.func === b.func && i === bArgs.length; + while (same && i--) + { + same = aArgs[i] === bArgs[i]; + } + if (same) + { + b.node = a.node; + return; + } + b.node = b.thunk(); + var subPatches = []; + diffHelp(a.node, b.node, subPatches, 0); + if (subPatches.length > 0) + { + patches.push(makePatch('p-thunk', index, subPatches)); + } + return; + + case 'tagger': + // gather nested taggers + var aTaggers = a.tagger; + var bTaggers = b.tagger; + var nesting = false; + + var aSubNode = a.node; + while (aSubNode.type === 'tagger') + { + nesting = true; + + typeof aTaggers !== 'object' + ? aTaggers = [aTaggers, aSubNode.tagger] + : aTaggers.push(aSubNode.tagger); + + aSubNode = aSubNode.node; + } + + var bSubNode = b.node; + while (bSubNode.type === 'tagger') + { + nesting = true; + + typeof bTaggers !== 'object' + ? bTaggers = [bTaggers, bSubNode.tagger] + : bTaggers.push(bSubNode.tagger); + + bSubNode = bSubNode.node; + } + + // Just bail if different numbers of taggers. This implies the + // structure of the virtual DOM has changed. + if (nesting && aTaggers.length !== bTaggers.length) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // check if taggers are "the same" + if (nesting ? !pairwiseRefEqual(aTaggers, bTaggers) : aTaggers !== bTaggers) + { + patches.push(makePatch('p-tagger', index, bTaggers)); + } + + // diff everything below the taggers + diffHelp(aSubNode, bSubNode, patches, index + 1); + return; + + case 'text': + if (a.text !== b.text) + { + patches.push(makePatch('p-text', index, b.text)); + return; + } + + return; + + case 'node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffChildren(a, b, patches, index); + return; + + case 'keyed-node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffKeyedChildren(a, b, patches, index); + return; + + case 'custom': + if (a.impl !== b.impl) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + var patch = b.impl.diff(a,b); + if (patch) + { + patches.push(makePatch('p-custom', index, patch)); + return; + } + + return; + } +} + + +// assumes the incoming arrays are the same length +function pairwiseRefEqual(as, bs) +{ + for (var i = 0; i < as.length; i++) + { + if (as[i] !== bs[i]) + { + return false; + } + } + + return true; +} + + +// TODO Instead of creating a new diff object, it's possible to just test if +// there *is* a diff. During the actual patch, do the diff again and make the +// modifications directly. This way, there's no new allocations. Worth it? +function diffFacts(a, b, category) +{ + var diff; + + // look for changes and removals + for (var aKey in a) + { + if (aKey === STYLE_KEY || aKey === EVENT_KEY || aKey === ATTR_KEY || aKey === ATTR_NS_KEY) + { + var subDiff = diffFacts(a[aKey], b[aKey] || {}, aKey); + if (subDiff) + { + diff = diff || {}; + diff[aKey] = subDiff; + } + continue; + } + + // remove if not in the new facts + if (!(aKey in b)) + { + diff = diff || {}; + diff[aKey] = + (typeof category === 'undefined') + ? (typeof a[aKey] === 'string' ? '' : null) + : + (category === STYLE_KEY) + ? '' + : + (category === EVENT_KEY || category === ATTR_KEY) + ? undefined + : + { namespace: a[aKey].namespace, value: undefined }; + + continue; + } + + var aValue = a[aKey]; + var bValue = b[aKey]; + + // reference equal, so don't worry about it + if (aValue === bValue && aKey !== 'value' + || category === EVENT_KEY && equalEvents(aValue, bValue)) + { + continue; + } + + diff = diff || {}; + diff[aKey] = bValue; + } + + // add new stuff + for (var bKey in b) + { + if (!(bKey in a)) + { + diff = diff || {}; + diff[bKey] = b[bKey]; + } + } + + return diff; +} + + +function diffChildren(aParent, bParent, patches, rootIndex) +{ + var aChildren = aParent.children; + var bChildren = bParent.children; + + var aLen = aChildren.length; + var bLen = bChildren.length; + + // FIGURE OUT IF THERE ARE INSERTS OR REMOVALS + + if (aLen > bLen) + { + patches.push(makePatch('p-remove-last', rootIndex, aLen - bLen)); + } + else if (aLen < bLen) + { + patches.push(makePatch('p-append', rootIndex, bChildren.slice(aLen))); + } + + // PAIRWISE DIFF EVERYTHING ELSE + + var index = rootIndex; + var minLen = aLen < bLen ? aLen : bLen; + for (var i = 0; i < minLen; i++) + { + index++; + var aChild = aChildren[i]; + diffHelp(aChild, bChildren[i], patches, index); + index += aChild.descendantsCount || 0; + } +} + + + +//////////// KEYED DIFF //////////// + + +function diffKeyedChildren(aParent, bParent, patches, rootIndex) +{ + var localPatches = []; + + var changes = {}; // Dict String Entry + var inserts = []; // Array { index : Int, entry : Entry } + // type Entry = { tag : String, vnode : VNode, index : Int, data : _ } + + var aChildren = aParent.children; + var bChildren = bParent.children; + var aLen = aChildren.length; + var bLen = bChildren.length; + var aIndex = 0; + var bIndex = 0; + + var index = rootIndex; + + while (aIndex < aLen && bIndex < bLen) + { + var a = aChildren[aIndex]; + var b = bChildren[bIndex]; + + var aKey = a._0; + var bKey = b._0; + var aNode = a._1; + var bNode = b._1; + + // check if keys match + + if (aKey === bKey) + { + index++; + diffHelp(aNode, bNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex++; + bIndex++; + continue; + } + + // look ahead 1 to detect insertions and removals. + + var aLookAhead = aIndex + 1 < aLen; + var bLookAhead = bIndex + 1 < bLen; + + if (aLookAhead) + { + var aNext = aChildren[aIndex + 1]; + var aNextKey = aNext._0; + var aNextNode = aNext._1; + var oldMatch = bKey === aNextKey; + } + + if (bLookAhead) + { + var bNext = bChildren[bIndex + 1]; + var bNextKey = bNext._0; + var bNextNode = bNext._1; + var newMatch = aKey === bNextKey; + } + + + // swap a and b + if (aLookAhead && bLookAhead && newMatch && oldMatch) + { + index++; + diffHelp(aNode, bNextNode, localPatches, index); + insertNode(changes, localPatches, aKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + removeNode(changes, localPatches, aKey, aNextNode, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + // insert b + if (bLookAhead && newMatch) + { + index++; + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + diffHelp(aNode, bNextNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex += 1; + bIndex += 2; + continue; + } + + // remove a + if (aLookAhead && oldMatch) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 1; + continue; + } + + // remove a, insert b + if (aLookAhead && bLookAhead && aNextKey === bNextKey) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNextNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + break; + } + + // eat up any remaining nodes with removeNode and insertNode + + while (aIndex < aLen) + { + index++; + var a = aChildren[aIndex]; + var aNode = a._1; + removeNode(changes, localPatches, a._0, aNode, index); + index += aNode.descendantsCount || 0; + aIndex++; + } + + var endInserts; + while (bIndex < bLen) + { + endInserts = endInserts || []; + var b = bChildren[bIndex]; + insertNode(changes, localPatches, b._0, b._1, undefined, endInserts); + bIndex++; + } + + if (localPatches.length > 0 || inserts.length > 0 || typeof endInserts !== 'undefined') + { + patches.push(makePatch('p-reorder', rootIndex, { + patches: localPatches, + inserts: inserts, + endInserts: endInserts + })); + } +} + + + +//////////// CHANGES FROM KEYED DIFF //////////// + + +var POSTFIX = '_elmW6BL'; + + +function insertNode(changes, localPatches, key, vnode, bIndex, inserts) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + entry = { + tag: 'insert', + vnode: vnode, + index: bIndex, + data: undefined + }; + + inserts.push({ index: bIndex, entry: entry }); + changes[key] = entry; + + return; + } + + // this key was removed earlier, a match! + if (entry.tag === 'remove') + { + inserts.push({ index: bIndex, entry: entry }); + + entry.tag = 'move'; + var subPatches = []; + diffHelp(entry.vnode, vnode, subPatches, entry.index); + entry.index = bIndex; + entry.data.data = { + patches: subPatches, + entry: entry + }; + + return; + } + + // this key has already been inserted or moved, a duplicate! + insertNode(changes, localPatches, key + POSTFIX, vnode, bIndex, inserts); +} + + +function removeNode(changes, localPatches, key, vnode, index) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + var patch = makePatch('p-remove', index, undefined); + localPatches.push(patch); + + changes[key] = { + tag: 'remove', + vnode: vnode, + index: index, + data: patch + }; + + return; + } + + // this key was inserted earlier, a match! + if (entry.tag === 'insert') + { + entry.tag = 'move'; + var subPatches = []; + diffHelp(vnode, entry.vnode, subPatches, index); + + var patch = makePatch('p-remove', index, { + patches: subPatches, + entry: entry + }); + localPatches.push(patch); + + return; + } + + // this key has already been removed or moved, a duplicate! + removeNode(changes, localPatches, key + POSTFIX, vnode, index); +} + + + +//////////// ADD DOM NODES //////////// +// +// Each DOM node has an "index" assigned in order of traversal. It is important +// to minimize our crawl over the actual DOM, so these indexes (along with the +// descendantsCount of virtual nodes) let us skip touching entire subtrees of +// the DOM if we know there are no patches there. + + +function addDomNodes(domNode, vNode, patches, eventNode) +{ + addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.descendantsCount, eventNode); +} + + +// assumes `patches` is non-empty and indexes increase monotonically. +function addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode) +{ + var patch = patches[i]; + var index = patch.index; + + while (index === low) + { + var patchType = patch.type; + + if (patchType === 'p-thunk') + { + addDomNodes(domNode, vNode.node, patch.data, eventNode); + } + else if (patchType === 'p-reorder') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var subPatches = patch.data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + else if (patchType === 'p-remove') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var data = patch.data; + if (typeof data !== 'undefined') + { + data.entry.data = domNode; + var subPatches = data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + } + else + { + patch.domNode = domNode; + patch.eventNode = eventNode; + } + + i++; + + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + + switch (vNode.type) + { + case 'tagger': + var subNode = vNode.node; + + while (subNode.type === "tagger") + { + subNode = subNode.node; + } + + return addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref); + + case 'node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'keyed-node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]._1; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'text': + case 'thunk': + throw new Error('should never traverse `text` or `thunk` nodes like this'); + } +} + + + +//////////// APPLY PATCHES //////////// + + +function applyPatches(rootDomNode, oldVirtualNode, patches, eventNode) +{ + if (patches.length === 0) + { + return rootDomNode; + } + + addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode); + return applyPatchesHelp(rootDomNode, patches); +} + +function applyPatchesHelp(rootDomNode, patches) +{ + for (var i = 0; i < patches.length; i++) + { + var patch = patches[i]; + var localDomNode = patch.domNode + var newNode = applyPatch(localDomNode, patch); + if (localDomNode === rootDomNode) + { + rootDomNode = newNode; + } + } + return rootDomNode; +} + +function applyPatch(domNode, patch) +{ + switch (patch.type) + { + case 'p-redraw': + return applyPatchRedraw(domNode, patch.data, patch.eventNode); + + case 'p-facts': + applyFacts(domNode, patch.eventNode, patch.data); + return domNode; + + case 'p-text': + domNode.replaceData(0, domNode.length, patch.data); + return domNode; + + case 'p-thunk': + return applyPatchesHelp(domNode, patch.data); + + case 'p-tagger': + if (typeof domNode.elm_event_node_ref !== 'undefined') + { + domNode.elm_event_node_ref.tagger = patch.data; + } + else + { + domNode.elm_event_node_ref = { tagger: patch.data, parent: patch.eventNode }; + } + return domNode; + + case 'p-remove-last': + var i = patch.data; + while (i--) + { + domNode.removeChild(domNode.lastChild); + } + return domNode; + + case 'p-append': + var newNodes = patch.data; + for (var i = 0; i < newNodes.length; i++) + { + domNode.appendChild(render(newNodes[i], patch.eventNode)); + } + return domNode; + + case 'p-remove': + var data = patch.data; + if (typeof data === 'undefined') + { + domNode.parentNode.removeChild(domNode); + return domNode; + } + var entry = data.entry; + if (typeof entry.index !== 'undefined') + { + domNode.parentNode.removeChild(domNode); + } + entry.data = applyPatchesHelp(domNode, data.patches); + return domNode; + + case 'p-reorder': + return applyPatchReorder(domNode, patch); + + case 'p-custom': + var impl = patch.data; + return impl.applyPatch(domNode, impl.data); + + default: + throw new Error('Ran into an unknown patch!'); + } +} + + +function applyPatchRedraw(domNode, vNode, eventNode) +{ + var parentNode = domNode.parentNode; + var newNode = render(vNode, eventNode); + + if (typeof newNode.elm_event_node_ref === 'undefined') + { + newNode.elm_event_node_ref = domNode.elm_event_node_ref; + } + + if (parentNode && newNode !== domNode) + { + parentNode.replaceChild(newNode, domNode); + } + return newNode; +} + + +function applyPatchReorder(domNode, patch) +{ + var data = patch.data; + + // remove end inserts + var frag = applyPatchReorderEndInsertsHelp(data.endInserts, patch); + + // removals + domNode = applyPatchesHelp(domNode, data.patches); + + // inserts + var inserts = data.inserts; + for (var i = 0; i < inserts.length; i++) + { + var insert = inserts[i]; + var entry = insert.entry; + var node = entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode); + domNode.insertBefore(node, domNode.childNodes[insert.index]); + } + + // add end inserts + if (typeof frag !== 'undefined') + { + domNode.appendChild(frag); + } + + return domNode; +} + + +function applyPatchReorderEndInsertsHelp(endInserts, patch) +{ + if (typeof endInserts === 'undefined') + { + return; + } + + var frag = localDoc.createDocumentFragment(); + for (var i = 0; i < endInserts.length; i++) + { + var insert = endInserts[i]; + var entry = insert.entry; + frag.appendChild(entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode) + ); + } + return frag; +} + + +// PROGRAMS + +var program = makeProgram(checkNoFlags); +var programWithFlags = makeProgram(checkYesFlags); + +function makeProgram(flagChecker) +{ + return F2(function(debugWrap, impl) + { + return function(flagDecoder) + { + return function(object, moduleName, debugMetadata) + { + var checker = flagChecker(flagDecoder, moduleName); + if (typeof debugMetadata === 'undefined') + { + normalSetup(impl, object, moduleName, checker); + } + else + { + debugSetup(A2(debugWrap, debugMetadata, impl), object, moduleName, checker); + } + }; + }; + }); +} + +function staticProgram(vNode) +{ + var nothing = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + _elm_lang$core$Platform_Cmd$none + ); + return A2(program, _elm_lang$virtual_dom$VirtualDom_Debug$wrap, { + init: nothing, + view: function() { return vNode; }, + update: F2(function() { return nothing; }), + subscriptions: function() { return _elm_lang$core$Platform_Sub$none; } + })(); +} + + +// FLAG CHECKERS + +function checkNoFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flags === 'undefined') + { + return init; + } + + var errorMessage = + 'The `' + moduleName + '` module does not need flags.\n' + + 'Initialize it with no arguments and you should be all set!'; + + crash(errorMessage, domNode); + }; +} + +function checkYesFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flagDecoder === 'undefined') + { + var errorMessage = + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + + crash(errorMessage, domNode); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Ok') + { + return init(result._0); + } + + var errorMessage = + 'Trying to initialize the `' + moduleName + '` module with an unexpected flag.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0; + + crash(errorMessage, domNode); + }; +} + +function crash(errorMessage, domNode) +{ + if (domNode) + { + domNode.innerHTML = + '
' + + '

Oops! Something went wrong when starting your Elm program.

' + + '
' + errorMessage + '
' + + '
'; + } + + throw new Error(errorMessage); +} + + +// NORMAL SETUP + +function normalSetup(impl, object, moduleName, flagChecker) +{ + object['embed'] = function embed(node, flags) + { + while (node.lastChild) + { + node.removeChild(node.lastChild); + } + + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update, + impl.subscriptions, + normalRenderer(node, impl.view) + ); + }; + + object['fullscreen'] = function fullscreen(flags) + { + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update, + impl.subscriptions, + normalRenderer(document.body, impl.view) + ); + }; +} + +function normalRenderer(parentNode, view) +{ + return function(tagger, initialModel) + { + var eventNode = { tagger: tagger, parent: undefined }; + var initialVirtualNode = view(initialModel); + var domNode = render(initialVirtualNode, eventNode); + parentNode.appendChild(domNode); + return makeStepper(domNode, view, initialVirtualNode, eventNode); + }; +} + + +// STEPPER + +var rAF = + typeof requestAnimationFrame !== 'undefined' + ? requestAnimationFrame + : function(callback) { setTimeout(callback, 1000 / 60); }; + +function makeStepper(domNode, view, initialVirtualNode, eventNode) +{ + var state = 'NO_REQUEST'; + var currNode = initialVirtualNode; + var nextModel; + + function updateIfNeeded() + { + switch (state) + { + case 'NO_REQUEST': + throw new Error( + 'Unexpected draw callback.\n' + + 'Please report this to .' + ); + + case 'PENDING_REQUEST': + rAF(updateIfNeeded); + state = 'EXTRA_REQUEST'; + + var nextNode = view(nextModel); + var patches = diff(currNode, nextNode); + domNode = applyPatches(domNode, currNode, patches, eventNode); + currNode = nextNode; + + return; + + case 'EXTRA_REQUEST': + state = 'NO_REQUEST'; + return; + } + } + + return function stepper(model) + { + if (state === 'NO_REQUEST') + { + rAF(updateIfNeeded); + } + state = 'PENDING_REQUEST'; + nextModel = model; + }; +} + + +// DEBUG SETUP + +function debugSetup(impl, object, moduleName, flagChecker) +{ + object['fullscreen'] = function fullscreen(flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, document.body, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; + + object['embed'] = function fullscreen(node, flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, node, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; +} + +function scrollTask(popoutRef) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var doc = popoutRef.doc; + if (doc) + { + var msgs = doc.getElementsByClassName('debugger-sidebar-messages')[0]; + if (msgs) + { + msgs.scrollTop = msgs.scrollHeight; + } + } + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + + +function debugRenderer(moduleName, parentNode, popoutRef, view, viewIn, viewOut) +{ + return function(tagger, initialModel) + { + var appEventNode = { tagger: tagger, parent: undefined }; + var eventNode = { tagger: tagger, parent: undefined }; + + // make normal stepper + var appVirtualNode = view(initialModel); + var appNode = render(appVirtualNode, appEventNode); + parentNode.appendChild(appNode); + var appStepper = makeStepper(appNode, view, appVirtualNode, appEventNode); + + // make overlay stepper + var overVirtualNode = viewIn(initialModel)._1; + var overNode = render(overVirtualNode, eventNode); + parentNode.appendChild(overNode); + var wrappedViewIn = wrapViewIn(appEventNode, overNode, viewIn); + var overStepper = makeStepper(overNode, wrappedViewIn, overVirtualNode, eventNode); + + // make debugger stepper + var debugStepper = makeDebugStepper(initialModel, viewOut, eventNode, parentNode, moduleName, popoutRef); + + return function stepper(model) + { + appStepper(model); + overStepper(model); + debugStepper(model); + } + }; +} + +function makeDebugStepper(initialModel, view, eventNode, parentNode, moduleName, popoutRef) +{ + var curr; + var domNode; + + return function stepper(model) + { + if (!model.isDebuggerOpen) + { + return; + } + + if (!popoutRef.doc) + { + curr = view(model); + domNode = openDebugWindow(moduleName, popoutRef, curr, eventNode); + return; + } + + // switch to document of popout + localDoc = popoutRef.doc; + + var next = view(model); + var patches = diff(curr, next); + domNode = applyPatches(domNode, curr, patches, eventNode); + curr = next; + + // switch back to normal document + localDoc = document; + }; +} + +function openDebugWindow(moduleName, popoutRef, virtualNode, eventNode) +{ + var w = 900; + var h = 360; + var x = screen.width - w; + var y = screen.height - h; + var debugWindow = window.open('', '', 'width=' + w + ',height=' + h + ',left=' + x + ',top=' + y); + + // switch to window document + localDoc = debugWindow.document; + + popoutRef.doc = localDoc; + localDoc.title = 'Debugger - ' + moduleName; + localDoc.body.style.margin = '0'; + localDoc.body.style.padding = '0'; + var domNode = render(virtualNode, eventNode); + localDoc.body.appendChild(domNode); + + localDoc.addEventListener('keydown', function(event) { + if (event.metaKey && event.which === 82) + { + window.location.reload(); + } + if (event.which === 38) + { + eventNode.tagger({ ctor: 'Up' }); + event.preventDefault(); + } + if (event.which === 40) + { + eventNode.tagger({ ctor: 'Down' }); + event.preventDefault(); + } + }); + + function close() + { + popoutRef.doc = undefined; + debugWindow.close(); + } + window.addEventListener('unload', close); + debugWindow.addEventListener('unload', function() { + popoutRef.doc = undefined; + window.removeEventListener('unload', close); + eventNode.tagger({ ctor: 'Close' }); + }); + + // switch back to the normal document + localDoc = document; + + return domNode; +} + + +// BLOCK EVENTS + +function wrapViewIn(appEventNode, overlayNode, viewIn) +{ + var ignorer = makeIgnorer(overlayNode); + var blocking = 'Normal'; + var overflow; + + var normalTagger = appEventNode.tagger; + var blockTagger = function() {}; + + return function(model) + { + var tuple = viewIn(model); + var newBlocking = tuple._0.ctor; + appEventNode.tagger = newBlocking === 'Normal' ? normalTagger : blockTagger; + if (blocking !== newBlocking) + { + traverse('removeEventListener', ignorer, blocking); + traverse('addEventListener', ignorer, newBlocking); + + if (blocking === 'Normal') + { + overflow = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + } + + if (newBlocking === 'Normal') + { + document.body.style.overflow = overflow; + } + + blocking = newBlocking; + } + return tuple._1; + } +} + +function traverse(verbEventListener, ignorer, blocking) +{ + switch(blocking) + { + case 'Normal': + return; + + case 'Pause': + return traverseHelp(verbEventListener, ignorer, mostEvents); + + case 'Message': + return traverseHelp(verbEventListener, ignorer, allEvents); + } +} + +function traverseHelp(verbEventListener, handler, eventNames) +{ + for (var i = 0; i < eventNames.length; i++) + { + document.body[verbEventListener](eventNames[i], handler, true); + } +} + +function makeIgnorer(overlayNode) +{ + return function(event) + { + if (event.type === 'keydown' && event.metaKey && event.which === 82) + { + return; + } + + var isScroll = event.type === 'scroll' || event.type === 'wheel'; + + var node = event.target; + while (node !== null) + { + if (node.className === 'elm-overlay-message-details' && isScroll) + { + return; + } + + if (node === overlayNode && !isScroll) + { + return; + } + node = node.parentNode; + } + + event.stopPropagation(); + event.preventDefault(); + } +} + +var mostEvents = [ + 'click', 'dblclick', 'mousemove', + 'mouseup', 'mousedown', 'mouseenter', 'mouseleave', + 'touchstart', 'touchend', 'touchcancel', 'touchmove', + 'pointerdown', 'pointerup', 'pointerover', 'pointerout', + 'pointerenter', 'pointerleave', 'pointermove', 'pointercancel', + 'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave', 'drop', + 'keyup', 'keydown', 'keypress', + 'input', 'change', + 'focus', 'blur' +]; + +var allEvents = mostEvents.concat('wheel', 'scroll'); + + +return { + node: node, + text: text, + custom: custom, + map: F2(map), + + on: F3(on), + style: style, + property: F2(property), + attribute: F2(attribute), + attributeNS: F3(attributeNS), + mapProperty: F2(mapProperty), + + lazy: F2(lazy), + lazy2: F3(lazy2), + lazy3: F4(lazy3), + keyedNode: F3(keyedNode), + + program: program, + programWithFlags: programWithFlags, + staticProgram: staticProgram +}; + +}(); diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm new file mode 100644 index 0000000..ac28926 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm @@ -0,0 +1,331 @@ +module VirtualDom exposing + ( Node + , text, node + , Property, property, attribute, attributeNS, mapProperty + , style + , on, onWithOptions, Options, defaultOptions + , map + , lazy, lazy2, lazy3 + , keyedNode + , program, programWithFlags + ) + +{-| API to the core diffing algorithm. Can serve as a foundation for libraries +that expose more helper functions for HTML or SVG. + +# Create +@docs Node, text, node + +# Declare Properties and Attributes +@docs Property, property, attribute, attributeNS, mapProperty + +# Styles +@docs style + +# Events +@docs on, onWithOptions, Options, defaultOptions + +# Routing Messages +@docs map + +# Optimizations +@docs lazy, lazy2, lazy3, keyedNode + +# Programs +@docs program, programWithFlags + +-} + +import Json.Decode as Json +import Native.VirtualDom +import VirtualDom.Debug as Debug + + +{-| An immutable chunk of data representing a DOM node. This can be HTML or SVG. +-} +type Node msg = Node + + +{-| Create a DOM node with a tag name, a list of HTML properties that can +include styles and event listeners, a list of CSS properties like `color`, and +a list of child nodes. + + import Json.Encode as Json + + hello : Node msg + hello = + node "div" [] [ text "Hello!" ] + + greeting : Node msg + greeting = + node "div" + [ property "id" (Json.string "greeting") ] + [ text "Hello!" ] +-} +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Node msg +text = + Native.VirtualDom.text + + +{-| This function is useful when nesting components with [the Elm +Architecture](https://github.com/evancz/elm-architecture-tutorial/). It lets +you transform the messages produced by a subtree. + +Say you have a node named `button` that produces `()` values when it is +clicked. To get your model updating properly, you will probably want to tag +this `()` value like this: + + type Msg = Click | ... + + update msg model = + case msg of + Click -> + ... + + view model = + map (\_ -> Click) button + +So now all the events produced by `button` will be transformed to be of type +`Msg` so they can be handled by your update function! +-} +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + + +-- PROPERTIES + + +{-| When using HTML and JS, there are two ways to specify parts of a DOM node. + + 1. Attributes — You can set things in HTML itself. So the `class` + in `
` is called an *attribute*. + + 2. Properties — You can also set things in JS. So the `className` + in `div.className = 'greeting'` is called a *property*. + +So the `class` attribute corresponds to the `className` property. At first +glance, perhaps this distinction is defensible, but it gets much crazier. +*There is not always a one-to-one mapping between attributes and properties!* +Yes, that is a true fact. Sometimes an attribute exists, but there is no +corresponding property. Sometimes changing an attribute does not change the +underlying property. For example, as of this writing, the `webkit-playsinline` +attribute can be used in HTML, but there is no corresponding property! +-} +type Property msg = Property + + +{-| Create arbitrary *properties*. + + import JavaScript.Encode as Json + + greeting : Html + greeting = + node "div" [ property "className" (Json.string "greeting") ] [ + text "Hello!" + ] + +Notice that you must give the *property* name, so we use `className` as it +would be in JavaScript, not `class` as it would appear in HTML. +-} +property : String -> Json.Value -> Property msg +property = + Native.VirtualDom.property + + +{-| Create arbitrary HTML *attributes*. Maps onto JavaScript’s `setAttribute` +function under the hood. + + greeting : Html + greeting = + node "div" [ attribute "class" "greeting" ] [ + text "Hello!" + ] + +Notice that you must give the *attribute* name, so we use `class` as it would +be in HTML, not `className` as it would appear in JS. +-} +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +{-| Would you believe that there is another way to do this?! This corresponds +to JavaScript's `setAttributeNS` function under the hood. It is doing pretty +much the same thing as `attribute` but you are able to have "namespaced" +attributes. This is used in some SVG stuff at least. +-} +attributeNS : String -> String -> String -> Property msg +attributeNS = + Native.VirtualDom.attributeNS + + +{-| Transform the messages produced by a `Property`. +-} +mapProperty : (a -> b) -> Property a -> Property b +mapProperty = + Native.VirtualDom.mapProperty + + +{-| Specify a list of styles. + + myStyle : Property msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Node msg + greeting = + node "div" [ myStyle ] [ text "Hello!" ] + +-} +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + + +-- EVENTS + + +{-| Create a custom event listener. + + import Json.Decode as Json + + onClick : msg -> Property msg + onClick msg = + on "click" (Json.succeed msg) + +You first specify the name of the event in the same format as with JavaScript’s +`addEventListener`. Next you give a JSON decoder, which lets you pull +information out of the event object. If the decoder succeeds, it will produce +a message and route it to your `update` function. +-} +on : String -> Json.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + + +-- OPTIMIZATION + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +{-| Works just like `node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + + + +-- PROGRAMS + + +{-| Check out the docs for [`Html.App.program`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#program +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program Never model msg +program impl = + Native.VirtualDom.program Debug.wrap impl + + +{-| Check out the docs for [`Html.App.programWithFlags`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#programWithFlags +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program flags model msg +programWithFlags impl = + Native.VirtualDom.programWithFlags Debug.wrapWithFlags impl + diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm new file mode 100644 index 0000000..ba7afe5 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm @@ -0,0 +1,567 @@ +module VirtualDom.Debug exposing (wrap, wrapWithFlags) + +import Json.Decode as Decode +import Json.Encode as Encode +import Task exposing (Task) +import Native.Debug +import Native.VirtualDom +import VirtualDom.Expando as Expando exposing (Expando) +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.History as History exposing (History) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Overlay as Overlay +import VirtualDom.Report as Report + + + +-- WRAP PROGRAMS + + +wrap metadata { init, update, subscriptions, view } = + { init = wrapInit metadata init + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + +wrapWithFlags metadata { init, update, subscriptions, view } = + { init = \flags -> wrapInit metadata (init flags) + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + + +-- MODEL + + +type alias Model model msg = + { history : History model msg + , state : State model + , expando : Expando + , metadata : Result Metadata.Error Metadata + , overlay : Overlay.State + , isDebuggerOpen : Bool + } + + +type State model + = Running model + | Paused Int model model + + +wrapInit : Encode.Value -> ( model, Cmd msg ) -> ( Model model msg, Cmd (Msg msg) ) +wrapInit metadata ( userModel, userCommands ) = + { history = History.empty userModel + , state = Running userModel + , expando = Expando.init userModel + , metadata = Metadata.decode metadata + , overlay = Overlay.none + , isDebuggerOpen = False + } + ! [ Cmd.map UserMsg userCommands ] + + + +-- UPDATE + + +type Msg msg + = NoOp + | UserMsg msg + | ExpandoMsg Expando.Msg + | Resume + | Jump Int + | Open + | Close + | Up + | Down + | Import + | Export + | Upload String + | OverlayMsg Overlay.Msg + + +type alias UserUpdate model msg = + msg -> model -> ( model, Cmd msg ) + + +wrapUpdate + : UserUpdate model msg + -> Task Never () + -> Msg msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +wrapUpdate userUpdate scrollTask msg model = + case msg of + NoOp -> + model ! [] + + UserMsg userMsg -> + updateUserMsg userUpdate scrollTask userMsg model + + ExpandoMsg eMsg -> + { model + | expando = Expando.update eMsg model.expando + } + ! [] + + Resume -> + case model.state of + Running _ -> + model ! [] + + Paused _ _ userModel -> + { model + | state = Running userModel + , expando = Expando.merge userModel model.expando + } + ! [ runIf model.isDebuggerOpen scrollTask ] + + Jump index -> + let + (indexModel, indexMsg) = + History.get userUpdate index model.history + in + { model + | state = Paused index indexModel (getLatestModel model.state) + , expando = Expando.merge indexModel model.expando + } + ! [] + + Open -> + { model | isDebuggerOpen = True } ! [] + + Close -> + { model | isDebuggerOpen = False } ! [] + + Up -> + let + index = + case model.state of + Paused index _ _ -> + index + + Running _ -> + History.size model.history + in + if index > 0 then + wrapUpdate userUpdate scrollTask (Jump (index - 1)) model + else + model ! [] + + Down -> + case model.state of + Running _ -> + model ! [] + + Paused index _ userModel -> + if index == History.size model.history - 1 then + wrapUpdate userUpdate scrollTask Resume model + else + wrapUpdate userUpdate scrollTask (Jump (index + 1)) model + + Import -> + withGoodMetadata model <| \_ -> + model ! [ upload ] + + Export -> + withGoodMetadata model <| \metadata -> + model ! [ download metadata model.history ] + + Upload jsonString -> + withGoodMetadata model <| \metadata -> + case Overlay.assessImport metadata jsonString of + Err newOverlay -> + { model | overlay = newOverlay } ! [] + + Ok rawHistory -> + loadNewHistory rawHistory userUpdate model + + OverlayMsg overlayMsg -> + case Overlay.close overlayMsg model.overlay of + Nothing -> + { model | overlay = Overlay.none } ! [] + + Just rawHistory -> + loadNewHistory rawHistory userUpdate model + + + +-- COMMANDS + + +upload : Cmd (Msg msg) +upload = + Task.perform Upload Native.Debug.upload + + +download : Metadata -> History model msg -> Cmd (Msg msg) +download metadata history = + let + historyLength = + History.size history + + json = + Encode.object + [ ("metadata", Metadata.encode metadata) + , ("history", History.encode history) + ] + in + Task.perform (\_ -> NoOp) (Native.Debug.download historyLength json) + + + +-- UPDATE OVERLAY + + +withGoodMetadata + : Model model msg + -> (Metadata -> (Model model msg, Cmd (Msg msg))) + -> (Model model msg, Cmd (Msg msg)) +withGoodMetadata model func = + case model.metadata of + Ok metadata -> + func metadata + + Err error -> + { model | overlay = Overlay.badMetadata error } ! [] + + +loadNewHistory + : Encode.Value + -> UserUpdate model msg + -> Model model msg + -> ( Model model msg, Cmd (Msg msg) ) +loadNewHistory rawHistory userUpdate model = + let + initialUserModel = + History.initialModel model.history + + pureUserUpdate msg userModel = + Tuple.first (userUpdate msg userModel) + + decoder = + History.decoder initialUserModel pureUserUpdate + in + case Decode.decodeValue decoder rawHistory of + Err _ -> + { model | overlay = Overlay.corruptImport } ! [] + + Ok (latestUserModel, newHistory) -> + { model + | history = newHistory + , state = Running latestUserModel + , expando = Expando.init latestUserModel + , overlay = Overlay.none + } + ! [] + + + +-- UPDATE - USER MESSAGES + + +updateUserMsg + : UserUpdate model msg + -> Task Never () + -> msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +updateUserMsg userUpdate scrollTask userMsg ({ history, state, expando } as model) = + let + userModel = + getLatestModel state + + newHistory = + History.add userMsg userModel history + + (newUserModel, userCmds) = + userUpdate userMsg userModel + + commands = + Cmd.map UserMsg userCmds + in + case state of + Running _ -> + { model + | history = newHistory + , state = Running newUserModel + , expando = Expando.merge newUserModel expando + } + ! [ commands, runIf model.isDebuggerOpen scrollTask ] + + Paused index indexModel _ -> + { model + | history = newHistory + , state = Paused index indexModel newUserModel + } + ! [ commands ] + + +runIf : Bool -> Task Never () -> Cmd (Msg msg) +runIf bool task = + if bool then + Task.perform (always NoOp) task + else + Cmd.none + + +getLatestModel : State model -> model +getLatestModel state = + case state of + Running model -> + model + + Paused _ _ model -> + model + + + +-- SUBSCRIPTIONS + + +wrapSubs : (model -> Sub msg) -> Model model msg -> Sub (Msg msg) +wrapSubs userSubscriptions {state} = + getLatestModel state + |> userSubscriptions + |> Sub.map UserMsg + + + +-- VIEW + + +wrapView : (model -> Node msg) -> Model model msg -> Node (Msg msg) +wrapView userView { state } = + let + currentModel = + case state of + Running model -> + model + + Paused _ oldModel _ -> + oldModel + in + VDom.map UserMsg (userView currentModel) + + + +-- SMALL DEBUG VIEW + + +viewIn : Model model msg -> ( Overlay.Block, Node (Msg msg) ) +viewIn { history, state, overlay, isDebuggerOpen } = + let + isPaused = + case state of + Running _ -> + False + + Paused _ _ _ -> + True + in + Overlay.view overlayConfig isPaused isDebuggerOpen (History.size history) overlay + + +overlayConfig : Overlay.Config (Msg msg) +overlayConfig = + { resume = Resume + , open = Open + , importHistory = Import + , exportHistory = Export + , wrap = OverlayMsg + } + + + +-- BIG DEBUG VIEW + + +viewOut : Model model msg -> Node (Msg msg) +viewOut { history, state, expando } = + VDom.div + [ VDom.id "debugger" ] + [ styles + , viewSidebar state history + , VDom.map ExpandoMsg <| + VDom.div [ VDom.id "values" ] [ Expando.view Nothing expando ] + ] + + +viewSidebar : State model -> History model msg -> Node (Msg msg) +viewSidebar state history = + let + maybeIndex = + case state of + Running _ -> + Nothing + + Paused index _ _ -> + Just index + in + VDom.div [ VDom.class "debugger-sidebar" ] + [ VDom.map Jump (History.view maybeIndex history) + , playButton maybeIndex + ] + + +playButton : Maybe Int -> Node (Msg msg) +playButton maybeIndex = + VDom.div [ VDom.class "debugger-sidebar-controls" ] + [ viewResumeButton maybeIndex + , VDom.div [ VDom.class "debugger-sidebar-controls-import-export" ] + [ button Import "Import" + , VDom.text " / " + , button Export "Export" + ] + ] + + +button msg label = + VDom.span + [ VDom.onClick msg + , VDom.style [("cursor","pointer")] + ] + [ VDom.text label ] + + +viewResumeButton maybeIndex = + case maybeIndex of + Nothing -> + VDom.text "" + + Just _ -> + resumeButton + + +resumeButton = + VDom.div + [ VDom.onClick Resume + , VDom.class "debugger-sidebar-controls-resume" + ] + [ VDom.text "Resume" + ] + + + +-- STYLE + + +styles : Node msg +styles = + VDom.node "style" [] [ VDom.text """ + +html { + overflow: hidden; + height: 100%; +} + +body { + height: 100%; + overflow: auto; +} + +#debugger { + width: 100% + height: 100%; + font-family: monospace; +} + +#values { + display: block; + float: left; + height: 100%; + width: calc(100% - 30ch); + margin: 0; + overflow: auto; + cursor: default; +} + +.debugger-sidebar { + display: block; + float: left; + width: 30ch; + height: 100%; + color: white; + background-color: rgb(61, 61, 61); +} + +.debugger-sidebar-controls { + width: 100%; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.debugger-sidebar-controls-import-export { + width: 100%; + height: 24px; + line-height: 24px; + font-size: 12px; +} + +.debugger-sidebar-controls-resume { + width: 100%; + height: 30px; + line-height: 30px; + cursor: pointer; +} + +.debugger-sidebar-controls-resume:hover { + background-color: rgb(41, 41, 41); +} + +.debugger-sidebar-messages { + width: 100%; + overflow-y: auto; + height: calc(100% - 24px); +} + +.debugger-sidebar-messages-paused { + width: 100%; + overflow-y: auto; + height: calc(100% - 54px); +} + +.messages-entry { + cursor: pointer; + width: 100%; +} + +.messages-entry:hover { + background-color: rgb(41, 41, 41); +} + +.messages-entry-selected, .messages-entry-selected:hover { + background-color: rgb(10, 10, 10); +} + +.messages-entry-content { + width: calc(100% - 7ch); + padding-top: 4px; + padding-bottom: 4px; + padding-left: 1ch; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + display: inline-block; +} + +.messages-entry-index { + color: #666; + width: 5ch; + padding-top: 4px; + padding-bottom: 4px; + padding-right: 1ch; + text-align: right; + display: block; + float: right; +} + +""" ] diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm new file mode 100644 index 0000000..88b5857 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm @@ -0,0 +1,659 @@ +module VirtualDom.Expando exposing + ( Expando + , init + , merge + , Msg, update + , view + ) + + +import Dict exposing (Dict) +import Json.Decode as Json +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node, text, div, span, class, onClick) + + + +-- MODEL + + +type Expando + = S String + | Primitive String + | Sequence SeqType Bool (List Expando) + | Dictionary Bool (List (Expando, Expando)) + | Record Bool (Dict String Expando) + | Constructor (Maybe String) Bool (List Expando) + + +type SeqType = ListSeq | SetSeq | ArraySeq + + +seqTypeToString : Int -> SeqType -> String +seqTypeToString n seqType = + case seqType of + ListSeq -> + "List(" ++ toString n ++ ")" + + SetSeq -> + "Set(" ++ toString n ++ ")" + + ArraySeq -> + "Array(" ++ toString n ++ ")" + + + +-- INITIALIZE + + +init : a -> Expando +init value = + initHelp True (Native.Debug.init value) + + +initHelp : Bool -> Expando -> Expando +initHelp isOuter expando = + case expando of + S _ -> + expando + + Primitive _ -> + expando + + Sequence seqType isClosed items -> + if isOuter then + Sequence seqType False (List.map (initHelp False) items) + else if List.length items <= 8 then + Sequence seqType False items + else + expando + + Dictionary isClosed keyValuePairs -> + if isOuter then + Dictionary False (List.map (\(k,v) -> (k, initHelp False v)) keyValuePairs) + else if List.length keyValuePairs <= 8 then + Dictionary False keyValuePairs + else + expando + + Record isClosed entries -> + if isOuter then + Record False (Dict.map (\_ v -> initHelp False v) entries) + else if Dict.size entries <= 4 then + Record False entries + else + expando + + Constructor maybeName isClosed args -> + if isOuter then + Constructor maybeName False (List.map (initHelp False) args) + else if List.length args <= 4 then + Constructor maybeName False args + else + expando + + + +-- PRESERVE OLD EXPANDO STATE (open/closed) + + +merge : a -> Expando -> Expando +merge value expando = + mergeHelp expando (Native.Debug.init value) + + +mergeHelp : Expando -> Expando -> Expando +mergeHelp old new = + case ( old, new ) of + ( _, S _ ) -> + new + + ( _, Primitive _ ) -> + new + + ( Sequence _ isClosed oldValues, Sequence seqType _ newValues ) -> + Sequence seqType isClosed (mergeListHelp oldValues newValues) + + ( Dictionary isClosed _, Dictionary _ keyValuePairs ) -> + Dictionary isClosed keyValuePairs + + ( Record isClosed oldDict, Record _ newDict ) -> + Record isClosed <| Dict.map (mergeDictHelp oldDict) newDict + + ( Constructor _ isClosed oldValues, Constructor maybeName _ newValues ) -> + Constructor maybeName isClosed (mergeListHelp oldValues newValues) + + _ -> + new + + +mergeListHelp : List Expando -> List Expando -> List Expando +mergeListHelp olds news = + case (olds, news) of + ( [], _ ) -> + news + + ( _, [] ) -> + news + + ( x :: xs, y :: ys ) -> + mergeHelp x y :: mergeListHelp xs ys + + +mergeDictHelp : Dict String Expando -> String -> Expando -> Expando +mergeDictHelp oldDict key value = + case Dict.get key oldDict of + Nothing -> + value + + Just oldValue -> + mergeHelp oldValue value + + + +-- UPDATE + + +type Msg + = Toggle + | Index Redirect Int Msg + | Field String Msg + + +type Redirect = None | Key | Value + + +update : Msg -> Expando -> Expando +update msg value = + case value of + S _ -> + Debug.crash "No messages for primitives" + + Primitive _ -> + Debug.crash "No messages for primitives" + + Sequence seqType isClosed valueList -> + case msg of + Toggle -> + Sequence seqType (not isClosed) valueList + + Index None index subMsg -> + Sequence seqType isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field on sequences" + + Dictionary isClosed keyValuePairs -> + case msg of + Toggle -> + Dictionary (not isClosed) keyValuePairs + + Index redirect index subMsg -> + case redirect of + None -> + Debug.crash "must have redirect for dictionaries" + + Key -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (update subMsg k, v)) keyValuePairs + + Value -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (k, update subMsg v)) keyValuePairs + + Field _ _ -> + Debug.crash "no field for dictionaries" + + Record isClosed valueDict -> + case msg of + Toggle -> + Record (not isClosed) valueDict + + Index _ _ _ -> + Debug.crash "No index for records" + + Field field subMsg -> + Record isClosed (Dict.update field (updateField subMsg) valueDict) + + Constructor maybeName isClosed valueList -> + case msg of + Toggle -> + Constructor maybeName (not isClosed) valueList + + Index None index subMsg -> + Constructor maybeName isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field for constructors" + + +updateIndex : Int -> (a -> a) -> List a -> List a +updateIndex n func list = + case list of + [] -> + [] + + x :: xs -> + if n <= 0 then + func x :: xs + else + x :: updateIndex (n-1) func xs + + +updateField : Msg -> Maybe Expando -> Maybe Expando +updateField msg maybeExpando = + case maybeExpando of + Nothing -> + Debug.crash "key does not exist" + + Just expando -> + Just (update msg expando) + + + +-- VIEW + + +view : Maybe String -> Expando -> Node Msg +view maybeKey expando = + case expando of + S stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [red] [text stringRep]]) + + Primitive stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [blue] [text stringRep]]) + + Sequence seqType isClosed valueList -> + viewSequence maybeKey seqType isClosed valueList + + Dictionary isClosed keyValuePairs -> + viewDictionary maybeKey isClosed keyValuePairs + + Record isClosed valueDict -> + viewRecord maybeKey isClosed valueDict + + Constructor maybeName isClosed valueList -> + viewConstructor maybeKey maybeName isClosed valueList + + + +-- VIEW SEQUENCE + + +viewSequence : Maybe String -> SeqType -> Bool -> List Expando -> Node Msg +viewSequence maybeKey seqType isClosed valueList = + let + starter = + seqTypeToString (List.length valueList) seqType + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewSequenceOpen valueList + ] + + +viewSequenceOpen : List Expando -> Node Msg +viewSequenceOpen values = + div [] (List.indexedMap viewConstructorEntry values) + + + +-- VIEW DICTIONARY + + +viewDictionary : Maybe String -> Bool -> List (Expando, Expando) -> Node Msg +viewDictionary maybeKey isClosed keyValuePairs = + let + starter = + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewDictionaryOpen keyValuePairs + ] + + +viewDictionaryOpen : List (Expando, Expando) -> Node Msg +viewDictionaryOpen keyValuePairs = + div [] (List.indexedMap viewDictionaryEntry keyValuePairs) + + +viewDictionaryEntry : Int -> (Expando, Expando) -> Node Msg +viewDictionaryEntry index (key, value) = + case key of + S stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + Primitive stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + _ -> + div [] + [ VDom.map (Index Key index) (view (Just "key") key) + , VDom.map (Index Value index) (view (Just "value") value) + ] + + + +-- VIEW RECORD + + +viewRecord : Maybe String -> Bool -> Dict String Expando -> Node Msg +viewRecord maybeKey isClosed record = + let + (start, middle, end) = + if isClosed then + ( Tuple.second (viewTinyRecord record), text "", text "" ) + else + ( [ text "{" ], viewRecordOpen record, div [leftPad (Just ())] [text "}"] ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) start) + , middle + , end + ] + + +viewRecordOpen : Dict String Expando -> Node Msg +viewRecordOpen record = + div [] (List.map viewRecordEntry (Dict.toList record)) + + +viewRecordEntry : (String, Expando) -> Node Msg +viewRecordEntry (field, value) = + VDom.map (Field field) (view (Just field) value) + + + +-- VIEW CONSTRUCTOR + + +viewConstructor : Maybe String -> Maybe String -> Bool -> List Expando -> Node Msg +viewConstructor maybeKey maybeName isClosed valueList = + let + tinyArgs = + List.map (Tuple.second << viewExtraTiny) valueList + + description = + case (maybeName, tinyArgs) of + (Nothing, []) -> + [ text "()" ] + + (Nothing, x :: xs) -> + text "( " + :: span [] x + :: List.foldr (\args rest -> text ", " :: span [] args :: rest) [text " )"] xs + + (Just name, []) -> + [ text name ] + + (Just name, x :: xs) -> + text (name ++ " ") + :: span [] x + :: List.foldr (\args rest -> text " " :: span [] args :: rest) [] xs + + (maybeIsClosed, openHtml) = + case valueList of + [] -> + ( Nothing, div [] [] ) + + [entry] -> + case entry of + S _ -> + ( Nothing, div [] [] ) + + Primitive _ -> + ( Nothing, div [] [] ) + + Sequence _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewSequenceOpen subValueList) + ) + + Dictionary _ keyValuePairs -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewDictionaryOpen keyValuePairs) + ) + + Record _ record -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewRecordOpen record) + ) + + Constructor _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewConstructorOpen subValueList) + ) + + _ -> + ( Just isClosed + , if isClosed then div [] [] else viewConstructorOpen valueList + ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey maybeIsClosed description) + , openHtml + ] + + +viewConstructorOpen : List Expando -> Node Msg +viewConstructorOpen valueList = + div [] (List.indexedMap viewConstructorEntry valueList) + + +viewConstructorEntry : Int -> Expando -> Node Msg +viewConstructorEntry index value = + VDom.map (Index None index) (view (Just (toString index)) value) + + + +-- VIEW TINY + + +viewTiny : Expando -> ( Int, List (Node msg) ) +viewTiny value = + case value of + S stringRep -> + let + str = + elideMiddle stringRep + in + ( String.length str + , [ span [red] [text str] ] + ) + + Primitive stringRep -> + ( String.length stringRep + , [ span [blue] [text stringRep] ] + ) + + Sequence seqType _ valueList -> + viewTinyHelp <| + seqTypeToString (List.length valueList) seqType + + Dictionary _ keyValuePairs -> + viewTinyHelp <| + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + + Record _ record -> + viewTinyRecord record + + Constructor maybeName _ [] -> + viewTinyHelp <| + Maybe.withDefault "Unit" maybeName + + Constructor maybeName _ valueList -> + viewTinyHelp <| + case maybeName of + Nothing -> + "Tuple(" ++ toString (List.length valueList) ++ ")" + + Just name -> + name ++ " …" + + +viewTinyHelp : String -> ( Int, List (Node msg) ) +viewTinyHelp str = + ( String.length str, [text str] ) + + +elideMiddle : String -> String +elideMiddle str = + if String.length str <= 18 then + str + + else + String.left 8 str ++ "..." ++ String.right 8 str + + + +-- VIEW TINY RECORDS + + +viewTinyRecord : Dict String Expando -> ( Int, List (Node msg) ) +viewTinyRecord record = + if Dict.isEmpty record then + ( 2, [text "{}"] ) + + else + viewTinyRecordHelp 0 "{ " (Dict.toList record) + + +viewTinyRecordHelp : Int -> String -> List (String, Expando) -> ( Int, List (Node msg) ) +viewTinyRecordHelp length starter entries = + case entries of + [] -> + ( length + 2, [ text " }" ] ) + + (field, value) :: rest -> + let + fieldLen = + String.length field + + (valueLen, valueNodes) = + viewExtraTiny value + + newLength = + length + fieldLen + valueLen + 5 + in + if newLength > 60 then + ( length + 4, [text ", … }"] ) + + else + let + ( finalLength, otherNodes ) = + viewTinyRecordHelp newLength ", " rest + in + ( finalLength + , text starter + :: span [purple] [text field] + :: text " = " + :: span [] valueNodes + :: otherNodes + ) + + +viewExtraTiny : Expando -> ( Int, List (Node msg) ) +viewExtraTiny value = + case value of + Record _ record -> + viewExtraTinyRecord 0 "{" (Dict.keys record) + + _ -> + viewTiny value + + +viewExtraTinyRecord : Int -> String -> List String -> ( Int, List (Node msg) ) +viewExtraTinyRecord length starter entries = + case entries of + [] -> + ( length + 1, [text "}"] ) + + field :: rest -> + let + nextLength = + length + String.length field + 1 + in + if nextLength > 18 then + ( length + 2, [text "…}"]) + + else + let + (finalLength, otherNodes) = + viewExtraTinyRecord nextLength "," rest + in + ( finalLength + , text starter :: span [purple] [text field] :: otherNodes + ) + + + +-- VIEW HELPERS + + +lineStarter : Maybe String -> Maybe Bool -> List (Node msg) -> List (Node msg) +lineStarter maybeKey maybeIsClosed description = + let + arrow = + case maybeIsClosed of + Nothing -> + makeArrow "" + + Just True -> + makeArrow "▸" + + Just False -> + makeArrow "▾" + in + case maybeKey of + Nothing -> + arrow :: description + + Just key -> + arrow :: span [purple] [text key] :: text " = " :: description + + +makeArrow : String -> Node msg +makeArrow arrow = + span + [ VDom.style + [ ("color", "#777") + , ("padding-left", "2ch") + , ("width", "2ch") + , ("display", "inline-block") + ] + ] + [ text arrow ] + + +leftPad : Maybe a -> VDom.Property msg +leftPad maybeKey = + case maybeKey of + Nothing -> + VDom.style [] + + Just _ -> + VDom.style [("padding-left", "4ch")] + + +red : VDom.Property msg +red = + VDom.style [("color", "rgb(196, 26, 22)")] + + +blue : VDom.Property msg +blue = + VDom.style [("color", "rgb(28, 0, 207)")] + + +purple : VDom.Property msg +purple = + VDom.style [("color", "rgb(136, 19, 145)")] diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm new file mode 100644 index 0000000..104e23b --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm @@ -0,0 +1,137 @@ +module VirtualDom.Helpers exposing + ( Node + , text, node, div, span, a, h1 + , Property, property, attribute + , class, id, href + , style + , on, onWithOptions, Options, defaultOptions + , onClick + , map + , lazy, lazy2, lazy3 + , keyedNode + ) + + +import Json.Decode as Decode +import Json.Encode as Encode +import Native.VirtualDom + + +type Node msg = Node + + +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +text : String -> Node msg +text = + Native.VirtualDom.text + + +div : List (Property msg) -> List (Node msg) -> Node msg +div = + node "div" + + +span : List (Property msg) -> List (Node msg) -> Node msg +span = + node "span" + + +a : List (Property msg) -> List (Node msg) -> Node msg +a = + node "a" + + +h1 : List (Property msg) -> List (Node msg) -> Node msg +h1 = + node "h1" + + +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + +type Property msg = Property + + +property : String -> Decode.Value -> Property msg +property = + Native.VirtualDom.property + + +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +class : String -> Property msg +class name = + property "className" (Encode.string name) + + +href : String -> Property msg +href name = + property "href" (Encode.string name) + + +id : String -> Property msg +id = + attribute "id" + + +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + +on : String -> Decode.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +onClick : msg -> Property msg +onClick msg = + on "click" (Decode.succeed msg) + + +onWithOptions : String -> Options -> Decode.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm new file mode 100644 index 0000000..bd9a28d --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm @@ -0,0 +1,290 @@ +module VirtualDom.History exposing + ( History + , empty + , size + , initialModel + , add + , get + , view + , decoder + , encode + ) + + +import Array exposing (Array) +import Json.Decode as Decode +import Json.Encode as Encode +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.Metadata as Metadata + + + +-- CONSTANTS + + +maxSnapshotSize : Int +maxSnapshotSize = + 64 + + + +-- HISTORY + + +type alias History model msg = + { snapshots : Array (Snapshot model msg) + , recent : RecentHistory model msg + , numMessages : Int + } + + +type alias RecentHistory model msg = + { model : model + , messages : List msg + , numMessages : Int + } + + +type alias Snapshot model msg = + { model : model + , messages : Array msg + } + + +empty : model -> History model msg +empty model = + History Array.empty (RecentHistory model [] 0) 0 + + +size : History model msg -> Int +size history = + history.numMessages + + +initialModel : History model msg -> model +initialModel { snapshots, recent } = + case Array.get 0 snapshots of + Just { model } -> + model + + Nothing -> + recent.model + + + +-- JSON + + +decoder : model -> (msg -> model -> model) -> Decode.Decoder (model, History model msg) +decoder initialModel update = + let + addMessage rawMsg (model, history) = + let + msg = + jsToElm rawMsg + in + (update msg model, add msg model history) + + updateModel rawMsgs = + List.foldl addMessage (initialModel, empty initialModel) rawMsgs + in + Decode.map updateModel (Decode.list Decode.value) + + +jsToElm : Encode.Value -> a +jsToElm = + Native.Debug.unsafeCoerce + + +encode : History model msg -> Encode.Value +encode { snapshots, recent } = + let + recentJson = + List.map elmToJs (List.reverse recent.messages) + in + Encode.list <| Array.foldr encodeHelp recentJson snapshots + + +encodeHelp : Snapshot model msg -> List Encode.Value -> List Encode.Value +encodeHelp snapshot allMessages = + Array.foldl (\elm msgs -> elmToJs elm :: msgs) allMessages snapshot.messages + + +elmToJs : a -> Encode.Value +elmToJs = + Native.Debug.unsafeCoerce + + + +-- ADD MESSAGES + + +add : msg -> model -> History model msg -> History model msg +add msg model { snapshots, recent, numMessages } = + case addRecent msg model recent of + (Just snapshot, newRecent) -> + History (Array.push snapshot snapshots) newRecent (numMessages + 1) + + (Nothing, newRecent) -> + History snapshots newRecent (numMessages + 1) + + +addRecent + : msg + -> model + -> RecentHistory model msg + -> ( Maybe (Snapshot model msg), RecentHistory model msg ) +addRecent msg newModel { model, messages, numMessages } = + if numMessages == maxSnapshotSize then + ( Just (Snapshot model (Array.fromList messages)) + , RecentHistory newModel [msg] 1 + ) + + else + ( Nothing + , RecentHistory model (msg :: messages) (numMessages + 1) + ) + + + +-- GET SUMMARY + + +get : (msg -> model -> (model, a)) -> Int -> History model msg -> ( model, msg ) +get update index { snapshots, recent, numMessages } = + let + snapshotMax = + numMessages - recent.numMessages + in + if index >= snapshotMax then + undone <| + List.foldr (getHelp update) (Stepping (index - snapshotMax) recent.model) recent.messages + + else + case Array.get (index // maxSnapshotSize) snapshots of + Nothing -> + Debug.crash "UI should only let you ask for real indexes!" + + Just { model, messages } -> + undone <| + Array.foldr (getHelp update) (Stepping (rem index maxSnapshotSize) model) messages + + +type GetResult model msg + = Stepping Int model + | Done msg model + + +getHelp : (msg -> model -> (model, a)) -> msg -> GetResult model msg -> GetResult model msg +getHelp update msg getResult = + case getResult of + Done _ _ -> + getResult + + Stepping n model -> + if n == 0 then + Done msg (Tuple.first (update msg model)) + + else + Stepping (n - 1) (Tuple.first (update msg model)) + + +undone : GetResult model msg -> ( model, msg ) +undone getResult = + case getResult of + Done msg model -> + ( model, msg ) + + Stepping _ _ -> + Debug.crash "Bug in History.get" + + + +-- VIEW + + +view : Maybe Int -> History model msg -> Node Int +view maybeIndex { snapshots, recent, numMessages } = + let + (index, className) = + case maybeIndex of + Nothing -> + ( -1, "debugger-sidebar-messages" ) + Just i -> + ( i, "debugger-sidebar-messages-paused" ) + + oldStuff = + VDom.lazy2 viewSnapshots index snapshots + + newStuff = + Tuple.second <| List.foldl (consMsg index) (numMessages - 1, []) recent.messages + in + VDom.div [ VDom.class className ] (oldStuff :: newStuff) + + + +-- VIEW SNAPSHOTS + + +viewSnapshots : Int -> Array (Snapshot model msg) -> Node Int +viewSnapshots currentIndex snapshots = + let + highIndex = + maxSnapshotSize * Array.length snapshots + in + VDom.div [] <| Tuple.second <| + Array.foldr (consSnapshot currentIndex) (highIndex, []) snapshots + + +consSnapshot : Int -> Snapshot model msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consSnapshot currentIndex snapshot (index, rest) = + let + nextIndex = + index - maxSnapshotSize + + currentIndexHelp = + if nextIndex <= currentIndex && currentIndex < index then currentIndex else -1 + in + ( index - maxSnapshotSize + , VDom.lazy3 viewSnapshot currentIndexHelp index snapshot :: rest + ) + + +viewSnapshot : Int -> Int -> Snapshot model msg -> Node Int +viewSnapshot currentIndex index { messages } = + VDom.div [] <| Tuple.second <| + Array.foldl (consMsg currentIndex) (index - 1, []) messages + + + +-- VIEW MESSAGE + + +consMsg : Int -> msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consMsg currentIndex msg (index, rest) = + ( index - 1 + , VDom.lazy3 viewMessage currentIndex index msg :: rest + ) + + +viewMessage : Int -> Int -> msg -> Node Int +viewMessage currentIndex index msg = + let + className = + if currentIndex == index then + "messages-entry messages-entry-selected" + + else + "messages-entry" + + messageName = + Native.Debug.messageToString msg + in + VDom.div + [ VDom.class className + , VDom.on "click" (Decode.succeed index) + ] + [ VDom.span [VDom.class "messages-entry-content", VDom.attribute "title" messageName ] [ VDom.text messageName ] + , VDom.span [VDom.class "messages-entry-index"] [ VDom.text (toString index) ] + ] diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm new file mode 100644 index 0000000..74e7316 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm @@ -0,0 +1,326 @@ +module VirtualDom.Metadata exposing + ( Metadata + , check + , decode, decoder, encode + , Error, ProblemType, Problem(..) + ) + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Report as Report exposing (Report) + + + +-- METADATA + + +type alias Metadata = + { versions : Versions + , types : Types + } + + + +-- VERSIONS + + +type alias Versions = + { elm : String + } + + + +-- TYPES + + +type alias Types = + { message : String + , aliases : Dict String Alias + , unions : Dict String Union + } + + +type alias Alias = + { args : List String + , tipe : String + } + + +type alias Union = + { args : List String + , tags : Dict String (List String) + } + + + +-- PORTABILITY + + +isPortable : Metadata -> Maybe Error +isPortable {types} = + let + badAliases = + Dict.foldl collectBadAliases [] types.aliases + in + case Dict.foldl collectBadUnions badAliases types.unions of + [] -> + Nothing + + problems -> + Just (Error types.message problems) + + +type alias Error = + { message : String + , problems : List ProblemType + } + + +type alias ProblemType = + { name : String + , problems : List Problem + } + + +type Problem + = Function + | Decoder + | Task + | Process + | Socket + | Request + | Program + | VirtualDom + + +collectBadAliases : String -> Alias -> List ProblemType -> List ProblemType +collectBadAliases name {tipe} list = + case findProblems tipe of + [] -> + list + + problems -> + ProblemType name problems :: list + + +collectBadUnions : String -> Union -> List ProblemType -> List ProblemType +collectBadUnions name {tags} list = + case List.concatMap findProblems (List.concat (Dict.values tags)) of + [] -> + list + + problems -> + ProblemType name problems :: list + + +findProblems : String -> List Problem +findProblems tipe = + List.filterMap (hasProblem tipe) problemTable + + +hasProblem : String -> (Problem, String) -> Maybe Problem +hasProblem tipe (problem, token) = + if String.contains token tipe then Just problem else Nothing + + +problemTable : List (Problem, String) +problemTable = + [ ( Function, "->" ) + , ( Decoder, "Json.Decode.Decoder" ) + , ( Task, "Task.Task" ) + , ( Process, "Process.Id" ) + , ( Socket, "WebSocket.LowLevel.WebSocket" ) + , ( Request, "Http.Request" ) + , ( Program, "Platform.Program" ) + , ( VirtualDom, "VirtualDom.Node" ) + , ( VirtualDom, "VirtualDom.Attribute" ) + ] + + + +-- CHECK + + +check : Metadata -> Metadata -> Report +check old new = + if old.versions.elm /= new.versions.elm then + Report.VersionChanged old.versions.elm new.versions.elm + + else + checkTypes old.types new.types + + +checkTypes : Types -> Types -> Report +checkTypes old new = + if old.message /= new.message then + Report.MessageChanged old.message new.message + + else + [] + |> Dict.merge ignore checkAlias ignore old.aliases new.aliases + |> Dict.merge ignore checkUnion ignore old.unions new.unions + |> Report.SomethingChanged + + +ignore : String -> value -> a -> a +ignore key value report = + report + + + +-- CHECK ALIASES + + +checkAlias : String -> Alias -> Alias -> List Report.Change -> List Report.Change +checkAlias name old new changes = + if old.tipe == new.tipe && old.args == new.args then + changes + + else + Report.AliasChange name :: changes + + + +-- CHECK UNIONS + + +checkUnion : String -> Union -> Union -> List Report.Change -> List Report.Change +checkUnion name old new changes = + let + tagChanges = + Dict.merge removeTag checkTag addTag old.tags new.tags <| + Report.emptyTagChanges (old.args == new.args) + in + if Report.hasTagChanges tagChanges then + changes + + else + Report.UnionChange name tagChanges :: changes + + +removeTag : String -> a -> Report.TagChanges -> Report.TagChanges +removeTag tag _ changes = + { changes | removed = tag :: changes.removed } + + +addTag : String -> a -> Report.TagChanges -> Report.TagChanges +addTag tag _ changes = + { changes | added = tag :: changes.added } + + +checkTag : String -> a -> a -> Report.TagChanges -> Report.TagChanges +checkTag tag old new changes = + if old == new then + changes + + else + { changes | changed = tag :: changes.changed } + + + +-- JSON DECODE + + +decode : Encode.Value -> Result Error Metadata +decode value = + case Decode.decodeValue decoder value of + Err _ -> + Debug.crash "Compiler is generating bad metadata. Report this at ." + + Ok metadata -> + case isPortable metadata of + Nothing -> + Ok metadata + + Just error -> + Err error + + +decoder : Decode.Decoder Metadata +decoder = + Decode.map2 Metadata + (Decode.field "versions" decodeVersions) + (Decode.field "types" decodeTypes) + + +decodeVersions : Decode.Decoder Versions +decodeVersions = + Decode.map Versions + (Decode.field "elm" Decode.string) + + +decodeTypes : Decode.Decoder Types +decodeTypes = + Decode.map3 Types + (Decode.field "message" Decode.string) + (Decode.field "aliases" (Decode.dict decodeAlias)) + (Decode.field "unions" (Decode.dict decodeUnion)) + + +decodeUnion : Decode.Decoder Union +decodeUnion = + Decode.map2 Union + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "tags" (Decode.dict (Decode.list Decode.string))) + + +decodeAlias : Decode.Decoder Alias +decodeAlias = + Decode.map2 Alias + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "type" (Decode.string)) + + + +-- JSON ENCODE + + +encode : Metadata -> Encode.Value +encode { versions, types } = + Encode.object + [ ("versions", encodeVersions versions) + , ("types", encodeTypes types) + ] + + +encodeVersions : Versions -> Encode.Value +encodeVersions { elm } = + Encode.object [("elm", Encode.string elm)] + + +encodeTypes : Types -> Encode.Value +encodeTypes { message, unions, aliases } = + Encode.object + [ ("message", Encode.string message) + , ("aliases", encodeDict encodeAlias aliases) + , ("unions", encodeDict encodeUnion unions) + ] + + +encodeAlias : Alias -> Encode.Value +encodeAlias { args, tipe } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("type", Encode.string tipe) + ] + + +encodeUnion : Union -> Encode.Value +encodeUnion { args, tags } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("tags", encodeDict (Encode.list << List.map Encode.string) tags) + ] + + +encodeDict : (a -> Encode.Value) -> Dict String a -> Encode.Value +encodeDict f dict = + dict + |> Dict.map (\key value -> f value) + |> Dict.toList + |> Encode.object + + diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm new file mode 100644 index 0000000..9e6bd2e --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm @@ -0,0 +1,541 @@ +module VirtualDom.Overlay exposing + ( State, none, corruptImport, badMetadata + , Msg, close, assessImport + , isBlocking + , Config + , Block + , view + , viewImportExport + ) + +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Helpers exposing (..) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Report as Report exposing (Report) + + + +type State + = None + | BadMetadata Metadata.Error + | BadImport Report + | RiskyImport Report Encode.Value + + +none : State +none = + None + + +corruptImport : State +corruptImport = + BadImport Report.CorruptHistory + + +badMetadata : Metadata.Error -> State +badMetadata = + BadMetadata + + +isBlocking : State -> Bool +isBlocking state = + case state of + None -> + False + + _ -> + True + + + +-- UPDATE + + +type Msg = Cancel | Proceed + + +close : Msg -> State -> Maybe Encode.Value +close msg state = + case state of + None -> + Nothing + + BadMetadata _ -> + Nothing + + BadImport _ -> + Nothing + + RiskyImport _ rawHistory -> + case msg of + Cancel -> + Nothing + + Proceed -> + Just rawHistory + + +assessImport : Metadata -> String -> Result State Encode.Value +assessImport metadata jsonString = + case Decode.decodeString uploadDecoder jsonString of + Err _ -> + Err corruptImport + + Ok (foreignMetadata, rawHistory) -> + let + report = + Metadata.check foreignMetadata metadata + in + case Report.evaluate report of + Report.Impossible -> + Err (BadImport report) + + Report.Risky -> + Err (RiskyImport report rawHistory) + + Report.Fine -> + Ok rawHistory + + +uploadDecoder : Decode.Decoder (Metadata, Encode.Value) +uploadDecoder = + Decode.map2 (,) + (Decode.field "metadata" Metadata.decoder) + (Decode.field "history" Decode.value) + + + +-- VIEW + + +type alias Config msg = + { resume : msg + , open : msg + , importHistory : msg + , exportHistory : msg + , wrap : Msg -> msg + } + + +type Block = Normal | Pause | Message + + +view : Config msg -> Bool -> Bool -> Int -> State -> ( Block, Node msg ) +view config isPaused isOpen numMsgs state = + let + (block, nodes) = + viewHelp config isPaused isOpen numMsgs state + in + ( block + , div [ class "elm-overlay" ] (styles :: nodes) + ) + + +viewHelp : Config msg -> Bool -> Bool -> Int -> State -> ( Block, List (Node msg) ) +viewHelp config isPaused isOpen numMsgs state = + case state of + None -> + let + miniControls = + if isOpen then [] else [ viewMiniControls config numMsgs ] + in + ( if isPaused then Pause else Normal + , if isPaused && not isOpen then + viewResume config :: miniControls + else + miniControls + ) + + BadMetadata badMetadata -> + viewMessage config + "Cannot use Import or Export" + (viewBadMetadata badMetadata) + (Accept "Ok") + + BadImport report -> + viewMessage config + "Cannot Import History" + (viewReport True report) + (Accept "Ok") + + RiskyImport report _ -> + viewMessage config + "Warning" + (viewReport False report) + (Choose "Cancel" "Import Anyway") + + +viewResume config = + div [ class "elm-overlay-resume", onClick config.resume ] + [ div [class "elm-overlay-resume-words"] [text "Click to Resume"] ] + + + +-- VIEW MESSAGE + + +viewMessage : Config msg -> String -> List (Node msg) -> Buttons -> ( Block, List (Node msg) ) +viewMessage config title details buttons = + ( Message + , [ div [ class "elm-overlay-message" ] + [ div [ class "elm-overlay-message-title" ] [ text title ] + , div [ class "elm-overlay-message-details" ] details + , map config.wrap (viewButtons buttons) + ] + ] + ) + + +viewReport : Bool -> Report -> List (Node msg) +viewReport isBad report = + case report of + Report.CorruptHistory -> + [ text "Looks like this history file is corrupt. I cannot understand it." + ] + + Report.VersionChanged old new -> + [ text <| + "This history was created with Elm " + ++ old ++ ", but you are using Elm " + ++ new ++ " right now." + ] + + Report.MessageChanged old new -> + [ text <| + "To import some other history, the overall message type must" + ++ " be the same. The old history has " + , viewCode old + , text " messages, but the new program works with " + , viewCode new + , text " messages." + ] + + Report.SomethingChanged changes -> + [ node "p" [] [ text (if isBad then explanationBad else explanationRisky) ] + , node "ul" [] (List.map viewChange changes) + ] + + +explanationBad : String +explanationBad = """ +The messages in this history do not match the messages handled by your +program. I noticed changes in the following types: +""" + +explanationRisky : String +explanationRisky = """ +This history seems old. It will work with this program, but some +messages have been added since the history was created: +""" + + +viewCode : String -> Node msg +viewCode name = + node "code" [] [ text name ] + + +viewChange : Report.Change -> Node msg +viewChange change = + node "li" [] <| + case change of + Report.AliasChange name -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + ] + + Report.UnionChange name { removed, changed, added, argsMatch } -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + , node "ul" [] + [ viewMention removed "Removed " + , viewMention changed "Changed " + , viewMention added "Added " + ] + , if argsMatch then + text "" + else + text "This may be due to the fact that the type variable names changed." + ] + + +viewMention : List String -> String -> Node msg +viewMention tags verbed = + case List.map viewCode (List.reverse tags) of + [] -> + text "" + + [tag] -> + node "li" [] + [ text verbed, tag, text "." ] + + [tag2, tag1] -> + node "li" [] + [ text verbed, tag1, text " and ", tag2, text "." ] + + lastTag :: otherTags -> + node "li" [] <| + text verbed + :: List.intersperse (text ", ") (List.reverse otherTags) + ++ [ text ", and ", lastTag, text "." ] + + +viewBadMetadata : Metadata.Error -> List (Node msg) +viewBadMetadata {message, problems} = + [ node "p" [] + [ text "The " + , viewCode message + , text " type of your program cannot be reliably serialized for history files." + ] + , node "p" [] [ text "Functions cannot be serialized, nor can values that contain functions. This is a problem in these places:" ] + , node "ul" [] (List.map viewProblemType problems) + , node "p" [] + [ text goodNews1 + , a [ href "https://guide.elm-lang.org/types/union_types.html" ] [ text "union types" ] + , text ", in your messages. From there, your " + , viewCode "update" + , text goodNews2 + ] + ] + + +goodNews1 = """ +The good news is that having values like this in your message type is not +so great in the long run. You are better off using simpler data, like +""" + + +goodNews2 = """ +function can pattern match on that data and call whatever functions, JSON +decoders, etc. you need. This makes the code much more explicit and easy to +follow for other readers (or you in a few months!) +""" + + +viewProblemType : Metadata.ProblemType -> Node msg +viewProblemType { name, problems } = + node "li" [] + [ viewCode name + , text (" can contain " ++ addCommas (List.map problemToString problems) ++ ".") + ] + + +problemToString : Metadata.Problem -> String +problemToString problem = + case problem of + Metadata.Function -> + "functions" + + Metadata.Decoder -> + "JSON decoders" + + Metadata.Task -> + "tasks" + + Metadata.Process -> + "processes" + + Metadata.Socket -> + "web sockets" + + Metadata.Request -> + "HTTP requests" + + Metadata.Program -> + "programs" + + Metadata.VirtualDom -> + "virtual DOM values" + + +addCommas : List String -> String +addCommas items = + case items of + [] -> + "" + + [item] -> + item + + [item1, item2] -> + item1 ++ " and " ++ item2 + + lastItem :: otherItems -> + String.join ", " (otherItems ++ [ " and " ++ lastItem ]) + + + +-- VIEW MESSAGE BUTTONS + + +type Buttons + = Accept String + | Choose String String + + +viewButtons : Buttons -> Node Msg +viewButtons buttons = + div [ class "elm-overlay-message-buttons" ] <| + case buttons of + Accept proceed -> + [ node "button" [ onClick Proceed ] [ text proceed ] + ] + + Choose cancel proceed -> + [ node "button" [ onClick Cancel ] [ text cancel ] + , node "button" [ onClick Proceed ] [ text proceed ] + ] + + + +-- VIEW MINI CONTROLS + + +viewMiniControls : Config msg -> Int -> Node msg +viewMiniControls config numMsgs = + div + [ class "elm-mini-controls" + ] + [ div + [ onClick config.open + , class "elm-mini-controls-button" + ] + [ text ("Explore History (" ++ toString numMsgs ++ ")") + ] + , viewImportExport + [class "elm-mini-controls-import-export"] + config.importHistory + config.exportHistory + ] + + +viewImportExport : List (Property msg) -> msg -> msg -> Node msg +viewImportExport props importMsg exportMsg = + div + props + [ button importMsg "Import" + , text " / " + , button exportMsg "Export" + ] + + +button : msg -> String -> Node msg +button msg label = + span [ onClick msg, style [("cursor","pointer")] ] [ text label ] + + + +-- STYLE + + +styles : Node msg +styles = + node "style" [] [ text """ + +.elm-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + color: white; + pointer-events: none; + font-family: 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif; +} + +.elm-overlay-resume { + width: 100%; + height: 100%; + cursor: pointer; + text-align: center; + pointer-events: auto; + background-color: rgba(200, 200, 200, 0.7); +} + +.elm-overlay-resume-words { + position: absolute; + top: calc(50% - 40px); + font-size: 80px; + line-height: 80px; + height: 80px; + width: 100%; +} + +.elm-mini-controls { + position: fixed; + bottom: 0; + right: 6px; + border-radius: 4px; + background-color: rgb(61, 61, 61); + font-family: monospace; + pointer-events: auto; +} + +.elm-mini-controls-button { + padding: 6px; + cursor: pointer; + text-align: center; + min-width: 24ch; +} + +.elm-mini-controls-import-export { + padding: 4px 0; + font-size: 0.8em; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message { + position: absolute; + width: 600px; + height: 100%; + padding-left: calc(50% - 300px); + padding-right: calc(50% - 300px); + background-color: rgba(200, 200, 200, 0.7); + pointer-events: auto; +} + +.elm-overlay-message-title { + font-size: 36px; + height: 80px; + background-color: rgb(50, 50, 50); + padding-left: 22px; + vertical-align: middle; + line-height: 80px; +} + +.elm-overlay-message-details { + padding: 8px 20px; + overflow-y: auto; + max-height: calc(100% - 156px); + background-color: rgb(61, 61, 61); +} + +.elm-overlay-message-details-type { + font-size: 1.5em; +} + +.elm-overlay-message-details ul { + list-style-type: none; + padding-left: 20px; +} + +.elm-overlay-message-details ul ul { + list-style-type: disc; + padding-left: 2em; +} + +.elm-overlay-message-details li { + margin: 8px 0; +} + +.elm-overlay-message-buttons { + height: 60px; + line-height: 60px; + text-align: right; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message-buttons button { + margin-right: 20px; +} + +""" ] \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm new file mode 100644 index 0000000..89b4e07 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm @@ -0,0 +1,99 @@ +module VirtualDom.Report exposing + ( Report(..) + , Change(..) + , TagChanges + , emptyTagChanges + , hasTagChanges + , Status(..), evaluate + ) + + + +-- REPORTS + + +type Report + = CorruptHistory + | VersionChanged String String + | MessageChanged String String + | SomethingChanged (List Change) + + +type Change + = AliasChange String + | UnionChange String TagChanges + + +type alias TagChanges = + { removed : List String + , changed : List String + , added : List String + , argsMatch : Bool + } + + +emptyTagChanges : Bool -> TagChanges +emptyTagChanges argsMatch = + TagChanges [] [] [] argsMatch + + +hasTagChanges : TagChanges -> Bool +hasTagChanges tagChanges = + tagChanges == TagChanges [] [] [] True + + +type Status = Impossible | Risky | Fine + + +evaluate : Report -> Status +evaluate report = + case report of + CorruptHistory -> + Impossible + + VersionChanged _ _ -> + Impossible + + MessageChanged _ _ -> + Impossible + + SomethingChanged changes -> + worstCase Fine (List.map evaluateChange changes) + + +worstCase : Status -> List Status -> Status +worstCase status statusList = + case statusList of + [] -> + status + + Impossible :: _ -> + Impossible + + Risky :: rest -> + worstCase Risky rest + + Fine :: rest -> + worstCase status rest + + +evaluateChange : Change -> Status +evaluateChange change = + case change of + AliasChange _ -> + Impossible + + UnionChange _ { removed, changed, added, argsMatch } -> + if not argsMatch || some changed || some removed then + Impossible + + else if some added then + Risky + + else + Fine + + +some : List a -> Bool +some list = + not (List.isEmpty list) diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js new file mode 100644 index 0000000..6b1ebbb --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js @@ -0,0 +1,35 @@ +Elm.Native.TestHelpers = {}; +Elm.Native.TestHelpers.make = function(localRuntime) +{ + localRuntime.Native = localRuntime.Native || {}; + localRuntime.Native.TestHelpers = localRuntime.Native.TestHelpers || {}; + if (localRuntime.Native.TestHelpers.values) + { + return localRuntime.Native.TestHelpers.values; + } + + var VirtualDom = Elm.Native.VirtualDom.make(localRuntime); + + function unsafeRecordCallCount(f) { + function wrapper(a) { + wrapper.__elm_test_call_count += 1; + return f(a); + } + wrapper.__elm_test_call_count = 0; + return wrapper; + } + + function unsafeQueryCallCount(f) { + if (f.__elm_test_call_count === undefined) { + return -1; + } + return f.__elm_test_call_count; + } + + Elm.Native.TestHelpers.values = { + unsafeRecordCallCount: unsafeRecordCallCount, + unsafeQueryCallCount: unsafeQueryCallCount, + updateAndReplace: F3(VirtualDom.updateAndReplace) + }; + return localRuntime.Native.TestHelpers.values = Elm.Native.TestHelpers.values; +}; \ No newline at end of file diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm new file mode 100644 index 0000000..09e362a --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm @@ -0,0 +1,72 @@ +module TestCases.Lazy where + +import VirtualDom exposing (Node, lazy) +import ElmTest.Assertion exposing (assertEqual) +import ElmTest.Test exposing (Test, suite, test) + +import TestHelpers exposing (renderDom, updateDom, unsafeRecordCallCount, unsafeQueryCallCount) + +renderRecord : { x: String, y: String } -> Node +renderRecord r = + VirtualDom.text <| "The values: " ++ r.x ++ ", " ++ r.y + + +renderPrimitive : Int -> Node +renderPrimitive x = + VirtualDom.text <| "The value: " ++ (toString x) + + +testLazyIdenticalRecord = + test "isn't called again with identical record" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender record + v3 = updateDom v2 <| lazy wrappedRender record + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyIdenticalPrimitive = + test "isn't called again with identical primitive" <| + let wrappedRender = unsafeRecordCallCount renderPrimitive + v1 = renderDom <| lazy wrappedRender 5 + v2 = updateDom v1 <| lazy wrappedRender 5 + v3 = updateDom v2 <| lazy wrappedRender 5 + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyRecordMutationOfIdenticalValue = + test "isn't called again with record mutation of identical value" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender { record | x = "a" } + v3 = updateDom v2 <| lazy wrappedRender { record | x = "a", y = "b" } + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testNotLazyDifferentRecord = + test "is called again with an equivalent but different record" <| + let wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender { x = "a", y = "b" } + v2 = updateDom v1 <| lazy wrappedRender { x = "a", y = "b" } + v3 = updateDom v2 <| lazy wrappedRender { x = "a", y = "b" } + in + assertEqual 3 <| unsafeQueryCallCount wrappedRender + + +tests : Test +tests = + suite + "Lazy" + [ + testLazyIdenticalRecord, + testLazyIdenticalPrimitive, + -- Re-enable this test when core supports checking + -- record update values for identity before copying: + -- testLazyRecordMutationOfIdenticalValue, + testNotLazyDifferentRecord + ] diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm new file mode 100644 index 0000000..2fe24cf --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm @@ -0,0 +1,34 @@ +module TestHelpers where + +import VirtualDom exposing (Node) + +import Native.TestHelpers +import Native.VirtualDom + +unsafeRecordCallCount : (a -> b) -> (a -> b) +unsafeRecordCallCount = + Native.TestHelpers.unsafeRecordCallCount + +unsafeQueryCallCount : (a -> b) -> Int +unsafeQueryCallCount = + Native.TestHelpers.unsafeQueryCallCount + +type OpaqueDom = OpaqueDom + +render : Node -> OpaqueDom +render = + Native.VirtualDom.render + +updateAndReplace : OpaqueDom -> Node -> Node -> OpaqueDom +updateAndReplace = + Native.TestHelpers.updateAndReplace + + +renderDom : Node -> (OpaqueDom, Node) +renderDom vdom = + (render vdom, vdom) + + +updateDom : (OpaqueDom, Node) -> Node -> (OpaqueDom, Node) +updateDom (oldDom, oldVDom) newVDom = + (updateAndReplace oldDom oldVDom newVDom, newVDom) diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm new file mode 100644 index 0000000..ea59abf --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm @@ -0,0 +1,18 @@ + +import ElmTest.Runner.Console exposing (runDisplay) +import ElmTest.Test exposing (Test, suite) +import Console exposing (IO) +import Task exposing (Task) + +import TestCases.Lazy + +tests : Test +tests = + suite + "VirtualDom Library Tests" + [ + TestCases.Lazy.tests + ] + +port runner : Signal (Task x ()) +port runner = Console.run (runDisplay tests) diff --git a/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json new file mode 100644 index 0000000..5041954 --- /dev/null +++ b/part1/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "Test for VirtualDom", + "license": "BSD3", + "repository": "https://github.com/evancz/virtual-dom.git", + "exposed-modules": [], + "source-directories": [ + ".", + "build/virtual-dom/" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "2.0.0 <= v < 4.0.0", + "laszlopandy/elm-console": "1.0.0 <= v < 2.0.0", + "deadfoxygrandpa/elm-test": "1.0.3 <= v < 2.0.0" + }, + "elm-version": "0.16.0 <= v < 0.17.0" +} \ No newline at end of file diff --git a/part10/elm-stuff/exact-dependencies.json b/part10/elm-stuff/exact-dependencies.json new file mode 100644 index 0000000..3b06d52 --- /dev/null +++ b/part10/elm-stuff/exact-dependencies.json @@ -0,0 +1,7 @@ +{ + "elm-lang/virtual-dom": "2.0.4", + "elm-lang/html": "2.0.0", + "elm-lang/http": "1.0.0", + "NoRedInk/elm-decode-pipeline": "3.0.0", + "elm-lang/core": "5.1.1" +} \ No newline at end of file diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore new file mode 100644 index 0000000..a594364 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore @@ -0,0 +1,4 @@ +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE new file mode 100644 index 0000000..a8e355a --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016, NoRedInk +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of elm-decode-pipeline nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md new file mode 100644 index 0000000..7843d4d --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md @@ -0,0 +1,108 @@ +# elm-decode-pipeline + +A library for building decoders using the pipeline [`(|>)`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Basics#|>) +operator and plain function calls. + +## Motivation + +It's common to decode into a record that has a `type alias`. Here's an example +of this from the [`object3`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Json-Decode#object3) +docs: + +```elm +type alias Job = { name : String, id : Int, completed : Bool } + +point : Decoder Job +point = + object3 Job + ("name" := string) + ("id" := int) + ("completed" := bool) +``` + +This works because a record type alias can be called as a normal function. In +that case it accepts one argument for each field (in whatever order the fields +are declared in the type alias) and then returns an appropriate record built +with those arguments. + +The `objectN` decoders are straightforward, but require manually changing N +whenever the field count changes. This library provides functions designed to +be used with the `|>` operator, with the goal of having decoders that are both +easy to read and easy to modify. + +## Examples + +Here is a decoder built with this library. + +```elm +import Json.Decode exposing (int, string, float, Decoder) +import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded) + + +type alias User = + { id : Int + , email : Maybe String + , name : String + , percentExcited : Float + } + + +userDecoder : Decoder User +userDecoder = + decode User + |> required "id" int + |> required "email" (nullable string) -- `null` decodes to `Nothing` + |> optional "name" string "(fallback if name is `null` or not present)" + |> hardcoded 1.0 +``` + +In this example: + +* `decode` is a synonym for [`succeed`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Json-Decode#succeed) (it just reads better here) +* `required "id" int` is similar to `("id" := int)` +* `optional` is like `required`, but if the field is either `null` or not present, decoding does not fail; instead it succeeds with the provided fallback value. +* `hardcoded` does not look at the provided JSON, and instead always decodes to the same value. + +You could use this decoder as follows: + +```elm +Json.Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "name": "Sam Sample"} + """ +``` + +The result would be: + +```elm +{ id = 123 +, email = "sam@example.com" +, name = "Sam Sample" +, percentExcited = 1.0 +} +``` + +Alternatively, you could use it like so: + +```elm +Json.Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "percentExcited": "(hardcoded)"} + """ +``` + +In this case, the result would be: + +```elm +{ id = 123 +, email = "sam@example.com" +, name = "(fallback if name not present)" +, percentExcited = 1.0 +} +``` + +--- +[![NoRedInk](https://cloud.githubusercontent.com/assets/1094080/9069346/99522418-3a9d-11e5-8175-1c2bfd7a2ffe.png)][team] +[team]: http://noredink.com/about/team diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json new file mode 100644 index 0000000..06af200 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json @@ -0,0 +1,16 @@ +{ + "version": "3.0.0", + "summary": "A pipeline-friendly library for building JSON decoders.", + "repository": "https://github.com/NoRedInk/elm-decode-pipeline.git", + "license": "BSD-3-Clause", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Json.Decode.Pipeline" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm new file mode 100644 index 0000000..3b83e15 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm @@ -0,0 +1,19 @@ +module Example exposing (..) + +import Json.Decode exposing (int, string, float, Decoder) +import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded) + + +type alias User = + { id : Int + , name : String + , percentExcited : Float + } + + +userDecoder : Decoder User +userDecoder = + decode User + |> required "id" int + |> optional "name" string "(fallback if name not present)" + |> hardcoded 1.0 diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm new file mode 100644 index 0000000..15eab71 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm @@ -0,0 +1,292 @@ +module Json.Decode.Pipeline exposing (required, requiredAt, optional, optionalAt, resolve, decode, hardcoded, custom) + +{-| # Json.Decode.Pipeline + +Use the `(|>)` operator to build JSON decoders. + +## Decoding fields + +@docs required, requiredAt, optional, optionalAt, hardcoded, custom + +## Beginning and ending pipelines + +@docs decode, resolve + +-} + +import Json.Decode as Decode exposing (Decoder) + + +{-| Decode a required field. + + import Json.Decode exposing (int, string, Decoder) + import Decode.Pipeline exposing (decode, required) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "name" string + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "name": "Sam"} + """ + -- Ok { id = 123, name = "Sam", email = "sam@example.com" } +-} +required : String -> Decoder a -> Decoder (a -> b) -> Decoder b +required key valDecoder decoder = + custom (Decode.field key valDecoder) decoder + + +{-| Decode a required nested field. +-} +requiredAt : List String -> Decoder a -> Decoder (a -> b) -> Decoder b +requiredAt path valDecoder decoder = + custom (Decode.at path valDecoder) decoder + + +{-| Decode a field that may be missing or have a null value. If the field is +missing, then it decodes as the `fallback` value. If the field is present, +then `valDecoder` is used to decode its value. If `valDecoder` fails on a +`null` value, then the `fallback` is used as if the field were missing +entirely. + + import Json.Decode exposing (int, string, null, oneOf, Decoder) + import Decode.Pipeline exposing (decode, required, optional) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> optional "name" string "blah" + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com" } + """ + -- Ok { id = 123, name = "blah", email = "sam@example.com" } + +Because `valDecoder` is given an opportunity to decode `null` values before +resorting to the `fallback`, you can distinguish between missing and `null` +values if you need to: + + userDecoder2 = + decode User + |> required "id" int + |> optional "name" (oneOf [ string, null "NULL" ]) "MISSING" + |> required "email" string + +-} +optional : String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b +optional key valDecoder fallback decoder = + custom (optionalDecoder (Decode.field key Decode.value) valDecoder fallback) decoder + + +{-| Decode an optional nested field. +-} +optionalAt : List String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b +optionalAt path valDecoder fallback decoder = + custom (optionalDecoder (Decode.at path Decode.value) valDecoder fallback) decoder + + +optionalDecoder : Decoder Decode.Value -> Decoder a -> a -> Decoder a +optionalDecoder pathDecoder valDecoder fallback = + let + nullOr decoder = + Decode.oneOf [ decoder, Decode.null fallback ] + + handleResult input = + case Decode.decodeValue pathDecoder input of + Ok rawValue -> + -- The field was present, so now let's try to decode that value. + -- (If it was present but fails to decode, this should and will fail!) + case Decode.decodeValue (nullOr valDecoder) rawValue of + Ok finalResult -> + Decode.succeed finalResult + + Err finalErr -> + Decode.fail finalErr + + Err _ -> + -- The field was not present, so use the fallback. + Decode.succeed fallback + in + Decode.value + |> Decode.andThen handleResult + + +{-| Rather than decoding anything, use a fixed value for the next step in the +pipeline. `harcoded` does not look at the JSON at all. + + import Json.Decode exposing (int, string, Decoder) + import Decode.Pipeline exposing (decode, required) + + + type alias User = + { id : Int + , email : String + , followers : Int + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "email" string + |> hardcoded 0 + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com"} + """ + -- Ok { id = 123, email = "sam@example.com", followers = 0 } +-} +hardcoded : a -> Decoder (a -> b) -> Decoder b +hardcoded = + Decode.succeed >> custom + + +{-| Run the given decoder and feed its result into the pipeline at this point. + +Consider this example. + + import Json.Decode exposing (int, string, at, Decoder) + import Decode.Pipeline exposing (decode, required, custom) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> custom (at [ "profile", "name" ] string) + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + { + "id": 123, + "email": "sam@example.com", + "profile": {"name": "Sam"} + } + """ + -- Ok { id = 123, name = "Sam", email = "sam@example.com" } +-} +custom : Decoder a -> Decoder (a -> b) -> Decoder b +custom = + Decode.map2 (|>) + + +{-| Convert a `Decoder (Result x a)` into a `Decoder a`. Useful when you want +to perform some custom processing just before completing the decoding operation. + + import Json.Decode exposing (int, string, float, Decoder) + import Decode.Pipeline exposing + (decode, required, resolve) + + + type alias User = + { id : Int + , email : String + } + + + userDecoder : Decoder User + userDecoder = + let + -- toDecoder gets run *after* all the + -- (|> required ...) steps are done. + toDecoder : Int -> String -> Int -> Decoder User + toDecoder id email version = + if version > 2 then + succeed (User id email) + else + fail "This JSON is from a deprecated source. Please upgrade!" + in + decode toDecoder + |> required "id" int + |> required "email" string + |> required "version" int -- version is part of toDecoder, + |> resolve -- but it is not a part of User + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "version": 1} + """ + -- Err "This JSON is from a deprecated source. Please upgrade!" +-} +resolve : Decoder (Decoder a) -> Decoder a +resolve = + Decode.andThen identity + + +{-| Begin a decoding pipeline. This is a synonym for [Json.Decode.succeed](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode#succeed), +intended to make things read more clearly. + + import Json.Decode exposing (int, string, float, Decoder) + import Json.Decode.Pipeline exposing (decode, required, optional) + + + type alias User = + { id : Int + , email : String + , name : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "email" string + |> optional "name" string "" +-} +decode : a -> Decoder a +decode = + Decode.succeed diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore new file mode 100644 index 0000000..aee9810 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore @@ -0,0 +1 @@ +/elm-stuff/ diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm new file mode 100644 index 0000000..532f8e6 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm @@ -0,0 +1,19 @@ +port module Main exposing (..) + +{-| +Run the tests with node-test-runner: + +https://github.com/rtfeldman/node-test-runner +-} + +import Tests +import Test.Runner.Node exposing (run) +import Json.Encode exposing (Value) + + +main : Program Never +main = + run emit Tests.all + + +port emit : ( String, Value ) -> Cmd msg diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm new file mode 100644 index 0000000..f4bcaa1 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm @@ -0,0 +1,114 @@ +module Tests exposing (..) + +import Test exposing (..) +import Expect exposing (Expectation) +import Json.Decode.Pipeline + exposing + ( decode + , required + , requiredAt + , optional + , optionalAt + , resolveResult + ) +import Json.Decode exposing (Decoder, string, null) + + +{-| Run some JSON through a Decoder and return the result. +-} +runWith : String -> Decoder a -> Result String a +runWith = + flip Json.Decode.decodeString + + +isError : Result err ok -> Bool +isError result = + case result of + Err _ -> + True + + Ok _ -> + False + + +expectErr : Result err ok -> Expectation +expectErr result = + isError result + |> Expect.true ("Expected an Err but got " ++ toString result) + + +all : Test +all = + describe + "Json.Decode.Pipeline" + [ test "should decode basic example" <| + \() -> + decode (,) + |> required "a" string + |> required "b" string + |> runWith """{"a":"foo","b":"bar"}""" + |> Expect.equal (Ok ( "foo", "bar" )) + , test "should decode requiredAt fields" <| + \() -> + decode (,) + |> requiredAt [ "a" ] string + |> requiredAt [ "b", "c" ] string + |> runWith """{"a":"foo","b":{"c":"bar"}}""" + |> Expect.equal (Ok ( "foo", "bar" )) + , test "should decode optionalAt fields" <| + \() -> + decode (,) + |> optionalAt [ "a", "b" ] string "--" + |> optionalAt [ "x", "y" ] string "--" + |> runWith """{"a":{},"x":{"y":"bar"}}""" + |> Expect.equal (Ok ( "--", "bar" )) + , test "optional succeeds if the field is not present" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"x":"five"}""" + |> Expect.equal (Ok ( "--", "five" )) + , test "optional succeeds with fallback if the field is present but null" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"a":null,"x":"five"}""" + |> Expect.equal (Ok ( "--", "five" )) + , test "optional succeeds with result of the given decoder if the field is null and the decoder decodes nulls" <| + \() -> + decode (,) + |> optional "a" (null "null") "--" + |> optional "x" string "--" + |> runWith """{"a":null,"x":"five"}""" + |> Expect.equal (Ok ( "null", "five" )) + , test "optional fails if the field is present but doesn't decode" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"x":5}""" + |> expectErr + , test "optionalAt fails if the field is present but doesn't decode" <| + \() -> + decode (,) + |> optionalAt [ "a", "b" ] string "--" + |> optionalAt [ "x", "y" ] string "--" + |> runWith """{"a":{},"x":{"y":5}}""" + |> expectErr + , test "resolveResult bubbles up decoded Err results" <| + \() -> + decode Err + |> required "error" string + |> resolveResult + |> runWith """{"error":"invalid"}""" + |> expectErr + , test "resolveResult bubbles up decoded Ok results" <| + \() -> + decode Ok + |> required "ok" string + |> resolveResult + |> runWith """{"ok":"valid"}""" + |> Expect.equal (Ok "valid") + ] diff --git a/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json new file mode 100644 index 0000000..4513220 --- /dev/null +++ b/part10/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "1.0.0", + "summary": "Sample Elm Test", + "repository": "https://github.com/user/project.git", + "license": "BSD-3-Clause", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-community/elm-test": "2.0.0 <= v < 3.0.0", + "rtfeldman/node-test-runner": "1.0.0 <= v < 2.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/.eslintrc b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.eslintrc new file mode 100644 index 0000000..169879a --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.eslintrc @@ -0,0 +1,156 @@ +{ + "parser": "babel-eslint", // https://github.com/babel/babel-eslint + "plugins": [], + "env": { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments + "browser": true, // browser global variables + "node": true // Node.js global variables and Node.js-specific rules + }, + "ecmaFeatures": { + "arrowFunctions": true, + "blockBindings": true, + "classes": true, + "defaultParams": true, + "destructuring": true, + "forOf": true, + "generators": false, + "modules": true, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": false, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "spread": true, + "superInFunctions": true, + "templateStrings": true, + }, + "rules": { +/** + * Strict mode + */ + // babel inserts "use strict"; for us + "strict": [2, "never"], // http://eslint.org/docs/rules/strict + +/** + * Variables + */ + "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow + "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names + "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars + "vars": "local", + "args": "after-used" + }], + "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define + +/** + * Possible errors + */ + "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign + "no-console": 1, // http://eslint.org/docs/rules/no-console + "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger + "no-alert": 1, // http://eslint.org/docs/rules/no-alert + "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition + "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys + "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case + "no-empty": 2, // http://eslint.org/docs/rules/no-empty + "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign + "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast + "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi + "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign + "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations + "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp + "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace + "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls + "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays + "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable + "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan + "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var + +/** + * Best practices + */ + "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return + "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly + "default-case": 2, // http://eslint.org/docs/rules/default-case + "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation + "allowKeywords": true + }], + "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq + "max-len": [2, 100, 4], + "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in + "no-caller": 2, // http://eslint.org/docs/rules/no-caller + "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return + "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null + "no-eval": 2, // http://eslint.org/docs/rules/no-eval + "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native + "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind + "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough + "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal + "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval + "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks + "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func + "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str + "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign + "no-new": 2, // http://eslint.org/docs/rules/no-new + "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func + "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers + "no-octal": 2, // http://eslint.org/docs/rules/no-octal + "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape + "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign + "no-proto": 2, // http://eslint.org/docs/rules/no-proto + "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare + "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign + "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url + "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare + "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences + "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal + "no-with": 2, // http://eslint.org/docs/rules/no-with + "radix": 2, // http://eslint.org/docs/rules/radix + "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife + "yoda": 2, // http://eslint.org/docs/rules/yoda + +/** + * Style + */ + "indent": [2, "tab"], // http://eslint.org/docs/rules/indent + "quotes": [ + 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes + ], + "camelcase": [2, { // http://eslint.org/docs/rules/camelcase + "properties": "never" + }], + "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing + "before": false, + "after": true + }], + "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style + "eol-last": 2, // http://eslint.org/docs/rules/eol-last + "func-names": 1, // http://eslint.org/docs/rules/func-names + "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing + "beforeColon": false, + "afterColon": true + }], + "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines + "max": 2 + }], + "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary + "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object + "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func + "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces + "no-extra-parens": [2, "functions"], // http://eslint.org/docs/rules/no-extra-parens + "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle + "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks + "semi": [2, "always"], // http://eslint.org/docs/rules/semi + "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing + "before": false, + "after": true + }], + "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords + "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks + "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren + "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops + "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case + "spaced-comment": [2, "always", {// http://eslint.org/docs/rules/spaced-comment + "exceptions": ["-", "+"], + "markers": ["=", "!"] // space here to support sprockets directives + }] + } +} diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore new file mode 100644 index 0000000..7f3cfe4 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.gitignore @@ -0,0 +1,3 @@ +elm-stuff +tests/test.js +node_modules/ \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/.travis.yml b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.travis.yml new file mode 100644 index 0000000..9576ae8 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/.travis.yml @@ -0,0 +1,35 @@ +sudo: false + +cache: + directories: + - test/elm-stuff/build-artifacts + - sysconfcpus + +language: node_js + +node_js: + - "4.3" + +before_install: + - if [ ${TRAVIS_OS_NAME} == "osx" ]; + then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh; + fi + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142 + if [ ! -d sysconfcpus/bin ]; + then + git clone https://github.com/obmarg/libsysconfcpus.git; + cd libsysconfcpus; + ./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus; + make && make install; + cd ..; + fi + +install: + - npm install -g elm@0.18 elm-test + - mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old + - printf '%s\n\n' '#!/bin/bash' 'echo "Running elm-make with sysconfcpus -n 2"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old "$@"' > $(npm config get prefix)/bin/elm-make + - chmod +x $(npm config get prefix)/bin/elm-make + +script: + - bash tests/run-tests.sh diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/CONTRIBUTING.md b/part10/elm-stuff/packages/elm-lang/core/5.1.1/CONTRIBUTING.md new file mode 100644 index 0000000..c8bd8b4 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/CONTRIBUTING.md @@ -0,0 +1,43 @@ +# Contributing to the core libraries + +Thanks helping with the development of Elm! This document describes the basic +standards for opening pull requests and making the review process as smooth as +possible. + +## Ground rules + + * Always make pull requests minimal. If it can be split up, it should be split up. + * Use style consistent with the file you are modifying. + * Use descriptive titles for PRs + * Provide all the necessary context for evaluation in the PR. + If there are relevant issues or examples or discussions, add them. + If things can be summarized, summarize them. The easiest PRs are ones + that already address the reviewers questions and concerns. + +## Documentation Fixes + +If you want to fix docs, just open a PR. This is super helpful! + +## Bug Fixes + +If you find an issue or see one you want to work on, go for it! + +The best strategy is often to dive in. Asking for directions usually +does not work. If someone knew the specifics and knew how how to fix +it, it is likely they would have already sent the PR themselves! + +Also, be sure you are testing. + +## Adding New Functions + +We are fairly conservative about adding new functions to core libraries. +If you want to augment the `List` or `Array` library, we recommend creating +small packages called `list-extras` or `array-extras` that have all the +features you want. There are already several such packages maintained at +the [Elm Community organization](https://github.com/elm-community) that +welcome contributions in the form of pull requests. + +Long term, we will set up a process to review `*-extras` packages to move +stuff into core. By going through packages, it will be much easier to assess +whether a function is pleasant and useful in practice before committing to it +in the core libraries. diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE b/part10/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/README.md b/part10/elm-stuff/packages/elm-lang/core/5.1.1/README.md new file mode 100644 index 0000000..07c3f6e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/README.md @@ -0,0 +1,34 @@ +# Elm Core Libraries + +[![Build Status](https://travis-ci.org/elm-lang/core.svg?branch=master)](https://travis-ci.org/elm-lang/core) + +Every Elm project needs the core libraries. They provide basic functionality including: + + * The Basics — addition, subtraction, etc. + * Data Structures — lists, dictionaries, sets, etc. + + +## Default Imports + +All Elm files have some default imports: + +```elm +import Basics exposing (..) +import List exposing ( List, (::) ) +import Maybe exposing ( Maybe( Just, Nothing ) ) +import Result exposing ( Result( Ok, Err ) ) +import String +import Tuple + +import Debug + +import Platform exposing ( Program ) +import Platform.Cmd exposing ( Cmd, (!) ) +import Platform.Sub exposing ( Sub ) +``` + +The intention is to include things that are both extremely useful and very +unlikely to overlap with anything that anyone will ever write in a library. +By keeping the set of default imports small, it also becomes easier to use +whatever version of `map` suits your fancy. Finally, it makes it easier to +figure out where the heck a function is coming from. diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/changelog.md b/part10/elm-stuff/packages/elm-lang/core/5.1.1/changelog.md new file mode 100644 index 0000000..9781f2c --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/changelog.md @@ -0,0 +1,143 @@ +# 0.15 + +### Syntax + +New `import` syntax with keyword `exposing`. + +### Module Changes + + * Move `Http` to `elm-http` package and totally redo API + * Remove `WebSocket` module + * Add `Task` module + +### Channels become Mailboxes + +`Graphics.Input` now works with this API (from module `Signal`): + +```elm +type alias Mailbox a = { address : Address a, signal : Signal a } + +mailbox : a -> Mailbox a +``` + +You can then send messages to the `Address` with functions like `Signal.send` +and `Signal.message`, or create forwarding addresses with `Signal.forwardTo`. + +### Text in Collages + +`Graphics.Collage` now has two new functions: + +```elm +text : Text -> Form +outlinedText : LineStyle -> Text -> Form +``` + +These functions render text with the canvas, making things quite a bit faster. +The underlying implementation of `Text` has also been improved dramatically. + +### Miscellaneous + + * Change types of `head`, `tail`, `maximum`, `minimum` by wrapping output in `Maybe` + * Move `leftAligned`, `centered`, `rightAligned` from `Text` to `Graphics.Element` + * Move `asText` from `Text` to `Graphics.Element`, renaming it to `show` in the process + * Remove `Text.plainText` (can be replaced by `Graphics.Element.leftAligned << Text.fromString`) + * Change type of `Keyboard.keysDown` from `Signal (List KeyCode)` to `Signal (Set KeyCode)` + * Remove `Keyboard.directions` + * Rename `Keyboard.lastPressed` to `Keyboard.presses` + + +# 0.14 + +### Syntax + + * Keyword `type` becomes `type alias` + * Keyword `data` becomes `type` + * Remove special list syntax in types, so `[a]` becomes `List a` + + +### Reduce Default Imports + +The set of default imports has been reduced to the following: + +```haskell +import Basics (..) +import Maybe ( Maybe( Just, Nothing ) ) +import Result ( Result( Ok, Err ) ) +import List ( List ) +import Signal ( Signal ) +``` + +### Make JSON parsing easy + + * Added `Json.Decode` and `Json.Encode` libraries + + +### Use more natural names + + * Rename `String.show` to `String.toString` + + * Replace `List.zip` with `List.map2 (,)` + * Replace `List.zipWith f` with `List.map2 f` + + * Rename `Signal.liftN` to `Signal.mapN` + * Rename `Signal.merges` to `Signal.mergeMany` + + +### Simplify Signal Library + + * Revamp `Input` concept as `Signal.Channel` + * Remove `Signal.count` + * Remove `Signal.countIf` + * Remove `Signal.combine` + + +### Randomness Done Right + + * No longer signal-based + * Use a `Generator` to create random values + + + +### Revamp Maybes and Error Handling + + * Add the following functions to `Maybe` + + withDefault : a -> Maybe a -> a + oneOf : List (Maybe a) -> Maybe a + map : (a -> b) -> Maybe a -> Maybe b + andThen : Maybe a -> (a -> Maybe b) -> Maybe b + + * Remove `Maybe.maybe` so `maybe 0 sqrt Nothing` becomes `withDefault 0 (map sqrt Nothing)` + + * Remove `Maybe.isJust` and `Maybe.isNothing` in favor of pattern matching + + * Add `Result` library for proper error handling. This is for cases when + you want a computation to succeed, but if there is a mistake, it should + produce a nice error message. + + * Remove `Either` in favor of `Result` or custom union types + + * Revamp functions that result in a `Maybe`. + + - Remove `Dict.getOrElse` and `Dict.getOrFail` in favor of `withDefault 0 (Dict.get key dict)` + - Remove `Array.getOrElse` and `Array.getOrFail` in favor of `withDefault 0 (Array.get index array)` + - Change `String.toInt : String -> Maybe Int` to `String.toInt : String -> Result String Int` + - Change `String.toFloat : String -> Maybe Float` to `String.toFloat : String -> Result String Float` + + +### Make appending more logical + + * Add the following functions to `Text`: + + empty : Text + append : Text -> Text -> Text + concat : [Text] -> Text + join : Text -> [Text] -> Text + + * Make the following changes in `List`: + - Replace `(++)` with `append` + - Remove `join` + +### Miscellaneous + + * Rename `Text.toText` to `Text.fromString` diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json b/part10/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json new file mode 100644 index 0000000..2f25729 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/elm-package.json @@ -0,0 +1,38 @@ +{ + "version": "5.1.1", + "summary": "Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Array", + "Basics", + "Bitwise", + "Char", + "Color", + "Date", + "Debug", + "Dict", + "Json.Decode", + "Json.Encode", + "List", + "Maybe", + "Platform", + "Platform.Cmd", + "Platform.Sub", + "Process", + "Random", + "Regex", + "Result", + "Set", + "String", + "Task", + "Time", + "Tuple" + ], + "native-modules": true, + "dependencies": {}, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm new file mode 100644 index 0000000..58ae2ba --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Array.elm @@ -0,0 +1,240 @@ +module Array exposing + ( Array + , empty, repeat, initialize, fromList + , isEmpty, length, push, append + , get, set + , slice, toList, toIndexedList + , map, indexedMap, filter, foldl, foldr + ) + +{-| A library for fast immutable arrays. The elements in an array must have the +same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast +reads, updates, and appends. + +# Arrays +@docs Array + +# Creating Arrays +@docs empty, repeat, initialize, fromList + +# Basics +@docs isEmpty, length, push, append + +# Get and Set +@docs get, set + +# Taking Arrays Apart +@docs slice, toList, toIndexedList + +# Mapping, Filtering, and Folding +@docs map, indexedMap, filter, foldl, foldr +-} + +import Native.Array +import Basics exposing (..) +import Maybe exposing (..) +import List + + +{-| Representation of fast immutable arrays. You can create arrays of integers +(`Array Int`) or strings (`Array String`) or any other type of value you can +dream up. +-} +type Array a = Array + + +{-| Initialize an array. `initialize n f` creates an array of length `n` with +the element at index `i` initialized to the result of `(f i)`. + + initialize 4 identity == fromList [0,1,2,3] + initialize 4 (\n -> n*n) == fromList [0,1,4,9] + initialize 4 (always 0) == fromList [0,0,0,0] +-} +initialize : Int -> (Int -> a) -> Array a +initialize = + Native.Array.initialize + + +{-| Creates an array with a given length, filled with a default element. + + repeat 5 0 == fromList [0,0,0,0,0] + repeat 3 "cat" == fromList ["cat","cat","cat"] + +Notice that `repeat 3 x` is the same as `initialize 3 (always x)`. +-} +repeat : Int -> a -> Array a +repeat n e = + initialize n (always e) + + +{-| Create an array from a list. +-} +fromList : List a -> Array a +fromList = + Native.Array.fromList + + +{-| Create a list of elements from an array. + + toList (fromList [3,5,8]) == [3,5,8] +-} +toList : Array a -> List a +toList = + Native.Array.toList + + +-- TODO: make this a native function. +{-| Create an indexed list from an array. Each element of the array will be +paired with its index. + + toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")] +-} +toIndexedList : Array a -> List (Int, a) +toIndexedList array = + List.map2 + (,) + (List.range 0 (Native.Array.length array - 1)) + (Native.Array.toList array) + + +{-| Apply a function on every element in an array. + + map sqrt (fromList [1,4,9]) == fromList [1,2,3] +-} +map : (a -> b) -> Array a -> Array b +map = + Native.Array.map + + +{-| Apply a function on every element with its index as first argument. + + indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10] +-} +indexedMap : (Int -> a -> b) -> Array a -> Array b +indexedMap = + Native.Array.indexedMap + + +{-| Reduce an array from the left. Read `foldl` as “fold from the left”. + + foldl (::) [] (fromList [1,2,3]) == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> Array a -> b +foldl = + Native.Array.foldl + + +{-| Reduce an array from the right. Read `foldr` as “fold from the right”. + + foldr (+) 0 (repeat 3 5) == 15 +-} +foldr : (a -> b -> b) -> b -> Array a -> b +foldr = + Native.Array.foldr + + +{-| Keep only elements that satisfy the predicate: + + filter isEven (fromList [1,2,3,4,5,6]) == (fromList [2,4,6]) +-} +filter : (a -> Bool) -> Array a -> Array a +filter isOkay arr = + let + update x xs = + if isOkay x then + Native.Array.push x xs + else + xs + in + Native.Array.foldl update Native.Array.empty arr + +{-| Return an empty array. + + length empty == 0 +-} +empty : Array a +empty = + Native.Array.empty + + +{-| Push an element to the end of an array. + + push 3 (fromList [1,2]) == fromList [1,2,3] +-} +push : a -> Array a -> Array a +push = + Native.Array.push + + +{-| Return Just the element at the index or Nothing if the index is out of range. + + get 0 (fromList [0,5,3]) == Just 0 + get 2 (fromList [0,5,3]) == Just 3 + get 5 (fromList [0,5,3]) == Nothing + get -1 (fromList [0,5,3]) == Nothing + +-} +get : Int -> Array a -> Maybe a +get i array = + if 0 <= i && i < Native.Array.length array then + Just (Native.Array.get i array) + else + Nothing + + +{-| Set the element at a particular index. Returns an updated array. +If the index is out of range, the array is unaltered. + + set 1 7 (fromList [1,2,3]) == fromList [1,7,3] +-} +set : Int -> a -> Array a -> Array a +set = + Native.Array.set + + +{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a +zero-based index where we will start our slice. The `end` is a zero-based index +that indicates the end of the slice. The slice extracts up to but not including +`end`. + + slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2] + slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3] + +Both the `start` and `end` indexes can be negative, indicating an offset from +the end of the array. + + slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3] + slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4] + +This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array` +-} +slice : Int -> Int -> Array a -> Array a +slice = + Native.Array.slice + + +{-| Return the length of an array. + + length (fromList [1,2,3]) == 3 +-} +length : Array a -> Int +length = + Native.Array.length + + +{-| Determine if an array is empty. + + isEmpty empty == True +-} +isEmpty : Array a -> Bool +isEmpty array = + length array == 0 + + +{-| Append two arrays to a new one. + + append (repeat 2 42) (repeat 3 81) == fromList [42,42,81,81,81] +-} +append : Array a -> Array a -> Array a +append = + Native.Array.append diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm new file mode 100644 index 0000000..2d06c86 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Basics.elm @@ -0,0 +1,650 @@ +module Basics exposing + ( (==), (/=) + , (<), (>), (<=), (>=), max, min, Order (..), compare + , not, (&&), (||), xor + , (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + , pi, cos, sin, tan, acos, asin, atan, atan2 + , round, floor, ceiling, truncate, toFloat + , degrees, radians, turns + , toPolar, fromPolar + , isNaN, isInfinite + , toString, (++) + , identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + ) + +{-| Tons of useful functions that get imported by default. + +# Equality +@docs (==), (/=) + +# Comparison + +These functions only work on `comparable` types. This includes numbers, +characters, strings, lists of comparable things, and tuples of comparable +things. Note that tuples with 7 or more elements are not comparable; why +are your tuples so big? + +@docs (<), (>), (<=), (>=), max, min, Order, compare + +# Booleans +@docs not, (&&), (||), xor + +# Mathematics +@docs (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e + +# Trigonometry +@docs pi, cos, sin, tan, acos, asin, atan, atan2 + +# Number Conversions +@docs round, floor, ceiling, truncate, toFloat + +# Angle Conversions +All angle conversions result in “standard Elm angles” +which happen to be radians. + +@docs degrees, radians, turns + +# Polar Coordinates +@docs toPolar, fromPolar + +# Floating Point Checks +@docs isNaN, isInfinite + +# Strings and Lists +@docs toString, (++) + +# Higher-Order Helpers +@docs identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry, Never, never + +-} + +import Native.Basics +import Native.Utils + + +{-| Convert radians to standard Elm angles (radians). -} +radians : Float -> Float +radians t = + t + + +{-| Convert degrees to standard Elm angles (radians). -} +degrees : Float -> Float +degrees = + Native.Basics.degrees + + +{-| Convert turns to standard Elm angles (radians). +One turn is equal to 360°. +-} +turns : Float -> Float +turns = + Native.Basics.turns + + +{-| Convert polar coordinates (r,θ) to Cartesian coordinates (x,y). -} +fromPolar : (Float,Float) -> (Float,Float) +fromPolar = + Native.Basics.fromPolar + + +{-| Convert Cartesian coordinates (x,y) to polar coordinates (r,θ). -} +toPolar : (Float,Float) -> (Float,Float) +toPolar = + Native.Basics.toPolar + + +{-|-} +(+) : number -> number -> number +(+) = + Native.Basics.add + + +{-|-} +(-) : number -> number -> number +(-) = + Native.Basics.sub + + +{-|-} +(*) : number -> number -> number +(*) = + Native.Basics.mul + + +{-| Floating point division. -} +(/) : Float -> Float -> Float +(/) = + Native.Basics.floatDiv + + +infixl 6 + +infixl 6 - +infixl 7 * +infixl 7 / +infixr 8 ^ + +infixl 7 // +infixl 7 % + + +{-| Integer division. The remainder is discarded. -} +(//) : Int -> Int -> Int +(//) = + Native.Basics.div + + +{-| Find the remainder after dividing one number by another. + + rem 11 4 == 3 + rem 12 4 == 0 + rem 13 4 == 1 + rem -1 4 == -1 +-} +rem : Int -> Int -> Int +rem = + Native.Basics.rem + + +{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic). + + 7 % 2 == 1 + -1 % 4 == 3 +-} +(%) : Int -> Int -> Int +(%) = + Native.Basics.mod + + +{-| Exponentiation + + 3^2 == 9 +-} +(^) : number -> number -> number +(^) = + Native.Basics.exp + + +{-|-} +cos : Float -> Float +cos = + Native.Basics.cos + + +{-|-} +sin : Float -> Float +sin = + Native.Basics.sin + + +{-|-} +tan : Float -> Float +tan = + Native.Basics.tan + + +{-|-} +acos : Float -> Float +acos = + Native.Basics.acos + + +{-|-} +asin : Float -> Float +asin = + Native.Basics.asin + + +{-| You probably do not want to use this. It takes `(y/x)` as the +argument, so there is no way to know whether the negative signs comes from +the `y` or `x`. Thus, the resulting angle is always between π/2 and -π/2 +(in quadrants I and IV). You probably want to use `atan2` instead. +-} +atan : Float -> Float +atan = + Native.Basics.atan + + +{-| This helps you find the angle of a Cartesian coordinate. +You will almost certainly want to use this instead of `atan`. +So `atan2 y x` computes *atan(y/x)* but also keeps track of which +quadrant the angle should really be in. The result will be between +π and -π, giving you the full range of angles. +-} +atan2 : Float -> Float -> Float +atan2 = + Native.Basics.atan2 + + +{-| Take the square root of a number. -} +sqrt : Float -> Float +sqrt = + Native.Basics.sqrt + + +{-| Negate a number. + + negate 42 == -42 + negate -42 == 42 + negate 0 == 0 +-} +negate : number -> number +negate = + Native.Basics.negate + + +{-| Take the absolute value of a number. -} +abs : number -> number +abs = + Native.Basics.abs + + +{-| Calculate the logarithm of a number with a given base. + + logBase 10 100 == 2 + logBase 2 256 == 8 +-} +logBase : Float -> Float -> Float +logBase = + Native.Basics.logBase + + +{-| Clamps a number within a given range. With the expression +`clamp 100 200 x` the results are as follows: + + 100 if x < 100 + x if 100 <= x < 200 + 200 if 200 <= x +-} +clamp : number -> number -> number -> number +clamp = + Native.Basics.clamp + + +{-| An approximation of pi. -} +pi : Float +pi = + Native.Basics.pi + + +{-| An approximation of e. -} +e : Float +e = + Native.Basics.e + + +{-| Check if values are “the same”. + +**Note:** Elm uses structural equality on tuples, records, and user-defined +union types. This means the values `(3, 4)` and `(3, 4)` are definitely equal. +This is not true in languages like JavaScript that use reference equality on +objects. + +**Note:** Equality (in the Elm sense) is not possible for certain types. For +example, the functions `(\n -> n + 1)` and `(\n -> 1 + n)` are “the +same” but detecting this in general is [undecidable][]. In a future +release, the compiler will detect when `(==)` is used with problematic +types and provide a helpful error message. This will require quite serious +infrastructure work that makes sense to batch with another big project, so the +stopgap is to crash as quickly as possible. Problematic types include functions +and JavaScript values like `Json.Encode.Value` which could contain functions +if passed through a port. + +[undecidable]: https://en.wikipedia.org/wiki/Undecidable_problem +-} +(==) : a -> a -> Bool +(==) = + Native.Basics.eq + + +{-| Check if values are not “the same”. + +So `(a /= b)` is the same as `(not (a == b))`. +-} +(/=) : a -> a -> Bool +(/=) = + Native.Basics.neq + + +{-|-} +(<) : comparable -> comparable -> Bool +(<) = + Native.Basics.lt + + +{-|-} +(>) : comparable -> comparable -> Bool +(>) = + Native.Basics.gt + + +{-|-} +(<=) : comparable -> comparable -> Bool +(<=) = + Native.Basics.le + + +{-|-} +(>=) : comparable -> comparable -> Bool +(>=) = + Native.Basics.ge + + +infix 4 == +infix 4 /= +infix 4 < +infix 4 > +infix 4 <= +infix 4 >= + + +{-| Compare any two comparable values. Comparable values include `String`, `Char`, +`Int`, `Float`, `Time`, or a list or tuple containing comparable values. +These are also the only values that work as `Dict` keys or `Set` members. +-} +compare : comparable -> comparable -> Order +compare = + Native.Basics.compare + + +{-| Represents the relative ordering of two things. +The relations are less than, equal to, and greater than. +-} +type Order = LT | EQ | GT + + +{-| Find the smaller of two comparables. -} +min : comparable -> comparable -> comparable +min = + Native.Basics.min + + +{-| Find the larger of two comparables. -} +max : comparable -> comparable -> comparable +max = + Native.Basics.max + + +{-| The logical AND operator. `True` if both inputs are `True`. + +**Note:** When used in the infix position, like `(left && right)`, the operator +short-circuits. This means if `left` is `False` we do not bother evaluating `right` +and just return `False` overall. +-} +(&&) : Bool -> Bool -> Bool +(&&) = + Native.Basics.and + + +{-| The logical OR operator. `True` if one or both inputs are `True`. + +**Note:** When used in the infix position, like `(left || right)`, the operator +short-circuits. This means if `left` is `True` we do not bother evaluating `right` +and just return `True` overall. +-} +(||) : Bool -> Bool -> Bool +(||) = + Native.Basics.or + + +infixr 3 && +infixr 2 || + + +{-| The exclusive-or operator. `True` if exactly one input is `True`. -} +xor : Bool -> Bool -> Bool +xor = + Native.Basics.xor + + +{-| Negate a boolean value. + + not True == False + not False == True +-} +not : Bool -> Bool +not = + Native.Basics.not + + +-- Conversions + +{-| Round a number to the nearest integer. -} +round : Float -> Int +round = + Native.Basics.round + + +{-| Truncate a number, rounding towards zero. -} +truncate : Float -> Int +truncate = + Native.Basics.truncate + + +{-| Floor function, rounding down. -} +floor : Float -> Int +floor = + Native.Basics.floor + + +{-| Ceiling function, rounding up. -} +ceiling : Float -> Int +ceiling = + Native.Basics.ceiling + + +{-| Convert an integer into a float. -} +toFloat : Int -> Float +toFloat = + Native.Basics.toFloat + + +{-| Determine whether a float is an undefined or unrepresentable number. +NaN stands for *not a number* and it is [a standardized part of floating point +numbers](http://en.wikipedia.org/wiki/NaN). + + isNaN (0/0) == True + isNaN (sqrt -1) == True + isNaN (1/0) == False -- infinity is a number + isNaN 1 == False +-} +isNaN : Float -> Bool +isNaN = + Native.Basics.isNaN + + +{-| Determine whether a float is positive or negative infinity. + + isInfinite (0/0) == False + isInfinite (sqrt -1) == False + isInfinite (1/0) == True + isInfinite 1 == False + +Notice that NaN is not infinite! For float `n` to be finite implies that +`not (isInfinite n || isNaN n)` evaluates to `True`. +-} +isInfinite : Float -> Bool +isInfinite = + Native.Basics.isInfinite + + +{-| Turn any kind of value into a string. When you view the resulting string +with `Text.fromString` it should look just like the value it came from. + + toString 42 == "42" + toString [1,2] == "[1,2]" + toString "he said, \"hi\"" == "\"he said, \\\"hi\\\"\"" +-} +toString : a -> String +toString = + Native.Utils.toString + + +{-| Put two appendable things together. This includes strings, lists, and text. + + "hello" ++ "world" == "helloworld" + [1,1,2] ++ [3,5,8] == [1,1,2,3,5,8] +-} +(++) : appendable -> appendable -> appendable +(++) = + Native.Utils.append + + +infixr 5 ++ + + +-- Function Helpers + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + not << isEven << sqrt + +You can think of this operator as equivalent to the following: + + (g << f) == (\x -> g (f x)) + +So our example expands out to something like this: + + \n -> not (isEven (sqrt n)) +-} +(<<) : (b -> c) -> (a -> b) -> (a -> c) +(<<) g f x = + g (f x) + + +{-| Function composition, passing results along in the suggested direction. For +example, the following code checks if the square root of a number is odd: + + sqrt >> isEven >> not + +This direction of function composition seems less pleasant than `(<<)` which +reads nicely in expressions like: `filter (not << isRegistered) students` +-} +(>>) : (a -> b) -> (b -> c) -> (a -> c) +(>>) f g x = + g (f x) + + +{-| Forward function application `x |> f == f x`. This function is useful +for avoiding parentheses and writing code in a more natural way. +Consider the following code to create a pentagon: + + scale 2 (move (10,10) (filled blue (ngon 5 30))) + +This can also be written as: + + ngon 5 30 + |> filled blue + |> move (10,10) + |> scale 2 +-} +(|>) : a -> (a -> b) -> b +(|>) x f = + f x + + +{-| Backward function application `f <| x == f x`. This function is useful for +avoiding parentheses. Consider the following code to create a text element: + + leftAligned (monospace (fromString "code")) + +This can also be written as: + + leftAligned <| monospace <| fromString "code" +-} +(<|) : (a -> b) -> a -> b +(<|) f x = + f x + + +infixr 9 << +infixl 9 >> +infixr 0 <| +infixl 0 |> + + +{-| Given a value, returns exactly the same value. This is called +[the identity function](http://en.wikipedia.org/wiki/Identity_function). +-} +identity : a -> a +identity x = + x + + +{-| Create a function that *always* returns the same value. Useful with +functions like `map`: + + List.map (always 0) [1,2,3,4,5] == [0,0,0,0,0] + + -- List.map (\_ -> 0) [1,2,3,4,5] == [0,0,0,0,0] + -- always = (\x _ -> x) +-} +always : a -> b -> a +always a _ = + a + + +{-| Flip the order of the first two arguments to a function. -} +flip : (a -> b -> c) -> (b -> a -> c) +flip f b a = + f a b + + +{-| Change how arguments are passed to a function. +This splits paired arguments into two separate arguments. +-} +curry : ((a,b) -> c) -> a -> b -> c +curry f a b = + f (a,b) + + +{-| Change how arguments are passed to a function. +This combines two arguments into a single pair. +-} +uncurry : (a -> b -> c) -> (a,b) -> c +uncurry f (a,b) = + f a b + + +{-| A value that can never happen! For context: + + - The boolean type `Bool` has two values: `True` and `False` + - The unit type `()` has one value: `()` + - The never type `Never` has no values! + +You may see it in the wild in `Html Never` which means this HTML will never +produce any messages. You would need to write an event handler like +`onClick ??? : Attribute Never` but how can we fill in the question marks?! +So there cannot be any event handlers on that HTML. + +You may also see this used with tasks that never fail, like `Task Never ()`. + +The `Never` type is useful for restricting *arguments* to a function. Maybe my +API can only accept HTML without event handlers, so I require `Html Never` and +users can give `Html msg` and everything will go fine. Generally speaking, you +do not want `Never` in your return types though. +-} +type Never = JustOneMore Never + + +{-| A function that can never be called. Seems extremely pointless, but it +*can* come in handy. Imagine you have some HTML that should never produce any +messages. And say you want to use it in some other HTML that *does* produce +messages. You could say: + + import Html exposing (..) + + embedHtml : Html Never -> Html msg + embedHtml staticStuff = + div [] + [ text "hello" + , Html.map never staticStuff + ] + +So the `never` function is basically telling the type system, make sure no one +ever calls me! +-} +never : Never -> a +never (JustOneMore nvr) = + never nvr diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm new file mode 100644 index 0000000..14c7a82 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Bitwise.elm @@ -0,0 +1,90 @@ +module Bitwise exposing + ( and, or, xor, complement + , shiftLeftBy, shiftRightBy, shiftRightZfBy + ) + +{-| Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation). + +# Basic Operations +@docs and, or, xor, complement + +# Bit Shifts +@docs shiftLeftBy, shiftRightBy, shiftRightZfBy +-} + +import Native.Bitwise + + +{-| Bitwise AND +-} +and : Int -> Int -> Int +and = + Native.Bitwise.and + + +{-| Bitwise OR +-} +or : Int -> Int -> Int +or = + Native.Bitwise.or + + +{-| Bitwise XOR +-} +xor : Int -> Int -> Int +xor = + Native.Bitwise.xor + + +{-| Flip each bit individually, often called bitwise NOT +-} +complement : Int -> Int +complement = + Native.Bitwise.complement + + +{-| Shift bits to the left by a given offset, filling new bits with zeros. +This can be used to multiply numbers by powers of two. + + shiftLeftBy 1 5 == 10 + shiftLeftBy 5 1 == 32 +-} +shiftLeftBy : Int -> Int -> Int +shiftLeftBy = + Native.Bitwise.shiftLeftBy + + +{-| Shift bits to the right by a given offset, filling new bits with +whatever is the topmost bit. This can be used to divide numbers by powers of two. + + shiftRightBy 1 32 == 16 + shiftRightBy 2 32 == 8 + shiftRightBy 1 -32 == -16 + +This is called an [arithmetic right shift][ars], often written (>>), and +sometimes called a sign-propagating right shift because it fills empty spots +with copies of the highest bit. + +[ars]: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift +-} +shiftRightBy : Int -> Int -> Int +shiftRightBy = + Native.Bitwise.shiftRightBy + + +{-| Shift bits to the right by a given offset, filling new bits with zeros. + + shiftRightZfBy 1 32 == 16 + shiftRightZfBy 2 32 == 8 + shiftRightZfBy 1 -32 == 2147483632 + +This is called an [logical right shift][lrs], often written (>>>), and +sometimes called a zero-fill right shift because it fills empty spots with +zeros. + +[lrs]: http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift +-} +shiftRightZfBy : Int -> Int -> Int +shiftRightZfBy = + Native.Bitwise.shiftRightZfBy + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm new file mode 100644 index 0000000..288f50b --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Char.elm @@ -0,0 +1,103 @@ +module Char exposing + ( isUpper, isLower, isDigit, isOctDigit, isHexDigit + , toUpper, toLower, toLocaleUpper, toLocaleLower + , KeyCode, toCode, fromCode + ) + +{-| Functions for working with characters. Character literals are enclosed in +`'a'` pair of single quotes. + +# Classification +@docs isUpper, isLower, isDigit, isOctDigit, isHexDigit + +# Conversion +@docs toUpper, toLower, toLocaleUpper, toLocaleLower + +# Key Codes +@docs KeyCode, toCode, fromCode + +-} + +import Native.Char +import Basics exposing ((&&), (||), (>=), (<=)) + + +isBetween : Char -> Char -> Char -> Bool +isBetween low high char = + let code = toCode char + in + (code >= toCode low) && (code <= toCode high) + + +{-| True for upper case ASCII letters. -} +isUpper : Char -> Bool +isUpper = + isBetween 'A' 'Z' + + +{-| True for lower case ASCII letters. -} +isLower : Char -> Bool +isLower = + isBetween 'a' 'z' + + +{-| True for ASCII digits `[0-9]`. -} +isDigit : Char -> Bool +isDigit = + isBetween '0' '9' + + +{-| True for ASCII octal digits `[0-7]`. -} +isOctDigit : Char -> Bool +isOctDigit = + isBetween '0' '7' + + +{-| True for ASCII hexadecimal digits `[0-9a-fA-F]`. -} +isHexDigit : Char -> Bool +isHexDigit char = + isDigit char || isBetween 'a' 'f' char || isBetween 'A' 'F' char + + +{-| Convert to upper case. -} +toUpper : Char -> Char +toUpper = + Native.Char.toUpper + + +{-| Convert to lower case. -} +toLower : Char -> Char +toLower = + Native.Char.toLower + + +{-| Convert to upper case, according to any locale-specific case mappings. -} +toLocaleUpper : Char -> Char +toLocaleUpper = + Native.Char.toLocaleUpper + + +{-| Convert to lower case, according to any locale-specific case mappings. -} +toLocaleLower : Char -> Char +toLocaleLower = + Native.Char.toLocaleLower + + +{-| Keyboard keys can be represented as integers. These are called *key codes*. +You can use [`toCode`](#toCode) and [`fromCode`](#fromCode) to convert between +key codes and characters. +-} +type alias KeyCode = Int + + +{-| Convert to key code. +-} +toCode : Char -> KeyCode +toCode = + Native.Char.toCode + + +{-| Convert from key code. -} +fromCode : KeyCode -> Char +fromCode = + Native.Char.fromCode diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm new file mode 100644 index 0000000..d150240 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Color.elm @@ -0,0 +1,456 @@ +module Color exposing + ( Color, rgb, rgba, hsl, hsla, greyscale, grayscale, complement + , Gradient, linear, radial + , toRgb, toHsl + , red, orange, yellow, green, blue, purple, brown + , lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + , darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + , white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + , lightGray, gray, darkGray + ) + +{-| Library for working with colors. Includes +[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and +[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and +built-in names. + +# Colors +@docs Color + +# Creation +@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement + +# Gradients +@docs Gradient, linear, radial + +# Extracting Colors +@docs toRgb, toHsl + +# Built-in Colors +These colors come from the [Tango +palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) +which provides aesthetically reasonable defaults for colors. Each color also +comes with a light and dark version. + +### Standard +@docs red, orange, yellow, green, blue, purple, brown + +### Light +@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + +### Dark +@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + +### Eight Shades of Grey +These colors are a compatible series of shades of grey, fitting nicely +with the Tango palette. +@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + +These are identical to the *grey* versions. It seems the spelling is regional, but +that has never helped me remember which one I should be writing. +@docs lightGray, gray, darkGray + +-} + +import Basics exposing (..) + + +{-| Representation of colors. +-} +type Color + = RGBA Int Int Int Float + | HSLA Float Float Float Float + + +{-| Create RGB colors with an alpha component for transparency. +The alpha component is specified with numbers between 0 and 1. -} +rgba : Int -> Int -> Int -> Float -> Color +rgba = + RGBA + + +{-| Create RGB colors from numbers between 0 and 255 inclusive. -} +rgb : Int -> Int -> Int -> Color +rgb r g b = + RGBA r g b 1 + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV) +with an alpha component for transparency. +-} +hsla : Float -> Float -> Float -> Float -> Color +hsla hue saturation lightness alpha = + HSLA (hue - turns (toFloat (floor (hue / (2*pi))))) saturation lightness alpha + + +{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives +you access to colors more like a color wheel, where all hues are arranged in a +circle that you specify with standard Elm angles (radians). + + red = hsl (degrees 0) 1 0.5 + green = hsl (degrees 120) 1 0.5 + blue = hsl (degrees 240) 1 0.5 + + pastelRed = hsl (degrees 0) 0.7 0.7 + +To cycle through all colors, just cycle through degrees. The saturation level +is how vibrant the color is, like a dial between grey and bright colors. The +lightness level is a dial between white and black. +-} +hsl : Float -> Float -> Float -> Color +hsl hue saturation lightness = + hsla hue saturation lightness 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +grayscale : Float -> Color +grayscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a gray based on the input. 0 is white, 1 is black. +-} +greyscale : Float -> Color +greyscale p = + HSLA 0 0 (1-p) 1 + + +{-| Produce a “complementary color”. The two colors will +accent each other. This is the same as rotating the hue by 180°. +-} +complement : Color -> Color +complement color = + case color of + HSLA h s l a -> + hsla (h + degrees 180) s l a + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + hsla (h + degrees 180) s l a + + +{-| Extract the components of a color in the HSL format. +-} +toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float } +toHsl color = + case color of + HSLA h s l a -> + { hue=h, saturation=s, lightness=l, alpha=a } + + RGBA r g b a -> + let + (h,s,l) = rgbToHsl r g b + in + { hue=h, saturation=s, lightness=l, alpha=a } + + +{-| Extract the components of a color in the RGB format. +-} +toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float } +toRgb color = + case color of + RGBA r g b a -> + { red = r, green = g, blue = b, alpha = a } + + HSLA h s l a -> + let + (r,g,b) = hslToRgb h s l + in + { red = round (255 * r) + , green = round (255 * g) + , blue = round (255 * b) + , alpha = a + } + + +fmod : Float -> Int -> Float +fmod f n = + let + integer = floor f + in + toFloat (integer % n) + f - toFloat integer + + +rgbToHsl : Int -> Int -> Int -> (Float,Float,Float) +rgbToHsl red green blue = + let + r = toFloat red / 255 + g = toFloat green / 255 + b = toFloat blue / 255 + + cMax = max (max r g) b + cMin = min (min r g) b + + c = cMax - cMin + + hue = + degrees 60 * + if cMax == r then + fmod ((g - b) / c) 6 + else if cMax == g then + ((b - r) / c) + 2 + else {- cMax == b -} + ((r - g) / c) + 4 + + lightness = + (cMax + cMin) / 2 + + saturation = + if lightness == 0 then + 0 + else + c / (1 - abs (2 * lightness - 1)) + in + (hue, saturation, lightness) + + +hslToRgb : Float -> Float -> Float -> (Float,Float,Float) +hslToRgb hue saturation lightness = + let + chroma = (1 - abs (2 * lightness - 1)) * saturation + normHue = hue / degrees 60 + + x = chroma * (1 - abs (fmod normHue 2 - 1)) + + (r,g,b) = + if normHue < 0 then (0, 0, 0) + else if normHue < 1 then (chroma, x, 0) + else if normHue < 2 then (x, chroma, 0) + else if normHue < 3 then (0, chroma, x) + else if normHue < 4 then (0, x, chroma) + else if normHue < 5 then (x, 0, chroma) + else if normHue < 6 then (chroma, 0, x) + else (0, 0, 0) + + m = lightness - chroma / 2 + in + (r + m, g + m, b + m) + + +--toV3 : Color -> V3 + +--toV4 : Color -> V4 + +{-| Abstract representation of a color gradient. +-} +type Gradient + = Linear (Float,Float) (Float,Float) (List (Float,Color)) + | Radial (Float,Float) Float (Float,Float) Float (List (Float,Color)) + + +{-| Create a linear gradient. Takes a start and end point and then a series of +“color stops” that indicate how to interpolate between the start and +end points. See [this example](http://elm-lang.org/examples/linear-gradient) for a +more visual explanation. +-} +linear : (Float, Float) -> (Float, Float) -> List (Float,Color) -> Gradient +linear = + Linear + + +{-| Create a radial gradient. First takes a start point and inner radius. Then +takes an end point and outer radius. It then takes a series of “color +stops” that indicate how to interpolate between the inner and outer +circles. See [this example](http://elm-lang.org/examples/radial-gradient) for a +more visual explanation. +-} +radial : (Float,Float) -> Float -> (Float,Float) -> Float -> List (Float,Color) -> Gradient +radial = + Radial + + +-- BUILT-IN COLORS + +{-|-} +lightRed : Color +lightRed = + RGBA 239 41 41 1 + + +{-|-} +red : Color +red = + RGBA 204 0 0 1 + + +{-|-} +darkRed : Color +darkRed = + RGBA 164 0 0 1 + + +{-|-} +lightOrange : Color +lightOrange = + RGBA 252 175 62 1 + + +{-|-} +orange : Color +orange = + RGBA 245 121 0 1 + + +{-|-} +darkOrange : Color +darkOrange = + RGBA 206 92 0 1 + + +{-|-} +lightYellow : Color +lightYellow = + RGBA 255 233 79 1 + + +{-|-} +yellow : Color +yellow = + RGBA 237 212 0 1 + + +{-|-} +darkYellow : Color +darkYellow = + RGBA 196 160 0 1 + + +{-|-} +lightGreen : Color +lightGreen = + RGBA 138 226 52 1 + + +{-|-} +green : Color +green = + RGBA 115 210 22 1 + + +{-|-} +darkGreen : Color +darkGreen = + RGBA 78 154 6 1 + + +{-|-} +lightBlue : Color +lightBlue = + RGBA 114 159 207 1 + + +{-|-} +blue : Color +blue = + RGBA 52 101 164 1 + + +{-|-} +darkBlue : Color +darkBlue = + RGBA 32 74 135 1 + + +{-|-} +lightPurple : Color +lightPurple = + RGBA 173 127 168 1 + + +{-|-} +purple : Color +purple = + RGBA 117 80 123 1 + + +{-|-} +darkPurple : Color +darkPurple = + RGBA 92 53 102 1 + + +{-|-} +lightBrown : Color +lightBrown = + RGBA 233 185 110 1 + + +{-|-} +brown : Color +brown = + RGBA 193 125 17 1 + + +{-|-} +darkBrown : Color +darkBrown = + RGBA 143 89 2 1 + + +{-|-} +black : Color +black = + RGBA 0 0 0 1 + + +{-|-} +white : Color +white = + RGBA 255 255 255 1 + + +{-|-} +lightGrey : Color +lightGrey = + RGBA 238 238 236 1 + + +{-|-} +grey : Color +grey = + RGBA 211 215 207 1 + + +{-|-} +darkGrey : Color +darkGrey = + RGBA 186 189 182 1 + + +{-|-} +lightGray : Color +lightGray = + RGBA 238 238 236 1 + + +{-|-} +gray : Color +gray = + RGBA 211 215 207 1 + + +{-|-} +darkGray : Color +darkGray = + RGBA 186 189 182 1 + + +{-|-} +lightCharcoal : Color +lightCharcoal = + RGBA 136 138 133 1 + + +{-|-} +charcoal : Color +charcoal = + RGBA 85 87 83 1 + + +{-|-} +darkCharcoal : Color +darkCharcoal = + RGBA 46 52 54 1 diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm new file mode 100644 index 0000000..0d62982 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Date.elm @@ -0,0 +1,150 @@ +module Date exposing + ( Date, fromString, toTime, fromTime + , year, month, Month(..) + , day, dayOfWeek, Day(..) + , hour, minute, second, millisecond + , now + ) + +{-| Library for working with dates. Email the mailing list if you encounter +issues with internationalization or locale formatting. + +# Dates +@docs Date, now + +# Conversions +@docs fromString, toTime, fromTime + +# Extractions +@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second, millisecond + +-} + +import Native.Date +import Task exposing (Task) +import Time exposing (Time) +import Result exposing (Result) + + + +-- DATES + + +{-| Representation of a date. +-} +type Date = Date + + +{-| Get the `Date` at the moment when this task is run. +-} +now : Task x Date +now = + Task.map fromTime Time.now + + + +-- CONVERSIONS AND EXTRACTIONS + + +{-| Represents the days of the week. +-} +type Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun + + +{-| Represents the month of the year. +-} +type Month + = Jan | Feb | Mar | Apr + | May | Jun | Jul | Aug + | Sep | Oct | Nov | Dec + + +{-| Attempt to read a date from a string. +-} +fromString : String -> Result String Date +fromString = + Native.Date.fromString + + +{-| Convert a `Date` to a time in milliseconds. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +toTime : Date -> Time +toTime = + Native.Date.toTime + + +{-| Convert a time in milliseconds into a `Date`. + +A time is the number of milliseconds since +[the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). +-} +fromTime : Time -> Date +fromTime = + Native.Date.fromTime + + +{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `1990`. +-} +year : Date -> Int +year = + Native.Date.year + + +{-| Extract the month of a given date. Given the date 23 June 1990 at 11:45AM +this returns the month `Jun` as defined below. +-} +month : Date -> Month +month = + Native.Date.month + + +{-| Extract the day of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `23`. +-} +day : Date -> Int +day = + Native.Date.day + + +{-| Extract the day of the week for a given date. Given the date 23 June +1990 at 11:45AM this returns the day `Sat` as defined below. +-} +dayOfWeek : Date -> Day +dayOfWeek = + Native.Date.dayOfWeek + + +{-| Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `11`. +-} +hour : Date -> Int +hour = + Native.Date.hour + + +{-| Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `45`. +-} +minute : Date -> Int +minute = + Native.Date.minute + + +{-| Extract the second of a given date. Given the date 23 June 1990 at 11:45AM +this returns the integer `0`. +-} +second : Date -> Int +second = + Native.Date.second + + +{-| Extract the millisecond of a given date. Given the date 23 June 1990 at 11:45:30.123AM +this returns the integer `123`. +-} +millisecond : Date -> Int +millisecond = + Native.Date.millisecond diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm new file mode 100644 index 0000000..49668f5 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Debug.elm @@ -0,0 +1,62 @@ +module Debug exposing + ( log + , crash + ) + +{-| This library is for investigating bugs or performance problems. It should +*not* be used in production code. + +# Debugging +@docs log, crash +-} + +import Native.Debug + + +{-| Log a tagged value on the developer console, and then return the value. + + 1 + log "number" 1 -- equals 2, logs "number: 1" + length (log "start" []) -- equals 0, logs "start: []" + +Notice that `log` is not a pure function! It should *only* be used for +investigating bugs or performance problems. +-} +log : String -> a -> a +log = + Native.Debug.log + + +{-| Crash the program with an error message. This is an uncatchable error, +intended for code that is soon-to-be-implemented. For example, if you are +working with a large ADT and have partially completed a case expression, it may +make sense to do this: + + type Entity = Ship | Fish | Captain | Seagull + + drawEntity entity = + case entity of + Ship -> + ... + + Fish -> + ... + + _ -> + Debug.crash "TODO" + +The Elm compiler recognizes each `Debug.crash` and when you run into it at +runtime, the error will point to the corresponding module name and line number. +For `case` expressions that ends with a wildcard pattern and a crash, it will +also show the value that snuck through. In our example, that'd be `Captain` or +`Seagull`. + +**Use this if** you want to do some testing while you are partway through +writing a function. + +**Do not use this if** you want to do some typical try-catch exception handling. +Use the [`Maybe`](Maybe) or [`Result`](Result) libraries instead. +-} +crash : String -> a +crash = + Native.Debug.crash + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm new file mode 100644 index 0000000..0bb9501 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Dict.elm @@ -0,0 +1,661 @@ +module Dict exposing + ( Dict + , empty, singleton, insert, update + , isEmpty, get, remove, member, size + , filter + , partition + , foldl, foldr, map + , union, intersect, diff, merge + , keys, values + , toList, fromList + ) + +{-| A dictionary mapping unique keys to values. The keys can be any comparable +type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or +lists of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Dictionaries +@docs Dict + +# Build +@docs empty, singleton, insert, update, remove + +# Query +@docs isEmpty, member, get, size + +# Lists +@docs keys, values, toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +# Combine +@docs union, intersect, diff, merge + +-} + + +import Basics exposing (..) +import Maybe exposing (..) +import List exposing (..) +import Native.Debug +import String + + + +-- DICTIONARIES + + +-- BBlack and NBlack should only be used during the deletion +-- algorithm. Any other occurrence is a bug and should fail an assert. +type NColor + = Red + | Black + | BBlack -- Double Black, counts as 2 blacks for the invariant + | NBlack -- Negative Black, counts as -1 blacks for the invariant + + +type LeafColor + = LBlack + | LBBlack -- Double Black, counts as 2 + + +{-| A dictionary of keys and values. So a `(Dict String User)` is a dictionary +that lets you look up a `String` (such as user names) and find the associated +`User`. +-} +type Dict k v + = RBNode_elm_builtin NColor k v (Dict k v) (Dict k v) + | RBEmpty_elm_builtin LeafColor + + +{-| Create an empty dictionary. -} +empty : Dict k v +empty = + RBEmpty_elm_builtin LBlack + + +maxWithDefault : k -> v -> Dict k v -> (k, v) +maxWithDefault k v r = + case r of + RBEmpty_elm_builtin _ -> + (k, v) + + RBNode_elm_builtin _ kr vr _ rr -> + maxWithDefault kr vr rr + + +{-| Get the value associated with a key. If the key is not found, return +`Nothing`. This is useful when you are not sure if a key will be in the +dictionary. + + animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ] + + get "Tom" animals == Just Cat + get "Jerry" animals == Just Mouse + get "Spike" animals == Nothing + +-} +get : comparable -> Dict comparable v -> Maybe v +get targetKey dict = + case dict of + RBEmpty_elm_builtin _ -> + Nothing + + RBNode_elm_builtin _ key value left right -> + case compare targetKey key of + LT -> + get targetKey left + + EQ -> + Just value + + GT -> + get targetKey right + + +{-| Determine if a key is in a dictionary. -} +member : comparable -> Dict comparable v -> Bool +member key dict = + case get key dict of + Just _ -> + True + + Nothing -> + False + + +{-| Determine the number of key-value pairs in the dictionary. -} +size : Dict k v -> Int +size dict = + sizeHelp 0 dict + + +sizeHelp : Int -> Dict k v -> Int +sizeHelp n dict = + case dict of + RBEmpty_elm_builtin _ -> + n + + RBNode_elm_builtin _ _ _ left right -> + sizeHelp (sizeHelp (n+1) right) left + + +{-| Determine if a dictionary is empty. + + isEmpty empty == True +-} +isEmpty : Dict k v -> Bool +isEmpty dict = + dict == empty + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + red node => black node + black node => same + bblack node => xxx + nblack node => xxx + + black leaf => same + bblack leaf => xxx +-} +ensureBlackRoot : Dict k v -> Dict k v +ensureBlackRoot dict = + case dict of + RBNode_elm_builtin Red key value left right -> + RBNode_elm_builtin Black key value left right + + _ -> + dict + + +{-| Insert a key-value pair into a dictionary. Replaces value when there is +a collision. -} +insert : comparable -> v -> Dict comparable v -> Dict comparable v +insert key value dict = + update key (always (Just value)) dict + + +{-| Remove a key-value pair from a dictionary. If the key is not found, +no changes are made. -} +remove : comparable -> Dict comparable v -> Dict comparable v +remove key dict = + update key (always Nothing) dict + + +type Flag = Insert | Remove | Same + + +{-| Update the value of a dictionary for a specific key with a given function. -} +update : comparable -> (Maybe v -> Maybe v) -> Dict comparable v -> Dict comparable v +update k alter dict = + let + up dict = + case dict of + -- expecting only black nodes, never double black nodes here + RBEmpty_elm_builtin _ -> + case alter Nothing of + Nothing -> + (Same, empty) + + Just v -> + (Insert, RBNode_elm_builtin Red k v empty empty) + + RBNode_elm_builtin clr key value left right -> + case compare k key of + EQ -> + case alter (Just value) of + Nothing -> + (Remove, rem clr left right) + + Just newValue -> + (Same, RBNode_elm_builtin clr key newValue left right) + + LT -> + let (flag, newLeft) = up left in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value newLeft right) + + Insert -> + (Insert, balance clr key value newLeft right) + + Remove -> + (Remove, bubble clr key value newLeft right) + + GT -> + let (flag, newRight) = up right in + case flag of + Same -> + (Same, RBNode_elm_builtin clr key value left newRight) + + Insert -> + (Insert, balance clr key value left newRight) + + Remove -> + (Remove, bubble clr key value left newRight) + + (flag, updatedDict) = + up dict + in + case flag of + Same -> + updatedDict + + Insert -> + ensureBlackRoot updatedDict + + Remove -> + blacken updatedDict + + +{-| Create a dictionary with one key-value pair. -} +singleton : comparable -> v -> Dict comparable v +singleton key value = + insert key value empty + + + +-- HELPERS + + +isBBlack : Dict k v -> Bool +isBBlack dict = + case dict of + RBNode_elm_builtin BBlack _ _ _ _ -> + True + + RBEmpty_elm_builtin LBBlack -> + True + + _ -> + False + + +moreBlack : NColor -> NColor +moreBlack color = + case color of + Black -> + BBlack + + Red -> + Black + + NBlack -> + Red + + BBlack -> + Native.Debug.crash "Can't make a double black node more black!" + + +lessBlack : NColor -> NColor +lessBlack color = + case color of + BBlack -> + Black + + Black -> + Red + + Red -> + NBlack + + NBlack -> + Native.Debug.crash "Can't make a negative black node less black!" + + +{- The actual pattern match here is somewhat lax. If it is given invalid input, +it will do the wrong thing. The expected behavior is: + + node => less black node + + bblack leaf => black leaf + black leaf => xxx +-} +lessBlackTree : Dict k v -> Dict k v +lessBlackTree dict = + case dict of + RBNode_elm_builtin c k v l r -> + RBNode_elm_builtin (lessBlack c) k v l r + + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + +reportRemBug : String -> NColor -> String -> String -> a +reportRemBug msg c lgot rgot = + Native.Debug.crash <| + String.concat + [ "Internal red-black tree invariant violated, expected " + , msg, " and got ", toString c, "/", lgot, "/", rgot + , "\nPlease report this bug to " + ] + + +-- Remove the top node from the tree, may leave behind BBlacks +rem : NColor -> Dict k v -> Dict k v -> Dict k v +rem color left right = + case (left, right) of + (RBEmpty_elm_builtin _, RBEmpty_elm_builtin _) -> + case color of + Red -> + RBEmpty_elm_builtin LBlack + + Black -> + RBEmpty_elm_builtin LBBlack + + _ -> + Native.Debug.crash "cannot have bblack or nblack nodes at this point" + + (RBEmpty_elm_builtin cl, RBNode_elm_builtin cr k v l r) -> + case (color, cl, cr) of + (Black, LBlack, Red) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/LBlack/Red" color (toString cl) (toString cr) + + (RBNode_elm_builtin cl k v l r, RBEmpty_elm_builtin cr) -> + case (color, cl, cr) of + (Black, Red, LBlack) -> + RBNode_elm_builtin Black k v l r + + _ -> + reportRemBug "Black/Red/LBlack" color (toString cl) (toString cr) + + -- l and r are both RBNodes + (RBNode_elm_builtin cl kl vl ll rl, RBNode_elm_builtin _ _ _ _ _) -> + let + (k, v) = + maxWithDefault kl vl rl + + newLeft = + removeMax cl kl vl ll rl + in + bubble color k v newLeft right + + +-- Kills a BBlack or moves it upward, may leave behind NBlack +bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +bubble c k v l r = + if isBBlack l || isBBlack r then + balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r) + + else + RBNode_elm_builtin c k v l r + + +-- Removes rightmost node, may leave root as BBlack +removeMax : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +removeMax c k v l r = + case r of + RBEmpty_elm_builtin _ -> + rem c l r + + RBNode_elm_builtin cr kr vr lr rr -> + bubble c k v l (removeMax cr kr vr lr rr) + + +-- generalized tree balancing act +balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v +balance c k v l r = + let + tree = + RBNode_elm_builtin c k v l r + in + if blackish tree then + balanceHelp tree + + else + tree + + +blackish : Dict k v -> Bool +blackish t = + case t of + RBNode_elm_builtin c _ _ _ _ -> + c == Black || c == BBlack + + RBEmpty_elm_builtin _ -> + True + + +balanceHelp : Dict k v -> Dict k v +balanceHelp tree = + case tree of + -- double red: left, left + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red yk yv (RBNode_elm_builtin Red xk xv a b) c) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: left, right + RBNode_elm_builtin col zk zv (RBNode_elm_builtin Red xk xv a (RBNode_elm_builtin Red yk yv b c)) d -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, left + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red zk zv (RBNode_elm_builtin Red yk yv b c) d) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- double red: right, right + RBNode_elm_builtin col xk xv a (RBNode_elm_builtin Red yk yv b (RBNode_elm_builtin Red zk zv c d)) -> + balancedTree col xk xv yk yv zk zv a b c d + + -- handle double blacks + RBNode_elm_builtin BBlack xk xv a (RBNode_elm_builtin NBlack zk zv (RBNode_elm_builtin Black yk yv b c) (RBNode_elm_builtin Black _ _ _ _ as d)) -> + RBNode_elm_builtin Black yk yv (RBNode_elm_builtin Black xk xv a b) (balance Black zk zv c (redden d)) + + RBNode_elm_builtin BBlack zk zv (RBNode_elm_builtin NBlack xk xv (RBNode_elm_builtin Black _ _ _ _ as a) (RBNode_elm_builtin Black yk yv b c)) d -> + RBNode_elm_builtin Black yk yv (balance Black xk xv (redden a) b) (RBNode_elm_builtin Black zk zv c d) + + _ -> + tree + + +balancedTree : NColor -> k -> v -> k -> v -> k -> v -> Dict k v -> Dict k v -> Dict k v -> Dict k v -> Dict k v +balancedTree col xk xv yk yv zk zv a b c d = + RBNode_elm_builtin + (lessBlack col) + yk + yv + (RBNode_elm_builtin Black xk xv a b) + (RBNode_elm_builtin Black zk zv c d) + + +-- make the top node black +blacken : Dict k v -> Dict k v +blacken t = + case t of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Black k v l r + + +-- make the top node red +redden : Dict k v -> Dict k v +redden t = + case t of + RBEmpty_elm_builtin _ -> + Native.Debug.crash "can't make a Leaf red" + + RBNode_elm_builtin _ k v l r -> + RBNode_elm_builtin Red k v l r + + + +-- COMBINE + + +{-| Combine two dictionaries. If there is a collision, preference is given +to the first dictionary. +-} +union : Dict comparable v -> Dict comparable v -> Dict comparable v +union t1 t2 = + foldl insert t2 t1 + + +{-| Keep a key-value pair when its key appears in the second dictionary. +Preference is given to values in the first dictionary. +-} +intersect : Dict comparable v -> Dict comparable v -> Dict comparable v +intersect t1 t2 = + filter (\k _ -> member k t2) t1 + + +{-| Keep a key-value pair when its key does not appear in the second dictionary. +-} +diff : Dict comparable v -> Dict comparable v -> Dict comparable v +diff t1 t2 = + foldl (\k v t -> remove k t) t1 t2 + + +{-| The most general way of combining two dictionaries. You provide three +accumulators for when a given key appears: + + 1. Only in the left dictionary. + 2. In both dictionaries. + 3. Only in the right dictionary. + +You then traverse all the keys from lowest to highest, building up whatever +you want. +-} +merge + : (comparable -> a -> result -> result) + -> (comparable -> a -> b -> result -> result) + -> (comparable -> b -> result -> result) + -> Dict comparable a + -> Dict comparable b + -> result + -> result +merge leftStep bothStep rightStep leftDict rightDict initialResult = + let + stepState rKey rValue (list, result) = + case list of + [] -> + (list, rightStep rKey rValue result) + + (lKey, lValue) :: rest -> + if lKey < rKey then + stepState rKey rValue (rest, leftStep lKey lValue result) + + else if lKey > rKey then + (list, rightStep rKey rValue result) + + else + (rest, bothStep lKey lValue rValue result) + + (leftovers, intermediateResult) = + foldl stepState (toList leftDict, initialResult) rightDict + in + List.foldl (\(k,v) result -> leftStep k v result) intermediateResult leftovers + + + +-- TRANSFORM + + +{-| Apply a function to all values in a dictionary. +-} +map : (comparable -> a -> b) -> Dict comparable a -> Dict comparable b +map f dict = + case dict of + RBEmpty_elm_builtin _ -> + RBEmpty_elm_builtin LBlack + + RBNode_elm_builtin clr key value left right -> + RBNode_elm_builtin clr key (f key value) (map f left) (map f right) + + +{-| Fold over the key-value pairs in a dictionary, in order from lowest +key to highest key. +-} +foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldl f acc dict = + case dict of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldl f (f key value (foldl f acc left)) right + + +{-| Fold over the key-value pairs in a dictionary, in order from highest +key to lowest key. +-} +foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b +foldr f acc t = + case t of + RBEmpty_elm_builtin _ -> + acc + + RBNode_elm_builtin _ key value left right -> + foldr f (f key value (foldr f acc right)) left + + +{-| Keep a key-value pair when it satisfies a predicate. -} +filter : (comparable -> v -> Bool) -> Dict comparable v -> Dict comparable v +filter predicate dictionary = + let + add key value dict = + if predicate key value then + insert key value dict + + else + dict + in + foldl add empty dictionary + + +{-| Partition a dictionary according to a predicate. The first dictionary +contains all key-value pairs which satisfy the predicate, and the second +contains the rest. +-} +partition : (comparable -> v -> Bool) -> Dict comparable v -> (Dict comparable v, Dict comparable v) +partition predicate dict = + let + add key value (t1, t2) = + if predicate key value then + (insert key value t1, t2) + + else + (t1, insert key value t2) + in + foldl add (empty, empty) dict + + + +-- LISTS + + +{-| Get all of the keys in a dictionary, sorted from lowest to highest. + + keys (fromList [(0,"Alice"),(1,"Bob")]) == [0,1] +-} +keys : Dict comparable v -> List comparable +keys dict = + foldr (\key value keyList -> key :: keyList) [] dict + + +{-| Get all of the values in a dictionary, in the order of their keys. + + values (fromList [(0,"Alice"),(1,"Bob")]) == ["Alice", "Bob"] +-} +values : Dict comparable v -> List v +values dict = + foldr (\key value valueList -> value :: valueList) [] dict + + +{-| Convert a dictionary into an association list of key-value pairs, sorted by keys. -} +toList : Dict comparable v -> List (comparable,v) +toList dict = + foldr (\key value list -> (key,value) :: list) [] dict + + +{-| Convert an association list into a dictionary. -} +fromList : List (comparable,v) -> Dict comparable v +fromList assocs = + List.foldl (\(key,value) dict -> insert key value dict) empty assocs diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm new file mode 100644 index 0000000..0fc853d --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Decode.elm @@ -0,0 +1,520 @@ +module Json.Decode exposing + ( Decoder, string, bool, int, float + , nullable, list, array, dict, keyValuePairs + , field, at, index + , maybe, oneOf + , decodeString, decodeValue, Value + , map, map2, map3, map4, map5, map6, map7, map8 + , lazy, value, null, succeed, fail, andThen + ) + +{-| Turn JSON values into Elm values. Definitely check out this [intro to +JSON decoders][guide] to get a feel for how this library works! + +[guide]: https://guide.elm-lang.org/interop/json.html + +# Primitives +@docs Decoder, string, bool, int, float + +# Data Structures +@docs nullable, list, array, dict, keyValuePairs + +# Object Primitives +@docs field, at, index + +# Inconsistent Structure +@docs maybe, oneOf + +# Run Decoders +@docs decodeString, decodeValue, Value + +# Mapping + +**Note:** If you run out of map functions, take a look at [elm-decode-pipeline][pipe] +which makes it easier to handle large objects, but produces lower quality type +errors. + +[pipe]: http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest + +@docs map, map2, map3, map4, map5, map6, map7, map8 + +# Fancy Decoding +@docs lazy, value, null, succeed, fail, andThen +-} + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Encode as JsEncode +import List +import Maybe exposing (Maybe(..)) +import Result exposing (Result(..)) +import Native.Json + + + +-- PRIMITIVES + + +{-| A value that knows how to decode JSON values. +-} +type Decoder a = Decoder + + +{-| Decode a JSON string into an Elm `String`. + + decodeString string "true" == Err ... + decodeString string "42" == Err ... + decodeString string "3.14" == Err ... + decodeString string "\"hello\"" == Ok "hello" + decodeString string "{ \"hello\": 42 }" == Err ... +-} +string : Decoder String +string = + Native.Json.decodePrimitive "string" + + +{-| Decode a JSON boolean into an Elm `Bool`. + + decodeString bool "true" == Ok True + decodeString bool "42" == Err ... + decodeString bool "3.14" == Err ... + decodeString bool "\"hello\"" == Err ... + decodeString bool "{ \"hello\": 42 }" == Err ... +-} +bool : Decoder Bool +bool = + Native.Json.decodePrimitive "bool" + + +{-| Decode a JSON number into an Elm `Int`. + + decodeString int "true" == Err ... + decodeString int "42" == Ok 42 + decodeString int "3.14" == Err ... + decodeString int "\"hello\"" == Err ... + decodeString int "{ \"hello\": 42 }" == Err ... +-} +int : Decoder Int +int = + Native.Json.decodePrimitive "int" + + +{-| Decode a JSON number into an Elm `Float`. + + decodeString float "true" == Err .. + decodeString float "42" == Ok 42 + decodeString float "3.14" == Ok 3.14 + decodeString float "\"hello\"" == Err ... + decodeString float "{ \"hello\": 42 }" == Err ... +-} +float : Decoder Float +float = + Native.Json.decodePrimitive "float" + + + +-- DATA STRUCTURES + + +{-| Decode a nullable JSON value into an Elm value. + + decodeString (nullable int) "13" == Ok (Just 13) + decodeString (nullable int) "42" == Ok (Just 42) + decodeString (nullable int) "null" == Ok Nothing + decodeString (nullable int) "true" == Err .. +-} +nullable : Decoder a -> Decoder (Maybe a) +nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] + + +{-| Decode a JSON array into an Elm `List`. + + decodeString (list int) "[1,2,3]" == Ok [1,2,3] + decodeString (list bool) "[true,false]" == Ok [True,False] +-} +list : Decoder a -> Decoder (List a) +list decoder = + Native.Json.decodeContainer "list" decoder + + +{-| Decode a JSON array into an Elm `Array`. + + decodeString (array int) "[1,2,3]" == Ok (Array.fromList [1,2,3]) + decodeString (array bool) "[true,false]" == Ok (Array.fromList [True,False]) +-} +array : Decoder a -> Decoder (Array a) +array decoder = + Native.Json.decodeContainer "array" decoder + + +{-| Decode a JSON object into an Elm `Dict`. + + decodeString (dict int) "{ \"alice\": 42, \"bob\": 99 }" + == Dict.fromList [("alice", 42), ("bob", 99)] +-} +dict : Decoder a -> Decoder (Dict String a) +dict decoder = + map Dict.fromList (keyValuePairs decoder) + + +{-| Decode a JSON object into an Elm `List` of pairs. + + decodeString (keyValuePairs int) "{ \"alice\": 42, \"bob\": 99 }" + == [("alice", 42), ("bob", 99)] +-} +keyValuePairs : Decoder a -> Decoder (List (String, a)) +keyValuePairs = + Native.Json.decodeKeyValuePairs + + + +-- OBJECT PRIMITIVES + + +{-| Decode a JSON object, requiring a particular field. + + decodeString (field "x" int) "{ \"x\": 3 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": 3, \"y\": 4 }" == Ok 3 + decodeString (field "x" int) "{ \"x\": true }" == Err ... + decodeString (field "x" int) "{ \"y\": 4 }" == Err ... + + decodeString (field "name" string) "{ \"name\": \"tom\" }" == Ok "tom" + +The object *can* have other fields. Lots of them! The only thing this decoder +cares about is if `x` is present and that the value there is an `Int`. + +Check out [`map2`](#map2) to see how to decode multiple fields! +-} +field : String -> Decoder a -> Decoder a +field = + Native.Json.decodeField + + +{-| Decode a nested JSON object, requiring certain fields. + + json = """{ "person": { "name": "tom", "age": 42 } }""" + + decodeString (at ["person", "name"] string) json == Ok "tom" + decodeString (at ["person", "age" ] int ) json == Ok "42 + +This is really just a shorthand for saying things like: + + field "person" (field "name" string) == at ["person","name"] string +-} +at : List String -> Decoder a -> Decoder a +at fields decoder = + List.foldr field decoder fields + + +{-| Decode a JSON array, requiring a particular index. + + json = """[ "alice", "bob", "chuck" ]""" + + decodeString (index 0 string) json == Ok "alice" + decodeString (index 1 string) json == Ok "bob" + decodeString (index 2 string) json == Ok "chuck" + decodeString (index 3 string) json == Err ... +-} +index : Int -> Decoder a -> Decoder a +index = + Native.Json.decodeIndex + + + +-- WEIRD STRUCTURE + + +{-| Helpful for dealing with optional fields. Here are a few slightly different +examples: + + json = """{ "name": "tom", "age": 42 }""" + + decodeString (maybe (field "age" int )) json == Ok (Just 42) + decodeString (maybe (field "name" int )) json == Ok Nothing + decodeString (maybe (field "height" float)) json == Ok Nothing + + decodeString (field "age" (maybe int )) json == Ok (Just 42) + decodeString (field "name" (maybe int )) json == Ok Nothing + decodeString (field "height" (maybe float)) json == Err ... + +Notice the last example! It is saying we *must* have a field named `height` and +the content *may* be a float. There is no `height` field, so the decoder fails. + +Point is, `maybe` will make exactly what it contains conditional. For optional +fields, this means you probably want it *outside* a use of `field` or `at`. +-} +maybe : Decoder a -> Decoder (Maybe a) +maybe decoder = + Native.Json.decodeContainer "maybe" decoder + + +{-| Try a bunch of different decoders. This can be useful if the JSON may come +in a couple different formats. For example, say you want to read an array of +numbers, but some of them are `null`. + + import String + + badInt : Decoder Int + badInt = + oneOf [ int, null 0 ] + + -- decodeString (list badInt) "[1,2,null,4]" == Ok [1,2,0,4] + +Why would someone generate JSON like this? Questions like this are not good +for your health. The point is that you can use `oneOf` to handle situations +like this! + +You could also use `oneOf` to help version your data. Try the latest format, +then a few older ones that you still support. You could use `andThen` to be +even more particular if you wanted. +-} +oneOf : List (Decoder a) -> Decoder a +oneOf = + Native.Json.oneOf + + + +-- MAPPING + + +{-| Transform a decoder. Maybe you just want to know the length of a string: + + import String + + stringLength : Decoder Int + stringLength = + map String.length string + +It is often helpful to use `map` with `oneOf`, like when defining `nullable`: + + nullable : Decoder a -> Decoder (Maybe a) + nullable decoder = + oneOf + [ null Nothing + , map Just decoder + ] +-} +map : (a -> value) -> Decoder a -> Decoder value +map = + Native.Json.map1 + + +{-| Try two decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Point = { x : Float, y : Float } + + point : Decoder Point + point = + map2 Point + (field "x" float) + (field "y" float) + + -- decodeString point """{ "x": 3, "y": 4 }""" == Ok { x = 3, y = 4 } + +It tries each individual decoder and puts the result together with the `Point` +constructor. +-} +map2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value +map2 = + Native.Json.map2 + + +{-| Try three decoders and then combine the result. We can use this to decode +objects with many fields: + + type alias Person = { name : String, age : Int, height : Float } + + person : Decoder Person + person = + map3 Person + (at ["name"] string) + (at ["info","age"] int) + (at ["info","height"] float) + + -- json = """{ "name": "tom", "info": { "age": 42, "height": 1.8 } }""" + -- decodeString person json == Ok { name = "tom", age = 42, height = 1.8 } + +Like `map2` it tries each decoder in order and then give the results to the +`Person` constructor. That can be any function though! +-} +map3 : (a -> b -> c -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder value +map3 = + Native.Json.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder value +map4 = + Native.Json.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder value +map5 = + Native.Json.map5 + + +{-|-} +map6 : (a -> b -> c -> d -> e -> f -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder value +map6 = + Native.Json.map6 + + +{-|-} +map7 : (a -> b -> c -> d -> e -> f -> g -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder value +map7 = + Native.Json.map7 + + +{-|-} +map8 : (a -> b -> c -> d -> e -> f -> g -> h -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder h -> Decoder value +map8 = + Native.Json.map8 + + + +-- RUN DECODERS + + +{-| Parse the given string into a JSON value and then run the `Decoder` on it. +This will fail if the string is not well-formed JSON or if the `Decoder` +fails for some reason. + + decodeString int "4" == Ok 4 + decodeString int "1 + 2" == Err ... +-} +decodeString : Decoder a -> String -> Result String a +decodeString = + Native.Json.runOnString + + +{-| Run a `Decoder` on some JSON `Value`. You can send these JSON values +through ports, so that is probably the main time you would use this function. +-} +decodeValue : Decoder a -> Value -> Result String a +decodeValue = + Native.Json.run + + +{-| A JSON value. +-} +type alias Value = JsEncode.Value + + + +-- FANCY PRIMITIVES + + +{-| Ignore the JSON and produce a certain Elm value. + + decodeString (succeed 42) "true" == Ok 42 + decodeString (succeed 42) "[1,2,3]" == Ok 42 + decodeString (succeed 42) "hello" == Err ... -- this is not a valid JSON string + +This is handy when used with `oneOf` or `andThen`. +-} +succeed : a -> Decoder a +succeed = + Native.Json.succeed + + +{-| Ignore the JSON and make the decoder fail. This is handy when used with +`oneOf` or `andThen` where you want to give a custom error message in some +case. + +See the [`andThen`](#andThen) docs for an example. +-} +fail : String -> Decoder a +fail = + Native.Json.fail + + +{-| Create decoders that depend on previous results. If you are creating +versioned data, you might do something like this: + + info : Decoder Info + info = + field "version" int + |> andThen infoHelp + + infoHelp : Int -> Decoder Info + infoHelp version = + case version of + 4 -> + infoDecoder4 + + 3 -> + infoDecoder3 + + _ -> + fail <| + "Trying to decode info, but version " + ++ toString version ++ " is not supported." + + -- infoDecoder4 : Decoder Info + -- infoDecoder3 : Decoder Info +-} +andThen : (a -> Decoder b) -> Decoder a -> Decoder b +andThen = + Native.Json.andThen + + +{-| Sometimes you have JSON with recursive structure, like nested comments. +You can use `lazy` to make sure your decoder unrolls lazily. + + type alias Comment = + { message : String + , responses : Responses + } + + type Responses = Responses (List Comment) + + comment : Decoder Comment + comment = + map2 Comment + (field "message" string) + (field "responses" (map Responses (list (lazy (\_ -> comment))))) + +If we had said `list comment` instead, we would start expanding the value +infinitely. What is a `comment`? It is a decoder for objects where the +`responses` field contains comments. What is a `comment` though? Etc. + +By using `list (lazy (\_ -> comment))` we make sure the decoder only expands +to be as deep as the JSON we are given. You can read more about recursive data +structures [here][]. + +[here]: https://github.com/elm-lang/elm-compiler/blob/master/hints/recursive-alias.md +-} +lazy : (() -> Decoder a) -> Decoder a +lazy thunk = + andThen thunk (succeed ()) + + +{-| Do not do anything with a JSON value, just bring it into Elm as a `Value`. +This can be useful if you have particularly crazy data that you would like to +deal with later. Or if you are going to send it out a port and do not care +about its structure. +-} +value : Decoder Value +value = + Native.Json.decodePrimitive "value" + + +{-| Decode a `null` value into some Elm value. + + decodeString (null False) "null" == Ok False + decodeString (null 42) "null" == Ok 42 + decodeString (null 42) "42" == Err .. + decodeString (null 42) "false" == Err .. + +So if you ever see a `null`, this will return whatever value you specified. +-} +null : a -> Decoder a +null = + Native.Json.decodeNull diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm new file mode 100644 index 0000000..29e6fc9 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Json/Encode.elm @@ -0,0 +1,102 @@ +module Json.Encode exposing + ( Value + , encode + , string, int, float, bool, null + , list, array + , object + ) + +{-| Library for turning Elm values into Json values. + +# Encoding +@docs encode, Value + +# Primitives +@docs string, int, float, bool, null + +# Arrays +@docs list, array + +# Objects +@docs object +-} + +import Array exposing (Array) +import Native.Json + + +{-| Represents a JavaScript value. +-} +type Value = Value + + +{-| Convert a `Value` into a prettified string. The first argument specifies +the amount of indentation in the resulting string. + + person = + object + [ ("name", string "Tom") + , ("age", int 42) + ] + + compact = encode 0 person + -- {"name":"Tom","age":42} + + readable = encode 4 person + -- { + -- "name": "Tom", + -- "age": 42 + -- } +-} +encode : Int -> Value -> String +encode = + Native.Json.encode + + +{-|-} +string : String -> Value +string = + Native.Json.identity + + +{-|-} +int : Int -> Value +int = + Native.Json.identity + + +{-| Encode a Float. `Infinity` and `NaN` are encoded as `null`. +-} +float : Float -> Value +float = + Native.Json.identity + + +{-|-} +bool : Bool -> Value +bool = + Native.Json.identity + + +{-|-} +null : Value +null = + Native.Json.encodeNull + + +{-|-} +object : List (String, Value) -> Value +object = + Native.Json.encodeObject + + +{-|-} +array : Array Value -> Value +array = + Native.Json.encodeArray + + +{-|-} +list : List Value -> Value +list = + Native.Json.encodeList diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm new file mode 100644 index 0000000..0b7ddf9 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/List.elm @@ -0,0 +1,613 @@ +module List exposing + ( isEmpty, length, reverse, member + , head, tail, filter, take, drop + , singleton, repeat, range, (::), append, concat, intersperse + , partition, unzip + , map, map2, map3, map4, map5 + , filterMap, concatMap, indexedMap + , foldr, foldl + , sum, product, maximum, minimum, all, any, scanl + , sort, sortBy, sortWith + ) + +{-| A library for manipulating lists of values. Every value in a +list must have the same type. + +# Basics +@docs isEmpty, length, reverse, member + +# Sub-lists +@docs head, tail, filter, take, drop + +# Putting Lists Together +@docs singleton, repeat, range, (::), append, concat, intersperse + +# Taking Lists Apart +@docs partition, unzip + +# Mapping +@docs map, map2, map3, map4, map5 + +If you can think of a legitimate use of `mapN` where `N` is 6 or more, please +let us know on [the list](https://groups.google.com/forum/#!forum/elm-discuss). +The current sentiment is that it is already quite error prone once you get to +4 and possibly should be approached another way. + +# Special Maps +@docs filterMap, concatMap, indexedMap + +# Folding +@docs foldr, foldl + +# Special Folds +@docs sum, product, maximum, minimum, all, any, scanl + +# Sorting +@docs sort, sortBy, sortWith + +-} + +import Basics exposing (..) +import Maybe +import Maybe exposing ( Maybe(Just,Nothing) ) +import Native.List + + +{-| Add an element to the front of a list. Pronounced *cons*. + + 1 :: [2,3] == [1,2,3] + 1 :: [] == [1] +-} +(::) : a -> List a -> List a +(::) = + Native.List.cons + + +infixr 5 :: + + +{-| Extract the first element of a list. + + head [1,2,3] == Just 1 + head [] == Nothing +-} +head : List a -> Maybe a +head list = + case list of + x :: xs -> + Just x + + [] -> + Nothing + + +{-| Extract the rest of the list. + + tail [1,2,3] == Just [2,3] + tail [] == Nothing +-} +tail : List a -> Maybe (List a) +tail list = + case list of + x :: xs -> + Just xs + + [] -> + Nothing + + +{-| Determine if a list is empty. + + isEmpty [] == True +-} +isEmpty : List a -> Bool +isEmpty xs = + case xs of + [] -> + True + + _ -> + False + + +{-| Figure out whether a list contains a value. + + member 9 [1,2,3,4] == False + member 4 [1,2,3,4] == True +-} +member : a -> List a -> Bool +member x xs = + any (\a -> a == x) xs + + +{-| Apply a function to every element of a list. + + map sqrt [1,4,9] == [1,2,3] + + map not [True,False,True] == [False,True,False] +-} +map : (a -> b) -> List a -> List b +map f xs = + foldr (\x acc -> f x :: acc) [] xs + + +{-| Same as `map` but the function is also applied to the index of each +element (starting at zero). + + indexedMap (,) ["Tom","Sue","Bob"] == [ (0,"Tom"), (1,"Sue"), (2,"Bob") ] +-} +indexedMap : (Int -> a -> b) -> List a -> List b +indexedMap f xs = + map2 f (range 0 (length xs - 1)) xs + + +{-| Reduce a list from the left. + + foldl (::) [] [1,2,3] == [3,2,1] +-} +foldl : (a -> b -> b) -> b -> List a -> b +foldl func acc list = + case list of + [] -> + acc + + x :: xs -> + foldl func (func x acc) xs + + +{-| Reduce a list from the right. + + foldr (+) 0 [1,2,3] == 6 +-} +foldr : (a -> b -> b) -> b -> List a -> b +foldr = + Native.List.foldr + + +{-| Reduce a list from the left, building up all of the intermediate results into a list. + + scanl (+) 0 [1,2,3,4] == [0,1,3,6,10] +-} +scanl : (a -> b -> b) -> b -> List a -> List b +scanl f b xs = + let + scan1 x accAcc = + case accAcc of + acc :: _ -> + f x acc :: accAcc + + [] -> + [] -- impossible + in + reverse (foldl scan1 [b] xs) + + +{-| Keep only elements that satisfy the predicate. + + filter isEven [1,2,3,4,5,6] == [2,4,6] +-} +filter : (a -> Bool) -> List a -> List a +filter pred xs = + let + conditionalCons front back = + if pred front then + front :: back + + else + back + in + foldr conditionalCons [] xs + + +{-| Apply a function that may succeed to all values in the list, but only keep +the successes. + + onlyTeens = + filterMap isTeen [3, 15, 12, 18, 24] == [15, 18] + + isTeen : Int -> Maybe Int + isTeen n = + if 13 <= n && n <= 19 then + Just n + + else + Nothing +-} +filterMap : (a -> Maybe b) -> List a -> List b +filterMap f xs = + foldr (maybeCons f) [] xs + + +maybeCons : (a -> Maybe b) -> a -> List b -> List b +maybeCons f mx xs = + case f mx of + Just x -> + x :: xs + + Nothing -> + xs + + +{-| Determine the length of a list. + + length [1,2,3] == 3 +-} +length : List a -> Int +length xs = + foldl (\_ i -> i + 1) 0 xs + + +{-| Reverse a list. + + reverse [1,2,3,4] == [4,3,2,1] +-} +reverse : List a -> List a +reverse list = + foldl (::) [] list + + +{-| Determine if all elements satisfy the predicate. + + all isEven [2,4] == True + all isEven [2,3] == False + all isEven [] == True +-} +all : (a -> Bool) -> List a -> Bool +all isOkay list = + not (any (not << isOkay) list) + + +{-| Determine if any elements satisfy the predicate. + + any isEven [2,3] == True + any isEven [1,3] == False + any isEven [] == False +-} +any : (a -> Bool) -> List a -> Bool +any isOkay list = + case list of + [] -> + False + + x :: xs -> + -- note: (isOkay x || any isOkay xs) would not get TCO + if isOkay x then + True + + else + any isOkay xs + + +{-| Put two lists together. + + append [1,1,2] [3,5,8] == [1,1,2,3,5,8] + append ['a','b'] ['c'] == ['a','b','c'] + +You can also use [the `(++)` operator](Basics#++) to append lists. +-} +append : List a -> List a -> List a +append xs ys = + case ys of + [] -> + xs + + _ -> + foldr (::) ys xs + + +{-| Concatenate a bunch of lists into a single list: + + concat [[1,2],[3],[4,5]] == [1,2,3,4,5] +-} +concat : List (List a) -> List a +concat lists = + foldr append [] lists + + +{-| Map a given function onto a list and flatten the resulting lists. + + concatMap f xs == concat (map f xs) +-} +concatMap : (a -> List b) -> List a -> List b +concatMap f list = + concat (map f list) + + +{-| Get the sum of the list elements. + + sum [1,2,3,4] == 10 +-} +sum : List number -> number +sum numbers = + foldl (+) 0 numbers + + +{-| Get the product of the list elements. + + product [1,2,3,4] == 24 +-} +product : List number -> number +product numbers = + foldl (*) 1 numbers + + +{-| Find the maximum element in a non-empty list. + + maximum [1,4,2] == Just 4 + maximum [] == Nothing +-} +maximum : List comparable -> Maybe comparable +maximum list = + case list of + x :: xs -> + Just (foldl max x xs) + + _ -> + Nothing + + +{-| Find the minimum element in a non-empty list. + + minimum [3,2,1] == Just 1 + minimum [] == Nothing +-} +minimum : List comparable -> Maybe comparable +minimum list = + case list of + x :: xs -> + Just (foldl min x xs) + + _ -> + Nothing + + +{-| Partition a list based on a predicate. The first list contains all values +that satisfy the predicate, and the second list contains all the value that do +not. + + partition (\x -> x < 3) [0,1,2,3,4,5] == ([0,1,2], [3,4,5]) + partition isEven [0,1,2,3,4,5] == ([0,2,4], [1,3,5]) +-} +partition : (a -> Bool) -> List a -> (List a, List a) +partition pred list = + let + step x (trues, falses) = + if pred x then + (x :: trues, falses) + + else + (trues, x :: falses) + in + foldr step ([],[]) list + + +{-| Combine two lists, combining them with the given function. +If one list is longer, the extra elements are dropped. + + map2 (+) [1,2,3] [1,2,3,4] == [2,4,6] + + map2 (,) [1,2,3] ['a','b'] == [ (1,'a'), (2,'b') ] + + pairs : List a -> List b -> List (a,b) + pairs lefts rights = + map2 (,) lefts rights +-} +map2 : (a -> b -> result) -> List a -> List b -> List result +map2 = + Native.List.map2 + + +{-|-} +map3 : (a -> b -> c -> result) -> List a -> List b -> List c -> List result +map3 = + Native.List.map3 + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result +map4 = + Native.List.map4 + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result +map5 = + Native.List.map5 + + +{-| Decompose a list of tuples into a tuple of lists. + + unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True]) +-} +unzip : List (a,b) -> (List a, List b) +unzip pairs = + let + step (x,y) (xs,ys) = + (x :: xs, y :: ys) + in + foldr step ([], []) pairs + + +{-| Places the given value between all members of the given list. + + intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"] +-} +intersperse : a -> List a -> List a +intersperse sep xs = + case xs of + [] -> + [] + + hd :: tl -> + let + step x rest = + sep :: x :: rest + + spersed = + foldr step [] tl + in + hd :: spersed + + +{-| Take the first *n* members of a list. + + take 2 [1,2,3,4] == [1,2] +-} +take : Int -> List a -> List a +take n list = + takeFast 0 n list + + +takeFast : Int -> Int -> List a -> List a +takeFast ctr n list = + if n <= 0 then + [] + else + case ( n, list ) of + ( _, [] ) -> + list + + ( 1, x :: _ ) -> + [ x ] + + ( 2, x :: y :: _ ) -> + [ x, y ] + + ( 3, x :: y :: z :: _ ) -> + [ x, y, z ] + + ( _, x :: y :: z :: w :: tl ) -> + if ctr > 1000 then + x :: y :: z :: w :: takeTailRec (n - 4) tl + else + x :: y :: z :: w :: takeFast (ctr + 1) (n - 4) tl + + _ -> + list + +takeTailRec : Int -> List a -> List a +takeTailRec n list = + reverse (takeReverse n list []) + + +takeReverse : Int -> List a -> List a -> List a +takeReverse n list taken = + if n <= 0 then + taken + else + case list of + [] -> + taken + + x :: xs -> + takeReverse (n - 1) xs (x :: taken) + + +{-| Drop the first *n* members of a list. + + drop 2 [1,2,3,4] == [3,4] +-} +drop : Int -> List a -> List a +drop n list = + if n <= 0 then + list + + else + case list of + [] -> + list + + x :: xs -> + drop (n-1) xs + + +{-| Create a list with only one element: + + singleton 1234 == [1234] + singleton "hi" == ["hi"] +-} +singleton : a -> List a +singleton value = + [value] + + +{-| Create a list with *n* copies of a value: + + repeat 3 (0,0) == [(0,0),(0,0),(0,0)] +-} +repeat : Int -> a -> List a +repeat n value = + repeatHelp [] n value + + +repeatHelp : List a -> Int -> a -> List a +repeatHelp result n value = + if n <= 0 then + result + + else + repeatHelp (value :: result) (n-1) value + + +{-| Create a list of numbers, every element increasing by one. +You give the lowest and highest number that should be in the list. + + range 3 6 == [3, 4, 5, 6] + range 3 3 == [3] + range 6 3 == [] +-} +range : Int -> Int -> List Int +range lo hi = + rangeHelp lo hi [] + + +rangeHelp : Int -> Int -> List Int -> List Int +rangeHelp lo hi list = + if lo <= hi then + rangeHelp lo (hi - 1) (hi :: list) + + else + list + + +{-| Sort values from lowest to highest + + sort [3,1,5] == [1,3,5] +-} +sort : List comparable -> List comparable +sort xs = + sortBy identity xs + + +{-| Sort values by a derived property. + + alice = { name="Alice", height=1.62 } + bob = { name="Bob" , height=1.85 } + chuck = { name="Chuck", height=1.76 } + + sortBy .name [chuck,alice,bob] == [alice,bob,chuck] + sortBy .height [chuck,alice,bob] == [alice,chuck,bob] + + sortBy String.length ["mouse","cat"] == ["cat","mouse"] +-} +sortBy : (a -> comparable) -> List a -> List a +sortBy = + Native.List.sortBy + + +{-| Sort values with a custom comparison function. + + sortWith flippedComparison [1,2,3,4,5] == [5,4,3,2,1] + + flippedComparison a b = + case compare a b of + LT -> GT + EQ -> EQ + GT -> LT + +This is also the most general sort function, allowing you +to define any other: `sort == sortWith compare` +-} +sortWith : (a -> a -> Order) -> List a -> List a +sortWith = + Native.List.sortWith diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm new file mode 100644 index 0000000..337a246 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Maybe.elm @@ -0,0 +1,157 @@ +module Maybe exposing + ( Maybe(Just,Nothing) + , andThen + , map, map2, map3, map4, map5 + , withDefault + ) + +{-| This library fills a bunch of important niches in Elm. A `Maybe` can help +you with optional arguments, error handling, and records with optional fields. + +# Definition +@docs Maybe + +# Common Helpers +@docs withDefault, map, map2, map3, map4, map5 + +# Chaining Maybes +@docs andThen +-} + +{-| Represent values that may or may not exist. It can be useful if you have a +record field that is only filled in sometimes. Or if a function takes a value +sometimes, but does not absolutely need it. + + -- A person, but maybe we do not know their age. + type alias Person = + { name : String + , age : Maybe Int + } + + tom = { name = "Tom", age = Just 42 } + sue = { name = "Sue", age = Nothing } +-} +type Maybe a + = Just a + | Nothing + + +{-| Provide a default value, turning an optional value into a normal +value. This comes in handy when paired with functions like +[`Dict.get`](Dict#get) which gives back a `Maybe`. + + withDefault 100 (Just 42) -- 42 + withDefault 100 Nothing -- 100 + + withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" + +-} +withDefault : a -> Maybe a -> a +withDefault default maybe = + case maybe of + Just value -> value + Nothing -> default + + +{-| Transform a `Maybe` value with a given function: + + map sqrt (Just 9) == Just 3 + map sqrt Nothing == Nothing +-} +map : (a -> b) -> Maybe a -> Maybe b +map f maybe = + case maybe of + Just value -> Just (f value) + Nothing -> Nothing + + +{-| Apply a function if all the arguments are `Just` a value. + + map2 (+) (Just 3) (Just 4) == Just 7 + map2 (+) (Just 3) Nothing == Nothing + map2 (+) Nothing (Just 4) == Nothing +-} +map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value +map2 func ma mb = + case (ma,mb) of + (Just a, Just b) -> + Just (func a b) + + _ -> + Nothing + + +{-|-} +map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value +map3 func ma mb mc = + case (ma,mb,mc) of + (Just a, Just b, Just c) -> + Just (func a b c) + + _ -> + Nothing + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value +map4 func ma mb mc md = + case (ma,mb,mc,md) of + (Just a, Just b, Just c, Just d) -> + Just (func a b c d) + + _ -> + Nothing + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value +map5 func ma mb mc md me = + case (ma,mb,mc,md,me) of + (Just a, Just b, Just c, Just d, Just e) -> + Just (func a b c d e) + + _ -> + Nothing + + +{-| Chain together many computations that may fail. It is helpful to see its +definition: + + andThen : (a -> Maybe b) -> Maybe a -> Maybe b + andThen callback maybe = + case maybe of + Just value -> + callback value + + Nothing -> + Nothing + +This means we only continue with the callback if things are going well. For +example, say you need to use (`head : List Int -> Maybe Int`) to get the +first month from a `List` and then make sure it is between 1 and 12: + + toValidMonth : Int -> Maybe Int + toValidMonth month = + if month >= 1 && month <= 12 then + Just month + else + Nothing + + getFirstMonth : List Int -> Maybe Int + getFirstMonth months = + head months + |> andThen toValidMonth + +If `head` fails and results in `Nothing` (because the `List` was `empty`), +this entire chain of operations will short-circuit and result in `Nothing`. +If `toValidMonth` results in `Nothing`, again the chain of computations +will result in `Nothing`. +-} +andThen : (a -> Maybe b) -> Maybe a -> Maybe b +andThen callback maybeValue = + case maybeValue of + Just value -> + callback value + + Nothing -> + Nothing diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js new file mode 100644 index 0000000..7ddd42d --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Array.js @@ -0,0 +1,967 @@ +//import Native.List // + +var _elm_lang$core$Native_Array = function() { + +// A RRB-Tree has two distinct data types. +// Leaf -> "height" is always 0 +// "table" is an array of elements +// Node -> "height" is always greater than 0 +// "table" is an array of child nodes +// "lengths" is an array of accumulated lengths of the child nodes + +// M is the maximal table size. 32 seems fast. E is the allowed increase +// of search steps when concatting to find an index. Lower values will +// decrease balancing, but will increase search steps. +var M = 32; +var E = 2; + +// An empty array. +var empty = { + ctor: '_Array', + height: 0, + table: [] +}; + + +function get(i, array) +{ + if (i < 0 || i >= length(array)) + { + throw new Error( + 'Index ' + i + ' is out of range. Check the length of ' + + 'your array first or use getMaybe or getWithDefault.'); + } + return unsafeGet(i, array); +} + + +function unsafeGet(i, array) +{ + for (var x = array.height; x > 0; x--) + { + var slot = i >> (x * 5); + while (array.lengths[slot] <= i) + { + slot++; + } + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array = array.table[slot]; + } + return array.table[i]; +} + + +// Sets the value at the index i. Only the nodes leading to i will get +// copied and updated. +function set(i, item, array) +{ + if (i < 0 || length(array) <= i) + { + return array; + } + return unsafeSet(i, item, array); +} + + +function unsafeSet(i, item, array) +{ + array = nodeCopy(array); + + if (array.height === 0) + { + array.table[i] = item; + } + else + { + var slot = getSlot(i, array); + if (slot > 0) + { + i -= array.lengths[slot - 1]; + } + array.table[slot] = unsafeSet(i, item, array.table[slot]); + } + return array; +} + + +function initialize(len, f) +{ + if (len <= 0) + { + return empty; + } + var h = Math.floor( Math.log(len) / Math.log(M) ); + return initialize_(f, h, 0, len); +} + +function initialize_(f, h, from, to) +{ + if (h === 0) + { + var table = new Array((to - from) % (M + 1)); + for (var i = 0; i < table.length; i++) + { + table[i] = f(from + i); + } + return { + ctor: '_Array', + height: 0, + table: table + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = initialize_(f, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +function fromList(list) +{ + if (list.ctor === '[]') + { + return empty; + } + + // Allocate M sized blocks (table) and write list elements to it. + var table = new Array(M); + var nodes = []; + var i = 0; + + while (list.ctor !== '[]') + { + table[i] = list._0; + list = list._1; + i++; + + // table is full, so we can push a leaf containing it into the + // next node. + if (i === M) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table + }; + fromListPush(leaf, nodes); + table = new Array(M); + i = 0; + } + } + + // Maybe there is something left on the table. + if (i > 0) + { + var leaf = { + ctor: '_Array', + height: 0, + table: table.splice(0, i) + }; + fromListPush(leaf, nodes); + } + + // Go through all of the nodes and eventually push them into higher nodes. + for (var h = 0; h < nodes.length - 1; h++) + { + if (nodes[h].table.length > 0) + { + fromListPush(nodes[h], nodes); + } + } + + var head = nodes[nodes.length - 1]; + if (head.height > 0 && head.table.length === 1) + { + return head.table[0]; + } + else + { + return head; + } +} + +// Push a node into a higher node as a child. +function fromListPush(toPush, nodes) +{ + var h = toPush.height; + + // Maybe the node on this height does not exist. + if (nodes.length === h) + { + var node = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + nodes.push(node); + } + + nodes[h].table.push(toPush); + var len = length(toPush); + if (nodes[h].lengths.length > 0) + { + len += nodes[h].lengths[nodes[h].lengths.length - 1]; + } + nodes[h].lengths.push(len); + + if (nodes[h].table.length === M) + { + fromListPush(nodes[h], nodes); + nodes[h] = { + ctor: '_Array', + height: h + 1, + table: [], + lengths: [] + }; + } +} + +// Pushes an item via push_ to the bottom right of a tree. +function push(item, a) +{ + var pushed = push_(item, a); + if (pushed !== null) + { + return pushed; + } + + var newTree = create(item, a.height); + return siblise(a, newTree); +} + +// Recursively tries to push an item to the bottom-right most +// tree possible. If there is no space left for the item, +// null will be returned. +function push_(item, a) +{ + // Handle resursion stop at leaf level. + if (a.height === 0) + { + if (a.table.length < M) + { + var newA = { + ctor: '_Array', + height: 0, + table: a.table.slice() + }; + newA.table.push(item); + return newA; + } + else + { + return null; + } + } + + // Recursively push + var pushed = push_(item, botRight(a)); + + // There was space in the bottom right tree, so the slot will + // be updated. + if (pushed !== null) + { + var newA = nodeCopy(a); + newA.table[newA.table.length - 1] = pushed; + newA.lengths[newA.lengths.length - 1]++; + return newA; + } + + // When there was no space left, check if there is space left + // for a new slot with a tree which contains only the item + // at the bottom. + if (a.table.length < M) + { + var newSlot = create(item, a.height - 1); + var newA = nodeCopy(a); + newA.table.push(newSlot); + newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot)); + return newA; + } + else + { + return null; + } +} + +// Converts an array into a list of elements. +function toList(a) +{ + return toList_(_elm_lang$core$Native_List.Nil, a); +} + +function toList_(list, a) +{ + for (var i = a.table.length - 1; i >= 0; i--) + { + list = + a.height === 0 + ? _elm_lang$core$Native_List.Cons(a.table[i], list) + : toList_(list, a.table[i]); + } + return list; +} + +// Maps a function over the elements of an array. +function map(f, a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? f(a.table[i]) + : map(f, a.table[i]); + } + return newA; +} + +// Maps a function over the elements with their index as first argument. +function indexedMap(f, a) +{ + return indexedMap_(f, a, 0); +} + +function indexedMap_(f, a, from) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: new Array(a.table.length) + }; + if (a.height > 0) + { + newA.lengths = a.lengths; + } + for (var i = 0; i < a.table.length; i++) + { + newA.table[i] = + a.height === 0 + ? A2(f, from + i, a.table[i]) + : indexedMap_(f, a.table[i], i == 0 ? from : from + a.lengths[i - 1]); + } + return newA; +} + +function foldl(f, b, a) +{ + if (a.height === 0) + { + for (var i = 0; i < a.table.length; i++) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = 0; i < a.table.length; i++) + { + b = foldl(f, b, a.table[i]); + } + } + return b; +} + +function foldr(f, b, a) +{ + if (a.height === 0) + { + for (var i = a.table.length; i--; ) + { + b = A2(f, a.table[i], b); + } + } + else + { + for (var i = a.table.length; i--; ) + { + b = foldr(f, b, a.table[i]); + } + } + return b; +} + +// TODO: currently, it slices the right, then the left. This can be +// optimized. +function slice(from, to, a) +{ + if (from < 0) + { + from += length(a); + } + if (to < 0) + { + to += length(a); + } + return sliceLeft(from, sliceRight(to, a)); +} + +function sliceRight(to, a) +{ + if (to === length(a)) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(0, to); + return newA; + } + + // Slice the right recursively. + var right = getSlot(to, a); + var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (right === 0) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(0, right), + lengths: a.lengths.slice(0, right) + }; + if (sliced.table.length > 0) + { + newA.table[right] = sliced; + newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0); + } + return newA; +} + +function sliceLeft(from, a) +{ + if (from === 0) + { + return a; + } + + // Handle leaf level. + if (a.height === 0) + { + var newA = { ctor:'_Array', height:0 }; + newA.table = a.table.slice(from, a.table.length + 1); + return newA; + } + + // Slice the left recursively. + var left = getSlot(from, a); + var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]); + + // Maybe the a node is not even needed, as sliced contains the whole slice. + if (left === a.table.length - 1) + { + return sliced; + } + + // Create new node. + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice(left, a.table.length + 1), + lengths: new Array(a.table.length - left) + }; + newA.table[0] = sliced; + var len = 0; + for (var i = 0; i < newA.table.length; i++) + { + len += length(newA.table[i]); + newA.lengths[i] = len; + } + + return newA; +} + +// Appends two trees. +function append(a,b) +{ + if (a.table.length === 0) + { + return b; + } + if (b.table.length === 0) + { + return a; + } + + var c = append_(a, b); + + // Check if both nodes can be crunshed together. + if (c[0].table.length + c[1].table.length <= M) + { + if (c[0].table.length === 0) + { + return c[1]; + } + if (c[1].table.length === 0) + { + return c[0]; + } + + // Adjust .table and .lengths + c[0].table = c[0].table.concat(c[1].table); + if (c[0].height > 0) + { + var len = length(c[0]); + for (var i = 0; i < c[1].lengths.length; i++) + { + c[1].lengths[i] += len; + } + c[0].lengths = c[0].lengths.concat(c[1].lengths); + } + + return c[0]; + } + + if (c[0].height > 0) + { + var toRemove = calcToRemove(a, b); + if (toRemove > E) + { + c = shuffle(c[0], c[1], toRemove); + } + } + + return siblise(c[0], c[1]); +} + +// Returns an array of two nodes; right and left. One node _may_ be empty. +function append_(a, b) +{ + if (a.height === 0 && b.height === 0) + { + return [a, b]; + } + + if (a.height !== 1 || b.height !== 1) + { + if (a.height === b.height) + { + a = nodeCopy(a); + b = nodeCopy(b); + var appended = append_(botRight(a), botLeft(b)); + + insertRight(a, appended[1]); + insertLeft(b, appended[0]); + } + else if (a.height > b.height) + { + a = nodeCopy(a); + var appended = append_(botRight(a), b); + + insertRight(a, appended[0]); + b = parentise(appended[1], appended[1].height + 1); + } + else + { + b = nodeCopy(b); + var appended = append_(a, botLeft(b)); + + var left = appended[0].table.length === 0 ? 0 : 1; + var right = left === 0 ? 1 : 0; + insertLeft(b, appended[left]); + a = parentise(appended[right], appended[right].height + 1); + } + } + + // Check if balancing is needed and return based on that. + if (a.table.length === 0 || b.table.length === 0) + { + return [a, b]; + } + + var toRemove = calcToRemove(a, b); + if (toRemove <= E) + { + return [a, b]; + } + return shuffle(a, b, toRemove); +} + +// Helperfunctions for append_. Replaces a child node at the side of the parent. +function insertRight(parent, node) +{ + var index = parent.table.length - 1; + parent.table[index] = node; + parent.lengths[index] = length(node); + parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0; +} + +function insertLeft(parent, node) +{ + if (node.table.length > 0) + { + parent.table[0] = node; + parent.lengths[0] = length(node); + + var len = length(parent.table[0]); + for (var i = 1; i < parent.lengths.length; i++) + { + len += length(parent.table[i]); + parent.lengths[i] = len; + } + } + else + { + parent.table.shift(); + for (var i = 1; i < parent.lengths.length; i++) + { + parent.lengths[i] = parent.lengths[i] - parent.lengths[0]; + } + parent.lengths.shift(); + } +} + +// Returns the extra search steps for E. Refer to the paper. +function calcToRemove(a, b) +{ + var subLengths = 0; + for (var i = 0; i < a.table.length; i++) + { + subLengths += a.table[i].table.length; + } + for (var i = 0; i < b.table.length; i++) + { + subLengths += b.table[i].table.length; + } + + var toRemove = a.table.length + b.table.length; + return toRemove - (Math.floor((subLengths - 1) / M) + 1); +} + +// get2, set2 and saveSlot are helpers for accessing elements over two arrays. +function get2(a, b, index) +{ + return index < a.length + ? a[index] + : b[index - a.length]; +} + +function set2(a, b, index, value) +{ + if (index < a.length) + { + a[index] = value; + } + else + { + b[index - a.length] = value; + } +} + +function saveSlot(a, b, index, slot) +{ + set2(a.table, b.table, index, slot); + + var l = (index === 0 || index === a.lengths.length) + ? 0 + : get2(a.lengths, a.lengths, index - 1); + + set2(a.lengths, b.lengths, index, l + length(slot)); +} + +// Creates a node or leaf with a given length at their arrays for perfomance. +// Is only used by shuffle. +function createNode(h, length) +{ + if (length < 0) + { + length = 0; + } + var a = { + ctor: '_Array', + height: h, + table: new Array(length) + }; + if (h > 0) + { + a.lengths = new Array(length); + } + return a; +} + +// Returns an array of two balanced nodes. +function shuffle(a, b, toRemove) +{ + var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove)); + var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove)); + + // Skip the slots with size M. More precise: copy the slot references + // to the new node + var read = 0; + while (get2(a.table, b.table, read).table.length % M === 0) + { + set2(newA.table, newB.table, read, get2(a.table, b.table, read)); + set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read)); + read++; + } + + // Pulling items from left to right, caching in a slot before writing + // it into the new nodes. + var write = read; + var slot = new createNode(a.height - 1, 0); + var from = 0; + + // If the current slot is still containing data, then there will be at + // least one more write, so we do not break this loop yet. + while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) + { + // Find out the max possible items for copying. + var source = get2(a.table, b.table, read); + var to = Math.min(M - slot.table.length, source.table.length); + + // Copy and adjust size table. + slot.table = slot.table.concat(source.table.slice(from, to)); + if (slot.height > 0) + { + var len = slot.lengths.length; + for (var i = len; i < len + to - from; i++) + { + slot.lengths[i] = length(slot.table[i]); + slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0); + } + } + + from += to; + + // Only proceed to next slots[i] if the current one was + // fully copied. + if (source.table.length <= to) + { + read++; from = 0; + } + + // Only create a new slot if the current one is filled up. + if (slot.table.length === M) + { + saveSlot(newA, newB, write, slot); + slot = createNode(a.height - 1, 0); + write++; + } + } + + // Cleanup after the loop. Copy the last slot into the new nodes. + if (slot.table.length > 0) + { + saveSlot(newA, newB, write, slot); + write++; + } + + // Shift the untouched slots to the left + while (read < a.table.length + b.table.length ) + { + saveSlot(newA, newB, write, get2(a.table, b.table, read)); + read++; + write++; + } + + return [newA, newB]; +} + +// Navigation functions +function botRight(a) +{ + return a.table[a.table.length - 1]; +} +function botLeft(a) +{ + return a.table[0]; +} + +// Copies a node for updating. Note that you should not use this if +// only updating only one of "table" or "lengths" for performance reasons. +function nodeCopy(a) +{ + var newA = { + ctor: '_Array', + height: a.height, + table: a.table.slice() + }; + if (a.height > 0) + { + newA.lengths = a.lengths.slice(); + } + return newA; +} + +// Returns how many items are in the tree. +function length(array) +{ + if (array.height === 0) + { + return array.table.length; + } + else + { + return array.lengths[array.lengths.length - 1]; + } +} + +// Calculates in which slot of "table" the item probably is, then +// find the exact slot via forward searching in "lengths". Returns the index. +function getSlot(i, a) +{ + var slot = i >> (5 * a.height); + while (a.lengths[slot] <= i) + { + slot++; + } + return slot; +} + +// Recursively creates a tree with a given height containing +// only the given item. +function create(item, h) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: [item] + }; + } + return { + ctor: '_Array', + height: h, + table: [create(item, h - 1)], + lengths: [1] + }; +} + +// Recursively creates a tree that contains the given tree. +function parentise(tree, h) +{ + if (h === tree.height) + { + return tree; + } + + return { + ctor: '_Array', + height: h, + table: [parentise(tree, h - 1)], + lengths: [length(tree)] + }; +} + +// Emphasizes blood brotherhood beneath two trees. +function siblise(a, b) +{ + return { + ctor: '_Array', + height: a.height + 1, + table: [a, b], + lengths: [length(a), length(a) + length(b)] + }; +} + +function toJSArray(a) +{ + var jsArray = new Array(length(a)); + toJSArray_(jsArray, 0, a); + return jsArray; +} + +function toJSArray_(jsArray, i, a) +{ + for (var t = 0; t < a.table.length; t++) + { + if (a.height === 0) + { + jsArray[i + t] = a.table[t]; + } + else + { + var inc = t === 0 ? 0 : a.lengths[t - 1]; + toJSArray_(jsArray, i + inc, a.table[t]); + } + } +} + +function fromJSArray(jsArray) +{ + if (jsArray.length === 0) + { + return empty; + } + var h = Math.floor(Math.log(jsArray.length) / Math.log(M)); + return fromJSArray_(jsArray, h, 0, jsArray.length); +} + +function fromJSArray_(jsArray, h, from, to) +{ + if (h === 0) + { + return { + ctor: '_Array', + height: 0, + table: jsArray.slice(from, to) + }; + } + + var step = Math.pow(M, h); + var table = new Array(Math.ceil((to - from) / step)); + var lengths = new Array(table.length); + for (var i = 0; i < table.length; i++) + { + table[i] = fromJSArray_(jsArray, h - 1, from + (i * step), Math.min(from + ((i + 1) * step), to)); + lengths[i] = length(table[i]) + (i > 0 ? lengths[i - 1] : 0); + } + return { + ctor: '_Array', + height: h, + table: table, + lengths: lengths + }; +} + +return { + empty: empty, + fromList: fromList, + toList: toList, + initialize: F2(initialize), + append: F2(append), + push: F2(push), + slice: F3(slice), + get: F2(get), + set: F3(set), + map: F2(map), + indexedMap: F2(indexedMap), + foldl: F3(foldl), + foldr: F3(foldr), + length: length, + + toJSArray: toJSArray, + fromJSArray: fromJSArray +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js new file mode 100644 index 0000000..1d97bf3 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Basics.js @@ -0,0 +1,141 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Basics = function() { + +function div(a, b) +{ + return (a / b) | 0; +} +function rem(a, b) +{ + return a % b; +} +function mod(a, b) +{ + if (b === 0) + { + throw new Error('Cannot perform mod 0. Division by zero error.'); + } + var r = a % b; + var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r + b) : -mod(-a, -b)); + + return m === b ? 0 : m; +} +function logBase(base, n) +{ + return Math.log(n) / Math.log(base); +} +function negate(n) +{ + return -n; +} +function abs(n) +{ + return n < 0 ? -n : n; +} + +function min(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) < 0 ? a : b; +} +function max(a, b) +{ + return _elm_lang$core$Native_Utils.cmp(a, b) > 0 ? a : b; +} +function clamp(lo, hi, n) +{ + return _elm_lang$core$Native_Utils.cmp(n, lo) < 0 + ? lo + : _elm_lang$core$Native_Utils.cmp(n, hi) > 0 + ? hi + : n; +} + +var ord = ['LT', 'EQ', 'GT']; + +function compare(x, y) +{ + return { ctor: ord[_elm_lang$core$Native_Utils.cmp(x, y) + 1] }; +} + +function xor(a, b) +{ + return a !== b; +} +function not(b) +{ + return !b; +} +function isInfinite(n) +{ + return n === Infinity || n === -Infinity; +} + +function truncate(n) +{ + return n | 0; +} + +function degrees(d) +{ + return d * Math.PI / 180; +} +function turns(t) +{ + return 2 * Math.PI * t; +} +function fromPolar(point) +{ + var r = point._0; + var t = point._1; + return _elm_lang$core$Native_Utils.Tuple2(r * Math.cos(t), r * Math.sin(t)); +} +function toPolar(point) +{ + var x = point._0; + var y = point._1; + return _elm_lang$core$Native_Utils.Tuple2(Math.sqrt(x * x + y * y), Math.atan2(y, x)); +} + +return { + div: F2(div), + rem: F2(rem), + mod: F2(mod), + + pi: Math.PI, + e: Math.E, + cos: Math.cos, + sin: Math.sin, + tan: Math.tan, + acos: Math.acos, + asin: Math.asin, + atan: Math.atan, + atan2: F2(Math.atan2), + + degrees: degrees, + turns: turns, + fromPolar: fromPolar, + toPolar: toPolar, + + sqrt: Math.sqrt, + logBase: F2(logBase), + negate: negate, + abs: abs, + min: F2(min), + max: F2(max), + clamp: F3(clamp), + compare: F2(compare), + + xor: F2(xor), + not: not, + + truncate: truncate, + ceiling: Math.ceil, + floor: Math.floor, + round: Math.round, + toFloat: function(x) { return x; }, + isNaN: isNaN, + isInfinite: isInfinite +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js new file mode 100644 index 0000000..a597f82 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Bitwise.js @@ -0,0 +1,13 @@ +var _elm_lang$core$Native_Bitwise = function() { + +return { + and: F2(function and(a, b) { return a & b; }), + or: F2(function or(a, b) { return a | b; }), + xor: F2(function xor(a, b) { return a ^ b; }), + complement: function complement(a) { return ~a; }, + shiftLeftBy: F2(function(offset, a) { return a << offset; }), + shiftRightBy: F2(function(offset, a) { return a >> offset; }), + shiftRightZfBy: F2(function(offset, a) { return a >>> offset; }) +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js new file mode 100644 index 0000000..56c2957 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Char.js @@ -0,0 +1,14 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Char = function() { + +return { + fromCode: function(c) { return _elm_lang$core$Native_Utils.chr(String.fromCharCode(c)); }, + toCode: function(c) { return c.charCodeAt(0); }, + toUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toUpperCase()); }, + toLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLowerCase()); }, + toLocaleUpper: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleUpperCase()); }, + toLocaleLower: function(c) { return _elm_lang$core$Native_Utils.chr(c.toLocaleLowerCase()); } +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js new file mode 100644 index 0000000..cb64193 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Date.js @@ -0,0 +1,33 @@ +//import Result // + +var _elm_lang$core$Native_Date = function() { + +function fromString(str) +{ + var date = new Date(str); + return isNaN(date.getTime()) + ? _elm_lang$core$Result$Err('Unable to parse \'' + str + '\' as a date. Dates must be in the ISO 8601 format.') + : _elm_lang$core$Result$Ok(date); +} + +var dayTable = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; +var monthTable = + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + +return { + fromString: fromString, + year: function(d) { return d.getFullYear(); }, + month: function(d) { return { ctor: monthTable[d.getMonth()] }; }, + day: function(d) { return d.getDate(); }, + hour: function(d) { return d.getHours(); }, + minute: function(d) { return d.getMinutes(); }, + second: function(d) { return d.getSeconds(); }, + millisecond: function(d) { return d.getMilliseconds(); }, + toTime: function(d) { return d.getTime(); }, + fromTime: function(t) { return new Date(t); }, + dayOfWeek: function(d) { return { ctor: dayTable[d.getDay()] }; } +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js new file mode 100644 index 0000000..15ce1dc --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Debug.js @@ -0,0 +1,30 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Debug = function() { + +function log(tag, value) +{ + var msg = tag + ': ' + _elm_lang$core$Native_Utils.toString(value); + var process = process || {}; + if (process.stdout) + { + process.stdout.write(msg); + } + else + { + console.log(msg); + } + return value; +} + +function crash(message) +{ + throw new Error(message); +} + +return { + crash: crash, + log: F2(log) +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js new file mode 100644 index 0000000..61df889 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Json.js @@ -0,0 +1,575 @@ +//import Maybe, Native.Array, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_Json = function() { + + +// CORE DECODERS + +function succeed(msg) +{ + return { + ctor: '', + tag: 'succeed', + msg: msg + }; +} + +function fail(msg) +{ + return { + ctor: '', + tag: 'fail', + msg: msg + }; +} + +function decodePrimitive(tag) +{ + return { + ctor: '', + tag: tag + }; +} + +function decodeContainer(tag, decoder) +{ + return { + ctor: '', + tag: tag, + decoder: decoder + }; +} + +function decodeNull(value) +{ + return { + ctor: '', + tag: 'null', + value: value + }; +} + +function decodeField(field, decoder) +{ + return { + ctor: '', + tag: 'field', + field: field, + decoder: decoder + }; +} + +function decodeIndex(index, decoder) +{ + return { + ctor: '', + tag: 'index', + index: index, + decoder: decoder + }; +} + +function decodeKeyValuePairs(decoder) +{ + return { + ctor: '', + tag: 'key-value', + decoder: decoder + }; +} + +function mapMany(f, decoders) +{ + return { + ctor: '', + tag: 'map-many', + func: f, + decoders: decoders + }; +} + +function andThen(callback, decoder) +{ + return { + ctor: '', + tag: 'andThen', + decoder: decoder, + callback: callback + }; +} + +function oneOf(decoders) +{ + return { + ctor: '', + tag: 'oneOf', + decoders: decoders + }; +} + + +// DECODING OBJECTS + +function map1(f, d1) +{ + return mapMany(f, [d1]); +} + +function map2(f, d1, d2) +{ + return mapMany(f, [d1, d2]); +} + +function map3(f, d1, d2, d3) +{ + return mapMany(f, [d1, d2, d3]); +} + +function map4(f, d1, d2, d3, d4) +{ + return mapMany(f, [d1, d2, d3, d4]); +} + +function map5(f, d1, d2, d3, d4, d5) +{ + return mapMany(f, [d1, d2, d3, d4, d5]); +} + +function map6(f, d1, d2, d3, d4, d5, d6) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6]); +} + +function map7(f, d1, d2, d3, d4, d5, d6, d7) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7]); +} + +function map8(f, d1, d2, d3, d4, d5, d6, d7, d8) +{ + return mapMany(f, [d1, d2, d3, d4, d5, d6, d7, d8]); +} + + +// DECODE HELPERS + +function ok(value) +{ + return { tag: 'ok', value: value }; +} + +function badPrimitive(type, value) +{ + return { tag: 'primitive', type: type, value: value }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badField(field, nestedProblems) +{ + return { tag: 'field', field: field, rest: nestedProblems }; +} + +function badIndex(index, nestedProblems) +{ + return { tag: 'index', index: index, rest: nestedProblems }; +} + +function badOneOf(problems) +{ + return { tag: 'oneOf', problems: problems }; +} + +function bad(msg) +{ + return { tag: 'fail', msg: msg }; +} + +function badToString(problem) +{ + var context = '_'; + while (problem) + { + switch (problem.tag) + { + case 'primitive': + return 'Expecting ' + problem.type + + (context === '_' ? '' : ' at ' + context) + + ' but instead got: ' + jsToString(problem.value); + + case 'index': + context += '[' + problem.index + ']'; + problem = problem.rest; + break; + + case 'field': + context += '.' + problem.field; + problem = problem.rest; + break; + + case 'oneOf': + var problems = problem.problems; + for (var i = 0; i < problems.length; i++) + { + problems[i] = badToString(problems[i]); + } + return 'I ran into the following problems' + + (context === '_' ? '' : ' at ' + context) + + ':\n\n' + problems.join('\n'); + + case 'fail': + return 'I ran into a `fail` decoder' + + (context === '_' ? '' : ' at ' + context) + + ': ' + problem.msg; + } + } +} + +function jsToString(value) +{ + return value === undefined + ? 'undefined' + : JSON.stringify(value); +} + + +// DECODE + +function runOnString(decoder, string) +{ + var json; + try + { + json = JSON.parse(string); + } + catch (e) + { + return _elm_lang$core$Result$Err('Given an invalid JSON: ' + e.message); + } + return run(decoder, json); +} + +function run(decoder, value) +{ + var result = runHelp(decoder, value); + return (result.tag === 'ok') + ? _elm_lang$core$Result$Ok(result.value) + : _elm_lang$core$Result$Err(badToString(result)); +} + +function runHelp(decoder, value) +{ + switch (decoder.tag) + { + case 'bool': + return (typeof value === 'boolean') + ? ok(value) + : badPrimitive('a Bool', value); + + case 'int': + if (typeof value !== 'number') { + return badPrimitive('an Int', value); + } + + if (-2147483647 < value && value < 2147483647 && (value | 0) === value) { + return ok(value); + } + + if (isFinite(value) && !(value % 1)) { + return ok(value); + } + + return badPrimitive('an Int', value); + + case 'float': + return (typeof value === 'number') + ? ok(value) + : badPrimitive('a Float', value); + + case 'string': + return (typeof value === 'string') + ? ok(value) + : (value instanceof String) + ? ok(value + '') + : badPrimitive('a String', value); + + case 'null': + return (value === null) + ? ok(decoder.value) + : badPrimitive('null', value); + + case 'value': + return ok(value); + + case 'list': + if (!(value instanceof Array)) + { + return badPrimitive('a List', value); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i = value.length; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result) + } + list = _elm_lang$core$Native_List.Cons(result.value, list); + } + return ok(list); + + case 'array': + if (!(value instanceof Array)) + { + return badPrimitive('an Array', value); + } + + var len = value.length; + var array = new Array(len); + for (var i = len; i--; ) + { + var result = runHelp(decoder.decoder, value[i]); + if (result.tag !== 'ok') + { + return badIndex(i, result); + } + array[i] = result.value; + } + return ok(_elm_lang$core$Native_Array.fromJSArray(array)); + + case 'maybe': + var result = runHelp(decoder.decoder, value); + return (result.tag === 'ok') + ? ok(_elm_lang$core$Maybe$Just(result.value)) + : ok(_elm_lang$core$Maybe$Nothing); + + case 'field': + var field = decoder.field; + if (typeof value !== 'object' || value === null || !(field in value)) + { + return badPrimitive('an object with a field named `' + field + '`', value); + } + + var result = runHelp(decoder.decoder, value[field]); + return (result.tag === 'ok') ? result : badField(field, result); + + case 'index': + var index = decoder.index; + if (!(value instanceof Array)) + { + return badPrimitive('an array', value); + } + if (index >= value.length) + { + return badPrimitive('a longer array. Need index ' + index + ' but there are only ' + value.length + ' entries', value); + } + + var result = runHelp(decoder.decoder, value[index]); + return (result.tag === 'ok') ? result : badIndex(index, result); + + case 'key-value': + if (typeof value !== 'object' || value === null || value instanceof Array) + { + return badPrimitive('an object', value); + } + + var keyValuePairs = _elm_lang$core$Native_List.Nil; + for (var key in value) + { + var result = runHelp(decoder.decoder, value[key]); + if (result.tag !== 'ok') + { + return badField(key, result); + } + var pair = _elm_lang$core$Native_Utils.Tuple2(key, result.value); + keyValuePairs = _elm_lang$core$Native_List.Cons(pair, keyValuePairs); + } + return ok(keyValuePairs); + + case 'map-many': + var answer = decoder.func; + var decoders = decoder.decoders; + for (var i = 0; i < decoders.length; i++) + { + var result = runHelp(decoders[i], value); + if (result.tag !== 'ok') + { + return result; + } + answer = answer(result.value); + } + return ok(answer); + + case 'andThen': + var result = runHelp(decoder.decoder, value); + return (result.tag !== 'ok') + ? result + : runHelp(decoder.callback(result.value), value); + + case 'oneOf': + var errors = []; + var temp = decoder.decoders; + while (temp.ctor !== '[]') + { + var result = runHelp(temp._0, value); + + if (result.tag === 'ok') + { + return result; + } + + errors.push(result); + + temp = temp._1; + } + return badOneOf(errors); + + case 'fail': + return bad(decoder.msg); + + case 'succeed': + return ok(decoder.msg); + } +} + + +// EQUALITY + +function equality(a, b) +{ + if (a === b) + { + return true; + } + + if (a.tag !== b.tag) + { + return false; + } + + switch (a.tag) + { + case 'succeed': + case 'fail': + return a.msg === b.msg; + + case 'bool': + case 'int': + case 'float': + case 'string': + case 'value': + return true; + + case 'null': + return a.value === b.value; + + case 'list': + case 'array': + case 'maybe': + case 'key-value': + return equality(a.decoder, b.decoder); + + case 'field': + return a.field === b.field && equality(a.decoder, b.decoder); + + case 'index': + return a.index === b.index && equality(a.decoder, b.decoder); + + case 'map-many': + if (a.func !== b.func) + { + return false; + } + return listEquality(a.decoders, b.decoders); + + case 'andThen': + return a.callback === b.callback && equality(a.decoder, b.decoder); + + case 'oneOf': + return listEquality(a.decoders, b.decoders); + } +} + +function listEquality(aDecoders, bDecoders) +{ + var len = aDecoders.length; + if (len !== bDecoders.length) + { + return false; + } + for (var i = 0; i < len; i++) + { + if (!equality(aDecoders[i], bDecoders[i])) + { + return false; + } + } + return true; +} + + +// ENCODE + +function encode(indentLevel, value) +{ + return JSON.stringify(value, null, indentLevel); +} + +function identity(value) +{ + return value; +} + +function encodeObject(keyValuePairs) +{ + var obj = {}; + while (keyValuePairs.ctor !== '[]') + { + var pair = keyValuePairs._0; + obj[pair._0] = pair._1; + keyValuePairs = keyValuePairs._1; + } + return obj; +} + +return { + encode: F2(encode), + runOnString: F2(runOnString), + run: F2(run), + + decodeNull: decodeNull, + decodePrimitive: decodePrimitive, + decodeContainer: F2(decodeContainer), + + decodeField: F2(decodeField), + decodeIndex: F2(decodeIndex), + + map1: F2(map1), + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + map6: F7(map6), + map7: F8(map7), + map8: F9(map8), + decodeKeyValuePairs: decodeKeyValuePairs, + + andThen: F2(andThen), + fail: fail, + succeed: succeed, + oneOf: oneOf, + + identity: identity, + encodeNull: null, + encodeArray: _elm_lang$core$Native_Array.toJSArray, + encodeList: _elm_lang$core$Native_List.toArray, + encodeObject: encodeObject, + + equality: equality +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js new file mode 100644 index 0000000..ccefb9c --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/List.js @@ -0,0 +1,137 @@ +//import Native.Utils // + +var _elm_lang$core$Native_List = function() { + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { ctor: '::', _0: hd, _1: tl }; +} + +function fromArray(arr) +{ + var out = Nil; + for (var i = arr.length; i--; ) + { + out = Cons(arr[i], out); + } + return out; +} + +function toArray(xs) +{ + var out = []; + while (xs.ctor !== '[]') + { + out.push(xs._0); + xs = xs._1; + } + return out; +} + +function foldr(f, b, xs) +{ + var arr = toArray(xs); + var acc = b; + for (var i = arr.length; i--; ) + { + acc = A2(f, arr[i], acc); + } + return acc; +} + +function map2(f, xs, ys) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]') + { + arr.push(A2(f, xs._0, ys._0)); + xs = xs._1; + ys = ys._1; + } + return fromArray(arr); +} + +function map3(f, xs, ys, zs) +{ + var arr = []; + while (xs.ctor !== '[]' && ys.ctor !== '[]' && zs.ctor !== '[]') + { + arr.push(A3(f, xs._0, ys._0, zs._0)); + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map4(f, ws, xs, ys, zs) +{ + var arr = []; + while ( ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A4(f, ws._0, xs._0, ys._0, zs._0)); + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function map5(f, vs, ws, xs, ys, zs) +{ + var arr = []; + while ( vs.ctor !== '[]' + && ws.ctor !== '[]' + && xs.ctor !== '[]' + && ys.ctor !== '[]' + && zs.ctor !== '[]') + { + arr.push(A5(f, vs._0, ws._0, xs._0, ys._0, zs._0)); + vs = vs._1; + ws = ws._1; + xs = xs._1; + ys = ys._1; + zs = zs._1; + } + return fromArray(arr); +} + +function sortBy(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + return _elm_lang$core$Native_Utils.cmp(f(a), f(b)); + })); +} + +function sortWith(f, xs) +{ + return fromArray(toArray(xs).sort(function(a, b) { + var ord = f(a)(b).ctor; + return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1; + })); +} + +return { + Nil: Nil, + Cons: Cons, + cons: F2(Cons), + toArray: toArray, + fromArray: fromArray, + + foldr: F3(foldr), + + map2: F3(map2), + map3: F4(map3), + map4: F5(map4), + map5: F6(map5), + sortBy: F2(sortBy), + sortWith: F2(sortWith) +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js new file mode 100644 index 0000000..bd6da19 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Platform.js @@ -0,0 +1,559 @@ +//import // + +var _elm_lang$core$Native_Platform = function() { + + +// PROGRAMS + +function program(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flags !== 'undefined') + { + throw new Error( + 'The `' + moduleName + '` module does not need flags.\n' + + 'Call ' + moduleName + '.worker() with no arguments and you should be all set!' + ); + } + + return initialize( + impl.init, + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function programWithFlags(impl) +{ + return function(flagDecoder) + { + return function(object, moduleName) + { + object['worker'] = function worker(flags) + { + if (typeof flagDecoder === 'undefined') + { + throw new Error( + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + ); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Err') + { + throw new Error( + moduleName + '.worker(...) was called with an unexpected argument.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0 + ); + } + + return initialize( + impl.init(result._0), + impl.update, + impl.subscriptions, + renderer + ); + }; + }; + }; +} + +function renderer(enqueue, _) +{ + return function(_) {}; +} + + +// HTML TO PROGRAM + +function htmlToProgram(vnode) +{ + var emptyBag = batch(_elm_lang$core$Native_List.Nil); + var noChange = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + emptyBag + ); + + return _elm_lang$virtual_dom$VirtualDom$program({ + init: noChange, + view: function(model) { return main; }, + update: F2(function(msg, model) { return noChange; }), + subscriptions: function (model) { return emptyBag; } + }); +} + + +// INITIALIZE A PROGRAM + +function initialize(init, update, subscriptions, renderer) +{ + // ambient state + var managers = {}; + var updateView; + + // init and update state in main process + var initApp = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var model = init._0; + updateView = renderer(enqueue, model); + var cmds = init._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + + function onMessage(msg, model) + { + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + var results = A2(update, msg, model); + model = results._0; + updateView(model); + var cmds = results._1; + var subs = subscriptions(model); + dispatchEffects(managers, cmds, subs); + callback(_elm_lang$core$Native_Scheduler.succeed(model)); + }); + } + + var mainProcess = spawnLoop(initApp, onMessage); + + function enqueue(msg) + { + _elm_lang$core$Native_Scheduler.rawSend(mainProcess, msg); + } + + var ports = setupEffects(managers, enqueue); + + return ports ? { ports: ports } : {}; +} + + +// EFFECT MANAGERS + +var effectManagers = {}; + +function setupEffects(managers, callback) +{ + var ports; + + // setup all necessary effect managers + for (var key in effectManagers) + { + var manager = effectManagers[key]; + + if (manager.isForeign) + { + ports = ports || {}; + ports[key] = manager.tag === 'cmd' + ? setupOutgoingPort(key) + : setupIncomingPort(key, callback); + } + + managers[key] = makeManager(manager, callback); + } + + return ports; +} + +function makeManager(info, callback) +{ + var router = { + main: callback, + self: undefined + }; + + var tag = info.tag; + var onEffects = info.onEffects; + var onSelfMsg = info.onSelfMsg; + + function onMessage(msg, state) + { + if (msg.ctor === 'self') + { + return A3(onSelfMsg, router, msg._0, state); + } + + var fx = msg._0; + switch (tag) + { + case 'cmd': + return A3(onEffects, router, fx.cmds, state); + + case 'sub': + return A3(onEffects, router, fx.subs, state); + + case 'fx': + return A4(onEffects, router, fx.cmds, fx.subs, state); + } + } + + var process = spawnLoop(info.init, onMessage); + router.self = process; + return process; +} + +function sendToApp(router, msg) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + router.main(msg); + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sendToSelf(router, msg) +{ + return A2(_elm_lang$core$Native_Scheduler.send, router.self, { + ctor: 'self', + _0: msg + }); +} + + +// HELPER for STATEFUL LOOPS + +function spawnLoop(init, onMessage) +{ + var andThen = _elm_lang$core$Native_Scheduler.andThen; + + function loop(state) + { + var handleMsg = _elm_lang$core$Native_Scheduler.receive(function(msg) { + return onMessage(msg, state); + }); + return A2(andThen, loop, handleMsg); + } + + var task = A2(andThen, loop, init); + + return _elm_lang$core$Native_Scheduler.rawSpawn(task); +} + + +// BAGS + +function leaf(home) +{ + return function(value) + { + return { + type: 'leaf', + home: home, + value: value + }; + }; +} + +function batch(list) +{ + return { + type: 'node', + branches: list + }; +} + +function map(tagger, bag) +{ + return { + type: 'map', + tagger: tagger, + tree: bag + } +} + + +// PIPE BAGS INTO EFFECT MANAGERS + +function dispatchEffects(managers, cmdBag, subBag) +{ + var effectsDict = {}; + gatherEffects(true, cmdBag, effectsDict, null); + gatherEffects(false, subBag, effectsDict, null); + + for (var home in managers) + { + var fx = home in effectsDict + ? effectsDict[home] + : { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + + _elm_lang$core$Native_Scheduler.rawSend(managers[home], { ctor: 'fx', _0: fx }); + } +} + +function gatherEffects(isCmd, bag, effectsDict, taggers) +{ + switch (bag.type) + { + case 'leaf': + var home = bag.home; + var effect = toEffect(isCmd, home, taggers, bag.value); + effectsDict[home] = insert(isCmd, effect, effectsDict[home]); + return; + + case 'node': + var list = bag.branches; + while (list.ctor !== '[]') + { + gatherEffects(isCmd, list._0, effectsDict, taggers); + list = list._1; + } + return; + + case 'map': + gatherEffects(isCmd, bag.tree, effectsDict, { + tagger: bag.tagger, + rest: taggers + }); + return; + } +} + +function toEffect(isCmd, home, taggers, value) +{ + function applyTaggers(x) + { + var temp = taggers; + while (temp) + { + x = temp.tagger(x); + temp = temp.rest; + } + return x; + } + + var map = isCmd + ? effectManagers[home].cmdMap + : effectManagers[home].subMap; + + return A2(map, applyTaggers, value) +} + +function insert(isCmd, newEffect, effects) +{ + effects = effects || { + cmds: _elm_lang$core$Native_List.Nil, + subs: _elm_lang$core$Native_List.Nil + }; + if (isCmd) + { + effects.cmds = _elm_lang$core$Native_List.Cons(newEffect, effects.cmds); + return effects; + } + effects.subs = _elm_lang$core$Native_List.Cons(newEffect, effects.subs); + return effects; +} + + +// PORTS + +function checkPortName(name) +{ + if (name in effectManagers) + { + throw new Error('There can only be one port named `' + name + '`, but your program has multiple.'); + } +} + + +// OUTGOING PORTS + +function outgoingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'cmd', + cmdMap: outgoingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var outgoingPortMap = F2(function cmdMap(tagger, value) { + return value; +}); + +function setupOutgoingPort(name) +{ + var subs = []; + var converter = effectManagers[name].converter; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function onEffects(router, cmdList, state) + { + while (cmdList.ctor !== '[]') + { + // grab a separate reference to subs in case unsubscribe is called + var currentSubs = subs; + var value = converter(cmdList._0); + for (var i = 0; i < currentSubs.length; i++) + { + currentSubs[i](value); + } + cmdList = cmdList._1; + } + return init; + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function subscribe(callback) + { + subs.push(callback); + } + + function unsubscribe(callback) + { + // copy subs into a new array in case unsubscribe is called within a + // subscribed callback + subs = subs.slice(); + var index = subs.indexOf(callback); + if (index >= 0) + { + subs.splice(index, 1); + } + } + + return { + subscribe: subscribe, + unsubscribe: unsubscribe + }; +} + + +// INCOMING PORTS + +function incomingPort(name, converter) +{ + checkPortName(name); + effectManagers[name] = { + tag: 'sub', + subMap: incomingPortMap, + converter: converter, + isForeign: true + }; + return leaf(name); +} + +var incomingPortMap = F2(function subMap(tagger, finalTagger) +{ + return function(value) + { + return tagger(finalTagger(value)); + }; +}); + +function setupIncomingPort(name, callback) +{ + var sentBeforeInit = []; + var subs = _elm_lang$core$Native_List.Nil; + var converter = effectManagers[name].converter; + var currentOnEffects = preInitOnEffects; + var currentSend = preInitSend; + + // CREATE MANAGER + + var init = _elm_lang$core$Native_Scheduler.succeed(null); + + function preInitOnEffects(router, subList, state) + { + var postInitResult = postInitOnEffects(router, subList, state); + + for(var i = 0; i < sentBeforeInit.length; i++) + { + postInitSend(sentBeforeInit[i]); + } + + sentBeforeInit = null; // to release objects held in queue + currentSend = postInitSend; + currentOnEffects = postInitOnEffects; + return postInitResult; + } + + function postInitOnEffects(router, subList, state) + { + subs = subList; + return init; + } + + function onEffects(router, subList, state) + { + return currentOnEffects(router, subList, state); + } + + effectManagers[name].init = init; + effectManagers[name].onEffects = F3(onEffects); + + // PUBLIC API + + function preInitSend(value) + { + sentBeforeInit.push(value); + } + + function postInitSend(value) + { + var temp = subs; + while (temp.ctor !== '[]') + { + callback(temp._0(value)); + temp = temp._1; + } + } + + function send(incomingValue) + { + var result = A2(_elm_lang$core$Json_Decode$decodeValue, converter, incomingValue); + if (result.ctor === 'Err') + { + throw new Error('Trying to send an unexpected type of value through port `' + name + '`:\n' + result._0); + } + + currentSend(result._0); + } + + return { send: send }; +} + +return { + // routers + sendToApp: F2(sendToApp), + sendToSelf: F2(sendToSelf), + + // global setup + effectManagers: effectManagers, + outgoingPort: outgoingPort, + incomingPort: incomingPort, + + htmlToProgram: htmlToProgram, + program: program, + programWithFlags: programWithFlags, + initialize: initialize, + + // effect bags + leaf: leaf, + batch: batch, + map: F2(map) +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js new file mode 100644 index 0000000..d3cc0dd --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Regex.js @@ -0,0 +1,119 @@ +//import Maybe, Native.List // + +var _elm_lang$core$Native_Regex = function() { + +function escape(str) +{ + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +} +function caseInsensitive(re) +{ + return new RegExp(re.source, 'gi'); +} +function regex(raw) +{ + return new RegExp(raw, 'g'); +} + +function contains(re, string) +{ + return string.match(re) !== null; +} + +function find(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var out = []; + var number = 0; + var string = str; + var lastIndex = re.lastIndex; + var prevLastIndex = -1; + var result; + while (number++ < n && (result = re.exec(string))) + { + if (prevLastIndex === re.lastIndex) break; + var i = result.length - 1; + var subs = new Array(i); + while (i > 0) + { + var submatch = result[i]; + subs[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + out.push({ + match: result[0], + submatches: _elm_lang$core$Native_List.fromArray(subs), + index: result.index, + number: number + }); + prevLastIndex = re.lastIndex; + } + re.lastIndex = lastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +function replace(n, re, replacer, string) +{ + n = n.ctor === 'All' ? Infinity : n._0; + var count = 0; + function jsReplacer(match) + { + if (count++ >= n) + { + return match; + } + var i = arguments.length - 3; + var submatches = new Array(i); + while (i > 0) + { + var submatch = arguments[i]; + submatches[--i] = submatch === undefined + ? _elm_lang$core$Maybe$Nothing + : _elm_lang$core$Maybe$Just(submatch); + } + return replacer({ + match: match, + submatches: _elm_lang$core$Native_List.fromArray(submatches), + index: arguments[arguments.length - 2], + number: count + }); + } + return string.replace(re, jsReplacer); +} + +function split(n, re, str) +{ + n = n.ctor === 'All' ? Infinity : n._0; + if (n === Infinity) + { + return _elm_lang$core$Native_List.fromArray(str.split(re)); + } + var string = str; + var result; + var out = []; + var start = re.lastIndex; + var restoreLastIndex = re.lastIndex; + while (n--) + { + if (!(result = re.exec(string))) break; + out.push(string.slice(start, result.index)); + start = re.lastIndex; + } + out.push(string.slice(start)); + re.lastIndex = restoreLastIndex; + return _elm_lang$core$Native_List.fromArray(out); +} + +return { + regex: regex, + caseInsensitive: caseInsensitive, + escape: escape, + + contains: F2(contains), + find: F3(find), + replace: F4(replace), + split: F3(split) +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js new file mode 100644 index 0000000..00f8259 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Scheduler.js @@ -0,0 +1,281 @@ +//import Native.Utils // + +var _elm_lang$core$Native_Scheduler = function() { + +var MAX_STEPS = 10000; + + +// TASKS + +function succeed(value) +{ + return { + ctor: '_Task_succeed', + value: value + }; +} + +function fail(error) +{ + return { + ctor: '_Task_fail', + value: error + }; +} + +function nativeBinding(callback) +{ + return { + ctor: '_Task_nativeBinding', + callback: callback, + cancel: null + }; +} + +function andThen(callback, task) +{ + return { + ctor: '_Task_andThen', + callback: callback, + task: task + }; +} + +function onError(callback, task) +{ + return { + ctor: '_Task_onError', + callback: callback, + task: task + }; +} + +function receive(callback) +{ + return { + ctor: '_Task_receive', + callback: callback + }; +} + + +// PROCESSES + +function rawSpawn(task) +{ + var process = { + ctor: '_Process', + id: _elm_lang$core$Native_Utils.guid(), + root: task, + stack: null, + mailbox: [] + }; + + enqueue(process); + + return process; +} + +function spawn(task) +{ + return nativeBinding(function(callback) { + var process = rawSpawn(task); + callback(succeed(process)); + }); +} + +function rawSend(process, msg) +{ + process.mailbox.push(msg); + enqueue(process); +} + +function send(process, msg) +{ + return nativeBinding(function(callback) { + rawSend(process, msg); + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function kill(process) +{ + return nativeBinding(function(callback) { + var root = process.root; + if (root.ctor === '_Task_nativeBinding' && root.cancel) + { + root.cancel(); + } + + process.root = null; + + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + +function sleep(time) +{ + return nativeBinding(function(callback) { + var id = setTimeout(function() { + callback(succeed(_elm_lang$core$Native_Utils.Tuple0)); + }, time); + + return function() { clearTimeout(id); }; + }); +} + + +// STEP PROCESSES + +function step(numSteps, process) +{ + while (numSteps < MAX_STEPS) + { + var ctor = process.root.ctor; + + if (ctor === '_Task_succeed') + { + while (process.stack && process.stack.ctor === '_Task_onError') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_fail') + { + while (process.stack && process.stack.ctor === '_Task_andThen') + { + process.stack = process.stack.rest; + } + if (process.stack === null) + { + break; + } + process.root = process.stack.callback(process.root.value); + process.stack = process.stack.rest; + ++numSteps; + continue; + } + + if (ctor === '_Task_andThen') + { + process.stack = { + ctor: '_Task_andThen', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_onError') + { + process.stack = { + ctor: '_Task_onError', + callback: process.root.callback, + rest: process.stack + }; + process.root = process.root.task; + ++numSteps; + continue; + } + + if (ctor === '_Task_nativeBinding') + { + process.root.cancel = process.root.callback(function(newRoot) { + process.root = newRoot; + enqueue(process); + }); + + break; + } + + if (ctor === '_Task_receive') + { + var mailbox = process.mailbox; + if (mailbox.length === 0) + { + break; + } + + process.root = process.root.callback(mailbox.shift()); + ++numSteps; + continue; + } + + throw new Error(ctor); + } + + if (numSteps < MAX_STEPS) + { + return numSteps + 1; + } + enqueue(process); + + return numSteps; +} + + +// WORK QUEUE + +var working = false; +var workQueue = []; + +function enqueue(process) +{ + workQueue.push(process); + + if (!working) + { + setTimeout(work, 0); + working = true; + } +} + +function work() +{ + var numSteps = 0; + var process; + while (numSteps < MAX_STEPS && (process = workQueue.shift())) + { + if (process.root) + { + numSteps = step(numSteps, process); + } + } + if (!process) + { + working = false; + return; + } + setTimeout(work, 0); +} + + +return { + succeed: succeed, + fail: fail, + nativeBinding: nativeBinding, + andThen: F2(andThen), + onError: F2(onError), + receive: receive, + + spawn: spawn, + kill: kill, + sleep: sleep, + send: F2(send), + + rawSpawn: rawSpawn, + rawSend: rawSend +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js new file mode 100644 index 0000000..3a21c76 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/String.js @@ -0,0 +1,339 @@ +//import Maybe, Native.List, Native.Utils, Result // + +var _elm_lang$core$Native_String = function() { + +function isEmpty(str) +{ + return str.length === 0; +} +function cons(chr, str) +{ + return chr + str; +} +function uncons(str) +{ + var hd = str[0]; + if (hd) + { + return _elm_lang$core$Maybe$Just(_elm_lang$core$Native_Utils.Tuple2(_elm_lang$core$Native_Utils.chr(hd), str.slice(1))); + } + return _elm_lang$core$Maybe$Nothing; +} +function append(a, b) +{ + return a + b; +} +function concat(strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(''); +} +function length(str) +{ + return str.length; +} +function map(f, str) +{ + var out = str.split(''); + for (var i = out.length; i--; ) + { + out[i] = f(_elm_lang$core$Native_Utils.chr(out[i])); + } + return out.join(''); +} +function filter(pred, str) +{ + return str.split('').map(_elm_lang$core$Native_Utils.chr).filter(pred).join(''); +} +function reverse(str) +{ + return str.split('').reverse().join(''); +} +function foldl(f, b, str) +{ + var len = str.length; + for (var i = 0; i < len; ++i) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function foldr(f, b, str) +{ + for (var i = str.length; i--; ) + { + b = A2(f, _elm_lang$core$Native_Utils.chr(str[i]), b); + } + return b; +} +function split(sep, str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(sep)); +} +function join(sep, strs) +{ + return _elm_lang$core$Native_List.toArray(strs).join(sep); +} +function repeat(n, str) +{ + var result = ''; + while (n > 0) + { + if (n & 1) + { + result += str; + } + n >>= 1, str += str; + } + return result; +} +function slice(start, end, str) +{ + return str.slice(start, end); +} +function left(n, str) +{ + return n < 1 ? '' : str.slice(0, n); +} +function right(n, str) +{ + return n < 1 ? '' : str.slice(-n); +} +function dropLeft(n, str) +{ + return n < 1 ? str : str.slice(n); +} +function dropRight(n, str) +{ + return n < 1 ? str : str.slice(0, -n); +} +function pad(n, chr, str) +{ + var half = (n - str.length) / 2; + return repeat(Math.ceil(half), chr) + str + repeat(half | 0, chr); +} +function padRight(n, chr, str) +{ + return str + repeat(n - str.length, chr); +} +function padLeft(n, chr, str) +{ + return repeat(n - str.length, chr) + str; +} + +function trim(str) +{ + return str.trim(); +} +function trimLeft(str) +{ + return str.replace(/^\s+/, ''); +} +function trimRight(str) +{ + return str.replace(/\s+$/, ''); +} + +function words(str) +{ + return _elm_lang$core$Native_List.fromArray(str.trim().split(/\s+/g)); +} +function lines(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split(/\r\n|\r|\n/g)); +} + +function toUpper(str) +{ + return str.toUpperCase(); +} +function toLower(str) +{ + return str.toLowerCase(); +} + +function any(pred, str) +{ + for (var i = str.length; i--; ) + { + if (pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return true; + } + } + return false; +} +function all(pred, str) +{ + for (var i = str.length; i--; ) + { + if (!pred(_elm_lang$core$Native_Utils.chr(str[i]))) + { + return false; + } + } + return true; +} + +function contains(sub, str) +{ + return str.indexOf(sub) > -1; +} +function startsWith(sub, str) +{ + return str.indexOf(sub) === 0; +} +function endsWith(sub, str) +{ + return str.length >= sub.length && + str.lastIndexOf(sub) === str.length - sub.length; +} +function indexes(sub, str) +{ + var subLen = sub.length; + + if (subLen < 1) + { + return _elm_lang$core$Native_List.Nil; + } + + var i = 0; + var is = []; + + while ((i = str.indexOf(sub, i)) > -1) + { + is.push(i); + i = i + subLen; + } + + return _elm_lang$core$Native_List.fromArray(is); +} + + +function toInt(s) +{ + var len = s.length; + + // if empty + if (len === 0) + { + return intErr(s); + } + + // if hex + var c = s[0]; + if (c === '0' && s[1] === 'x') + { + for (var i = 2; i < len; ++i) + { + var c = s[i]; + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) + { + continue; + } + return intErr(s); + } + return _elm_lang$core$Result$Ok(parseInt(s, 16)); + } + + // is decimal + if (c > '9' || (c < '0' && c !== '-' && c !== '+')) + { + return intErr(s); + } + for (var i = 1; i < len; ++i) + { + var c = s[i]; + if (c < '0' || '9' < c) + { + return intErr(s); + } + } + + return _elm_lang$core$Result$Ok(parseInt(s, 10)); +} + +function intErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to an Int"); +} + + +function toFloat(s) +{ + // check if it is a hex, octal, or binary number + if (s.length === 0 || /[\sxbo]/.test(s)) + { + return floatErr(s); + } + var n = +s; + // faster isNaN check + return n === n ? _elm_lang$core$Result$Ok(n) : floatErr(s); +} + +function floatErr(s) +{ + return _elm_lang$core$Result$Err("could not convert string '" + s + "' to a Float"); +} + + +function toList(str) +{ + return _elm_lang$core$Native_List.fromArray(str.split('').map(_elm_lang$core$Native_Utils.chr)); +} +function fromList(chars) +{ + return _elm_lang$core$Native_List.toArray(chars).join(''); +} + +return { + isEmpty: isEmpty, + cons: F2(cons), + uncons: uncons, + append: F2(append), + concat: concat, + length: length, + map: F2(map), + filter: F2(filter), + reverse: reverse, + foldl: F3(foldl), + foldr: F3(foldr), + + split: F2(split), + join: F2(join), + repeat: F2(repeat), + + slice: F3(slice), + left: F2(left), + right: F2(right), + dropLeft: F2(dropLeft), + dropRight: F2(dropRight), + + pad: F3(pad), + padLeft: F3(padLeft), + padRight: F3(padRight), + + trim: trim, + trimLeft: trimLeft, + trimRight: trimRight, + + words: words, + lines: lines, + + toUpper: toUpper, + toLower: toLower, + + any: F2(any), + all: F2(all), + + contains: F2(contains), + startsWith: F2(startsWith), + endsWith: F2(endsWith), + indexes: F2(indexes), + + toInt: toInt, + toFloat: toFloat, + toList: toList, + fromList: fromList +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js new file mode 100644 index 0000000..6b665ea --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Time.js @@ -0,0 +1,27 @@ +//import Native.Scheduler // + +var _elm_lang$core$Native_Time = function() { + +var now = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + callback(_elm_lang$core$Native_Scheduler.succeed(Date.now())); +}); + +function setInterval_(interval, task) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var id = setInterval(function() { + _elm_lang$core$Native_Scheduler.rawSpawn(task); + }, interval); + + return function() { clearInterval(id); }; + }); +} + +return { + now: now, + setInterval_: F2(setInterval_) +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js new file mode 100644 index 0000000..20aed5f --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Native/Utils.js @@ -0,0 +1,488 @@ +//import // + +var _elm_lang$core$Native_Utils = function() { + +// COMPARISONS + +function eq(x, y) +{ + var stack = []; + var isEqual = eqHelp(x, y, 0, stack); + var pair; + while (isEqual && (pair = stack.pop())) + { + isEqual = eqHelp(pair.x, pair.y, 0, stack); + } + return isEqual; +} + + +function eqHelp(x, y, depth, stack) +{ + if (depth > 100) + { + stack.push({ x: x, y: y }); + return true; + } + + if (x === y) + { + return true; + } + + if (typeof x !== 'object') + { + if (typeof x === 'function') + { + throw new Error( + 'Trying to use `(==)` on functions. There is no way to know if functions are "the same" in the Elm sense.' + + ' Read more about this at http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#==' + + ' which describes why it is this way and what the better version will look like.' + ); + } + return false; + } + + if (x === null || y === null) + { + return false + } + + if (x instanceof Date) + { + return x.getTime() === y.getTime(); + } + + if (!('ctor' in x)) + { + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; + } + + // convert Dicts and Sets to lists + if (x.ctor === 'RBNode_elm_builtin' || x.ctor === 'RBEmpty_elm_builtin') + { + x = _elm_lang$core$Dict$toList(x); + y = _elm_lang$core$Dict$toList(y); + } + if (x.ctor === 'Set_elm_builtin') + { + x = _elm_lang$core$Set$toList(x); + y = _elm_lang$core$Set$toList(y); + } + + // check if lists are equal without recursion + if (x.ctor === '::') + { + var a = x; + var b = y; + while (a.ctor === '::' && b.ctor === '::') + { + if (!eqHelp(a._0, b._0, depth + 1, stack)) + { + return false; + } + a = a._1; + b = b._1; + } + return a.ctor === b.ctor; + } + + // check if Arrays are equal + if (x.ctor === '_Array') + { + var xs = _elm_lang$core$Native_Array.toJSArray(x); + var ys = _elm_lang$core$Native_Array.toJSArray(y); + if (xs.length !== ys.length) + { + return false; + } + for (var i = 0; i < xs.length; i++) + { + if (!eqHelp(xs[i], ys[i], depth + 1, stack)) + { + return false; + } + } + return true; + } + + if (!eqHelp(x.ctor, y.ctor, depth + 1, stack)) + { + return false; + } + + for (var key in x) + { + if (!eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; +} + +// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on +// the particular integer values assigned to LT, EQ, and GT. + +var LT = -1, EQ = 0, GT = 1; + +function cmp(x, y) +{ + if (typeof x !== 'object') + { + return x === y ? EQ : x < y ? LT : GT; + } + + if (x instanceof String) + { + var a = x.valueOf(); + var b = y.valueOf(); + return a === b ? EQ : a < b ? LT : GT; + } + + if (x.ctor === '::' || x.ctor === '[]') + { + while (x.ctor === '::' && y.ctor === '::') + { + var ord = cmp(x._0, y._0); + if (ord !== EQ) + { + return ord; + } + x = x._1; + y = y._1; + } + return x.ctor === y.ctor ? EQ : x.ctor === '[]' ? LT : GT; + } + + if (x.ctor.slice(0, 6) === '_Tuple') + { + var ord; + var n = x.ctor.slice(6) - 0; + var err = 'cannot compare tuples with more than 6 elements.'; + if (n === 0) return EQ; + if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord; + if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord; + if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord; + if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord; + if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord; + if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord; + if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } } + return EQ; + } + + throw new Error( + 'Comparison error: comparison is only defined on ints, ' + + 'floats, times, chars, strings, lists of comparable values, ' + + 'and tuples of comparable values.' + ); +} + + +// COMMON VALUES + +var Tuple0 = { + ctor: '_Tuple0' +}; + +function Tuple2(x, y) +{ + return { + ctor: '_Tuple2', + _0: x, + _1: y + }; +} + +function chr(c) +{ + return new String(c); +} + + +// GUID + +var count = 0; +function guid(_) +{ + return count++; +} + + +// RECORDS + +function update(oldRecord, updatedFields) +{ + var newRecord = {}; + + for (var key in oldRecord) + { + newRecord[key] = oldRecord[key]; + } + + for (var key in updatedFields) + { + newRecord[key] = updatedFields[key]; + } + + return newRecord; +} + + +//// LIST STUFF //// + +var Nil = { ctor: '[]' }; + +function Cons(hd, tl) +{ + return { + ctor: '::', + _0: hd, + _1: tl + }; +} + +function append(xs, ys) +{ + // append Strings + if (typeof xs === 'string') + { + return xs + ys; + } + + // append Lists + if (xs.ctor === '[]') + { + return ys; + } + var root = Cons(xs._0, Nil); + var curr = root; + xs = xs._1; + while (xs.ctor !== '[]') + { + curr._1 = Cons(xs._0, Nil); + xs = xs._1; + curr = curr._1; + } + curr._1 = ys; + return root; +} + + +// CRASHES + +function crash(moduleName, region) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '` ' + regionToString(region) + '\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function crashCase(moduleName, region, value) +{ + return function(message) { + throw new Error( + 'Ran into a `Debug.crash` in module `' + moduleName + '`\n\n' + + 'This was caused by the `case` expression ' + regionToString(region) + '.\n' + + 'One of the branches ended with a crash and the following value got through:\n\n ' + toString(value) + '\n\n' + + 'The message provided by the code author is:\n\n ' + + message + ); + }; +} + +function regionToString(region) +{ + if (region.start.line == region.end.line) + { + return 'on line ' + region.start.line; + } + return 'between lines ' + region.start.line + ' and ' + region.end.line; +} + + +// TO STRING + +function toString(v) +{ + var type = typeof v; + if (type === 'function') + { + return ''; + } + + if (type === 'boolean') + { + return v ? 'True' : 'False'; + } + + if (type === 'number') + { + return v + ''; + } + + if (v instanceof String) + { + return '\'' + addSlashes(v, true) + '\''; + } + + if (type === 'string') + { + return '"' + addSlashes(v, false) + '"'; + } + + if (v === null) + { + return 'null'; + } + + if (type === 'object' && 'ctor' in v) + { + var ctorStarter = v.ctor.substring(0, 5); + + if (ctorStarter === '_Tupl') + { + var output = []; + for (var k in v) + { + if (k === 'ctor') continue; + output.push(toString(v[k])); + } + return '(' + output.join(',') + ')'; + } + + if (ctorStarter === '_Task') + { + return '' + } + + if (v.ctor === '_Array') + { + var list = _elm_lang$core$Array$toList(v); + return 'Array.fromList ' + toString(list); + } + + if (v.ctor === '') + { + return ''; + } + + if (v.ctor === '_Process') + { + return ''; + } + + if (v.ctor === '::') + { + var output = '[' + toString(v._0); + v = v._1; + while (v.ctor === '::') + { + output += ',' + toString(v._0); + v = v._1; + } + return output + ']'; + } + + if (v.ctor === '[]') + { + return '[]'; + } + + if (v.ctor === 'Set_elm_builtin') + { + return 'Set.fromList ' + toString(_elm_lang$core$Set$toList(v)); + } + + if (v.ctor === 'RBNode_elm_builtin' || v.ctor === 'RBEmpty_elm_builtin') + { + return 'Dict.fromList ' + toString(_elm_lang$core$Dict$toList(v)); + } + + var output = ''; + for (var i in v) + { + if (i === 'ctor') continue; + var str = toString(v[i]); + var c0 = str[0]; + var parenless = c0 === '{' || c0 === '(' || c0 === '<' || c0 === '"' || str.indexOf(' ') < 0; + output += ' ' + (parenless ? str : '(' + str + ')'); + } + return v.ctor + output; + } + + if (type === 'object') + { + if (v instanceof Date) + { + return '<' + v.toString() + '>'; + } + + if (v.elm_web_socket) + { + return ''; + } + + var output = []; + for (var k in v) + { + output.push(k + ' = ' + toString(v[k])); + } + if (output.length === 0) + { + return '{}'; + } + return '{ ' + output.join(', ') + ' }'; + } + + return ''; +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + eq: eq, + cmp: cmp, + Tuple0: Tuple0, + Tuple2: Tuple2, + chr: chr, + update: update, + guid: guid, + + append: F2(append), + + crash: crash, + crashCase: crashCase, + + toString: toString +}; + +}(); \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm new file mode 100644 index 0000000..2a136cc --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform.elm @@ -0,0 +1,145 @@ +module Platform exposing + ( Program, program, programWithFlags + , Task, ProcessId + , Router, sendToApp, sendToSelf + ) + +{-| + +# Programs +@docs Program, program, programWithFlags + +# Platform Internals + +## Tasks and Processes +@docs Task, ProcessId + +## Effect Manager Helpers + +An extremely tiny portion of library authors should ever write effect managers. +Fundamentally, Elm needs maybe 10 of them total. I get that people are smart, +curious, etc. but that is not a substitute for a legitimate reason to make an +effect manager. Do you have an *organic need* this fills? Or are you just +curious? Public discussions of your explorations should be framed accordingly. + +@docs Router, sendToApp, sendToSelf +-} + +import Basics exposing (Never) +import Native.Platform +import Native.Scheduler +import Platform.Cmd exposing (Cmd) +import Platform.Sub exposing (Sub) + + + +-- PROGRAMS + + +{-| A `Program` describes how to manage your Elm app. + +You can create [headless][] programs with the [`program`](#program) and +[`programWithFlags`](#programWithFlags) functions. Similar functions exist in +[`Html`][html] that let you specify a view. + +[headless]: https://en.wikipedia.org/wiki/Headless_software +[html]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html + +Honestly, it is totally normal if this seems crazy at first. The best way to +understand is to work through [guide.elm-lang.org](http://guide.elm-lang.org/). +It makes way more sense in context! +-} +type Program flags model msg = Program + + +{-| Create a [headless][] program. This is great if you want to use Elm as the +“brain” for something else. You can still communicate with JS via +ports and manage your model, you just do not have to specify a `view`. + +[headless]: https://en.wikipedia.org/wiki/Headless_software + +Initializing a headless program from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker(); +``` +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program Never model msg +program = + Native.Platform.program + + +{-| Same as [`program`](#program), but you can provide flags. Initializing a +headless program (with flags) from JavaScript looks like this: + +```javascript +var app = Elm.MyThing.worker({ user: 'Tom', token: 1234 }); +``` + +Whatever argument you provide to `worker` will get converted to an Elm value, +allowing you to configure your Elm program however you want from JavaScript! +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + } + -> Program flags model msg +programWithFlags = + Native.Platform.programWithFlags + + + +-- TASKS and PROCESSES + +{-| Head over to the documentation for the [`Task`](Task) module for more +information on this. It is only defined here because it is a platform +primitive. +-} +type Task err ok = Task + + +{-| Head over to the documentation for the [`Process`](Process) module for +information on this. It is only defined here because it is a platform +primitive. +-} +type ProcessId = ProcessId + + + +-- EFFECT MANAGER INTERNALS + + +{-| An effect manager has access to a “router” that routes messages between +the main app and your individual effect manager. +-} +type Router appMsg selfMsg = + Router + + +{-| Send the router a message for the main loop of your app. This message will +be handled by the overall `update` function, just like events from `Html`. +-} +sendToApp : Router msg a -> msg -> Task x () +sendToApp = + Native.Platform.sendToApp + + +{-| Send the router a message for your effect manager. This message will +be routed to the `onSelfMsg` function, where you can update the state of your +effect manager as necessary. + +As an example, the effect manager for web sockets +-} +sendToSelf : Router a msg -> msg -> Task x () +sendToSelf = + Native.Platform.sendToSelf + + +hack = + Native.Scheduler.succeed diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm new file mode 100644 index 0000000..a4ae4ed --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Cmd.elm @@ -0,0 +1,67 @@ +module Platform.Cmd exposing + ( Cmd + , map + , batch + , none + , (!) + ) + +{-| + +# Effects + +Elm has **managed effects**, meaning that things like HTTP requests or writing +to disk are all treated as *data* in Elm. When this data is given to the Elm +runtime system, it can do some “query optimization” before actually performing +the effect. Perhaps unexpectedly, this managed effects idea is the heart of why +Elm is so nice for testing, reuse, reproducibility, etc. + +There are two kinds of managed effects you will use in your programs: commands +and subscriptions. + +@docs Cmd, map, batch, none, (!) + +-} + +import Native.Platform + + +{-| A command is a way of telling Elm, “Hey, I want you to do this thing!” +So if you want to send an HTTP request, you would need to command Elm to do it. +Or if you wanted to ask for geolocation, you would need to command Elm to go +get it. + +Every `Cmd` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, commands will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they +fit into a real application! +-} +type Cmd msg = Cmd + + +{-|-} +map : (a -> msg) -> Cmd a -> Cmd msg +map = + Native.Platform.map + + +{-|-} +batch : List (Cmd msg) -> Cmd msg +batch = + Native.Platform.batch + + +{-|-} +none : Cmd msg +none = + batch [] + + +{-|-} +(!) : model -> List (Cmd msg) -> (model, Cmd msg) +(!) model commands = + (model, batch commands) + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm new file mode 100644 index 0000000..03f2f81 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Platform/Sub.elm @@ -0,0 +1,52 @@ +module Platform.Sub exposing + ( Sub + , map + , batch + , none + ) + +{-| + +@docs Sub, map, batch, none +-} + +import Native.Platform + + +{-| A subscription is a way of telling Elm, “Hey, let me know if anything +interesting happens over there!” So if you want to listen for messages on a web +socket, you would tell Elm to create a subscription. If you want to get clock +ticks, you would tell Elm to subscribe to that. The cool thing here is that +this means *Elm* manages all the details of subscriptions instead of *you*. +So if a web socket goes down, *you* do not need to manually reconnect with an +exponential backoff strategy, *Elm* does this all for you behind the scenes! + +Every `Sub` specifies (1) which effects you need access to and (2) the type of +messages that will come back into your application. + +**Note:** Do not worry if this seems confusing at first! As with every Elm user +ever, subscriptions will make more sense as you work through [the Elm Architecture +Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they fit +into a real application! +-} +type Sub msg = Sub + + +{-|-} +map : (a -> msg) -> Sub a -> Sub msg +map = + Native.Platform.map + + +{-|-} +batch : List (Sub msg) -> Sub msg +batch = + Native.Platform.batch + + +{-|-} +none : Sub msg +none = + batch [] + + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm new file mode 100644 index 0000000..0ef59af --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Process.elm @@ -0,0 +1,106 @@ +module Process exposing + ( Id + , spawn + , sleep + , kill + ) + +{-| + +# Processes +@docs Id, spawn, sleep, kill + +## Future Plans + +Right now, this library is pretty sparse. For example, there is no public API +for processes to communicate with each other. This is a really important +ability, but it is also something that is extraordinarily easy to get wrong! + +I think the trend will be towards an Erlang style of concurrency, where every +process has an “event queue” that anyone can send messages to. I currently +think the API will be extended to be more like this: + + type Id exit msg + + spawn : Task exit a -> Task x (Id exit Never) + + kill : Id exit msg -> Task x () + + send : Id exit msg -> msg -> Task x () + +A process `Id` will have two type variables to make sure all communication is +valid. The `exit` type describes the messages that are produced if the process +fails because of user code. So if processes are linked and trapping errors, +they will need to handle this. The `msg` type just describes what kind of +messages this process can be sent by strangers. + +We shall see though! This is just a draft that does not cover nearly everything +it needs to, so the long-term vision for concurrency in Elm will be rolling out +slowly as I get more data and experience. + +I ask that people bullish on compiling to node.js keep this in mind. I think we +can do better than the hopelessly bad concurrency model of node.js, and I hope +the Elm community will be supportive of being more ambitious, even if it takes +longer. That’s kind of what Elm is all about. +-} + +import Basics exposing (Never) +import Native.Scheduler +import Platform +import Task exposing (Task) +import Time exposing (Time) + + +{-| A light-weight process that runs concurrently. You can use `spawn` to +get a bunch of different tasks running in different processes. The Elm runtime +will interleave their progress. So if a task is taking too long, we will pause +it at an `andThen` and switch over to other stuff. + +**Note:** We make a distinction between *concurrency* which means interleaving +different sequences and *parallelism* which means running different +sequences at the exact same time. For example, a +[time-sharing system](https://en.wikipedia.org/wiki/Time-sharing) is definitely +concurrent, but not necessarily parallel. So even though JS runs within a +single OS-level thread, Elm can still run things concurrently. +-} +type alias Id = + Platform.ProcessId + + +{-| Run a task in its own light-weight process. In the following example, +`task1` and `task2` will be interleaved. If `task1` makes a long HTTP request +or is just taking a long time, we can hop over to `task2` and do some work +there. + + spawn task1 + |> Task.andThen (\_ -> spawn task2) + +**Note:** This creates a relatively restricted kind of `Process` because it +cannot receive any messages. More flexibility for user-defined processes will +come in a later release! +-} +spawn : Task x a -> Task y Id +spawn = + Native.Scheduler.spawn + + +{-| Block progress on the current process for a given amount of time. The +JavaScript equivalent of this is [`setTimeout`][setTimeout] which lets you +delay work until later. + +[setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout +-} +sleep : Time -> Task x () +sleep = + Native.Scheduler.sleep + + +{-| Sometimes you `spawn` a process, but later decide it would be a waste to +have it keep running and doing stuff. The `kill` function will force a process +to bail on whatever task it is running. So if there is an HTTP request in +flight, it will also abort the request. +-} +kill : Id -> Task x () +kill = + Native.Scheduler.kill + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm new file mode 100644 index 0000000..d506433 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Random.elm @@ -0,0 +1,532 @@ +effect module Random where { command = MyCmd } exposing + ( Generator, Seed + , bool, int, float + , list, pair + , map, map2, map3, map4, map5 + , andThen + , minInt, maxInt + , generate + , step, initialSeed + ) + +{-| This library helps you generate pseudo-random values. + +This library is all about building [`generators`](#Generator) for whatever +type of values you need. There are a bunch of primitive generators like +[`bool`](#bool) and [`int`](#int) that you can build up into fancier +generators with functions like [`list`](#list) and [`map`](#map). + +It may be helpful to [read about JSON decoders][json] because they work very +similarly. + +[json]: https://evancz.gitbooks.io/an-introduction-to-elm/content/interop/json.html + +> *Note:* This is an implementation of the Portable Combined Generator of +L'Ecuyer for 32-bit computers. It is almost a direct translation from the +[System.Random](http://hackage.haskell.org/package/random-1.0.1.1/docs/System-Random.html) +module. It has a period of roughly 2.30584e18. + +# Generators +@docs Generator + +# Primitive Generators +@docs bool, int, float + +# Data Structure Generators +@docs pair, list + +# Custom Generators +@docs map, map2, map3, map4, map5, andThen + +# Generate Values +@docs generate + +# Generate Values Manually +@docs step, Seed, initialSeed + +# Constants +@docs maxInt, minInt + +-} + +import Basics exposing (..) +import List exposing ((::)) +import Platform +import Platform.Cmd exposing (Cmd) +import Task exposing (Task) +import Time +import Tuple + + + +-- PRIMITIVE GENERATORS + + +{-| Create a generator that produces boolean values. The following example +simulates a coin flip that may land heads or tails. + + type Flip = Heads | Tails + + coinFlip : Generator Flip + coinFlip = + map (\b -> if b then Heads else Tails) bool +-} +bool : Generator Bool +bool = + map ((==) 1) (int 0 1) + + +{-| Generate 32-bit integers in a given range. + + int 0 10 -- an integer between zero and ten + int -5 5 -- an integer between -5 and 5 + + int minInt maxInt -- an integer in the widest range feasible + +This function *can* produce values outside of the range [[`minInt`](#minInt), +[`maxInt`](#maxInt)] but sufficient randomness is not guaranteed. +-} +int : Int -> Int -> Generator Int +int a b = + Generator <| \(Seed seed) -> + let + (lo,hi) = + if a < b then (a,b) else (b,a) + + k = hi - lo + 1 + -- 2^31 - 87 + base = 2147483561 + n = iLogBase base k + + f n acc state = + case n of + 0 -> (acc, state) + _ -> + let + (x, nextState) = seed.next state + in + f (n - 1) (x + acc * base) nextState + + (v, nextState) = + f n 1 seed.state + in + ( lo + v % k + , Seed { seed | state = nextState } + ) + + +iLogBase : Int -> Int -> Int +iLogBase b i = + if i < b then + 1 + else + 1 + iLogBase b (i // b) + + +{-| The maximum value for randomly generated 32-bit ints: 2147483647 -} +maxInt : Int +maxInt = + 2147483647 + + +{-| The minimum value for randomly generated 32-bit ints: -2147483648 -} +minInt : Int +minInt = + -2147483648 + + +{-| Generate floats in a given range. The following example is a generator +that produces decimals between 0 and 1. + + probability : Generator Float + probability = + float 0 1 +-} +float : Float -> Float -> Generator Float +float a b = + Generator <| \seed -> + let + (lo, hi) = + if a < b then (a,b) else (b,a) + + (number, newSeed) = + step (int minInt maxInt) seed + + negativeOneToOne = + toFloat number / toFloat (maxInt - minInt) + + scaled = + (lo+hi)/2 + ((hi-lo) * negativeOneToOne) + in + (scaled, newSeed) + + + +-- DATA STRUCTURES + + +{-| Create a pair of random values. A common use of this might be to generate +a point in a certain 2D space. Imagine we have a collage that is 400 pixels +wide and 200 pixels tall. + + randomPoint : Generator (Int,Int) + randomPoint = + pair (int -200 200) (int -100 100) + +-} +pair : Generator a -> Generator b -> Generator (a,b) +pair genA genB = + map2 (,) genA genB + + +{-| Create a list of random values. + + floatList : Generator (List Float) + floatList = + list 10 (float 0 1) + + intList : Generator (List Int) + intList = + list 5 (int 0 100) + + intPairs : Generator (List (Int, Int)) + intPairs = + list 10 <| pair (int 0 100) (int 0 100) +-} +list : Int -> Generator a -> Generator (List a) +list n (Generator generate) = + Generator <| \seed -> + listHelp [] n generate seed + + +listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed) +listHelp list n generate seed = + if n < 1 then + (List.reverse list, seed) + + else + let + (value, newSeed) = + generate seed + in + listHelp (value :: list) (n-1) generate newSeed + + + +-- CUSTOM GENERATORS + + +{-| Transform the values produced by a generator. The following examples show +how to generate booleans and letters based on a basic integer generator. + + bool : Generator Bool + bool = + map ((==) 1) (int 0 1) + + lowercaseLetter : Generator Char + lowercaseLetter = + map (\n -> Char.fromCode (n + 97)) (int 0 25) + + uppercaseLetter : Generator Char + uppercaseLetter = + map (\n -> Char.fromCode (n + 65)) (int 0 25) + +-} +map : (a -> b) -> Generator a -> Generator b +map func (Generator genA) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + in + (func a, seed1) + + +{-| Combine two generators. + +This function is used to define things like [`pair`](#pair) where you want to +put two generators together. + + pair : Generator a -> Generator b -> Generator (a,b) + pair genA genB = + map2 (,) genA genB + +-} +map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c +map2 func (Generator genA) (Generator genB) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + in + (func a b, seed2) + + +{-| Combine three generators. This could be used to produce random colors. + + import Color + + rgb : Generator Color.Color + rgb = + map3 Color.rgb (int 0 255) (int 0 255) (int 0 255) + + hsl : Generator Color.Color + hsl = + map3 Color.hsl (map degrees (int 0 360)) (float 0 1) (float 0 1) +-} +map3 : (a -> b -> c -> d) -> Generator a -> Generator b -> Generator c -> Generator d +map3 func (Generator genA) (Generator genB) (Generator genC) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + in + (func a b c, seed3) + + +{-| Combine four generators. +-} +map4 : (a -> b -> c -> d -> e) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e +map4 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + in + (func a b c d, seed4) + + +{-| Combine five generators. +-} +map5 : (a -> b -> c -> d -> e -> f) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e -> Generator f +map5 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) (Generator genE) = + Generator <| \seed0 -> + let + (a, seed1) = genA seed0 + (b, seed2) = genB seed1 + (c, seed3) = genC seed2 + (d, seed4) = genD seed3 + (e, seed5) = genE seed4 + in + (func a b c d e, seed5) + + +{-| Chain random operations, threading through the seed. In the following +example, we will generate a random letter by putting together uppercase and +lowercase letters. + + letter : Generator Char + letter = + bool + |> andThen upperOrLower + + upperOrLower : Bool -> Generator Char + upperOrLower b = + if b then uppercaseLetter else lowercaseLetter + + -- bool : Generator Bool + -- uppercaseLetter : Generator Char + -- lowercaseLetter : Generator Char +-} +andThen : (a -> Generator b) -> Generator a -> Generator b +andThen callback (Generator generate) = + Generator <| \seed -> + let + (result, newSeed) = + generate seed + + (Generator genB) = + callback result + in + genB newSeed + + + +-- IMPLEMENTATION + + +{-| A `Generator` is like a recipe for generating certain random values. So a +`Generator Int` describes how to generate integers and a `Generator String` +describes how to generate strings. + +To actually *run* a generator and produce the random values, you need to use +functions like [`generate`](#generate) and [`initialSeed`](#initialSeed). +-} +type Generator a = + Generator (Seed -> (a, Seed)) + + +type State = State Int Int + + +{-| A `Seed` is the source of randomness in this whole system. Whenever +you want to use a generator, you need to pair it with a seed. +-} +type Seed = + Seed + { state : State + , next : State -> (Int, State) + , split : State -> (State, State) + , range : State -> (Int,Int) + } + + +{-| Generate a random value as specified by a given `Generator`. + +In the following example, we are trying to generate a number between 0 and 100 +with the `int 0 100` generator. Each time we call `step` we need to provide a +seed. This will produce a random number and a *new* seed to use if we want to +run other generators later. + +So here it is done right, where we get a new seed from each `step` call and +thread that through. + + seed0 = initialSeed 31415 + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed1 ==> (31, seed2) + -- step (int 0 100) seed2 ==> (99, seed3) + +Notice that we use different seeds on each line. This is important! If you use +the same seed, you get the same results. + + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) + -- step (int 0 100) seed0 ==> (42, seed1) +-} +step : Generator a -> Seed -> (a, Seed) +step (Generator generator) seed = + generator seed + + +{-| Create a “seed” of randomness which makes it possible to +generate random values. If you use the same seed many times, it will result +in the same thing every time! A good way to get an unexpected seed is to use +the current time. +-} +initialSeed : Int -> Seed +initialSeed n = + Seed + { state = initState n + , next = next + , split = split + , range = range + } + + +{-| Produce the initial generator state. Distinct arguments should be likely +to produce distinct generator states. +-} +initState : Int -> State +initState seed = + let + s = max seed -seed + q = s // (magicNum6-1) + s1 = s % (magicNum6-1) + s2 = q % (magicNum7-1) + in + State (s1+1) (s2+1) + + +magicNum0 = 40014 +magicNum1 = 53668 +magicNum2 = 12211 +magicNum3 = 52774 +magicNum4 = 40692 +magicNum5 = 3791 +magicNum6 = 2147483563 +magicNum7 = 2147483399 +magicNum8 = 2147483562 + + +next : State -> (Int, State) +next (State state1 state2) = + -- Div always rounds down and so random numbers are biased + -- ideally we would use division that rounds towards zero so + -- that in the negative case it rounds up and in the positive case + -- it rounds down. Thus half the time it rounds up and half the time it + -- rounds down + let + k1 = state1 // magicNum1 + rawState1 = magicNum0 * (state1 - k1 * magicNum1) - k1 * magicNum2 + newState1 = if rawState1 < 0 then rawState1 + magicNum6 else rawState1 + k2 = state2 // magicNum3 + rawState2 = magicNum4 * (state2 - k2 * magicNum3) - k2 * magicNum5 + newState2 = if rawState2 < 0 then rawState2 + magicNum7 else rawState2 + z = newState1 - newState2 + newZ = if z < 1 then z + magicNum8 else z + in + (newZ, State newState1 newState2) + + +split : State -> (State, State) +split (State s1 s2 as std) = + let + new_s1 = + if s1 == magicNum6-1 then 1 else s1 + 1 + + new_s2 = + if s2 == 1 then magicNum7-1 else s2 - 1 + + (State t1 t2) = + Tuple.second (next std) + in + (State new_s1 t2, State t1 new_s2) + + +range : State -> (Int,Int) +range _ = + (0, magicNum8) + + + +-- MANAGER + + +{-| Create a command that will generate random values. + +Read more about how to use this in your programs in [The Elm Architecture +tutorial][arch] which has a section specifically [about random values][rand]. + +[arch]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/index.html +[rand]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/effects/random.html +-} +generate : (a -> msg) -> Generator a -> Cmd msg +generate tagger generator = + command (Generate (map tagger generator)) + + +type MyCmd msg = Generate (Generator msg) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap func (Generate generator) = + Generate (map func generator) + + +init : Task Never Seed +init = + Time.now + |> Task.andThen (\t -> Task.succeed (initialSeed (round t))) + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> Seed -> Task Never Seed +onEffects router commands seed = + case commands of + [] -> + Task.succeed seed + + Generate generator :: rest -> + let + (value, newSeed) = + step generator seed + in + Platform.sendToApp router value + |> Task.andThen (\_ -> onEffects router rest newSeed) + + +onSelfMsg : Platform.Router msg Never -> Never -> Seed -> Task Never Seed +onSelfMsg _ _ seed = + Task.succeed seed diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm new file mode 100644 index 0000000..2d58ecf --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Regex.elm @@ -0,0 +1,148 @@ +module Regex exposing + ( Regex + , regex, escape, caseInsensitive + , HowMany(..), Match + , contains, find, replace, split + ) + +{-| A library for working with regular expressions. It uses [the +same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions). + +# Create +@docs Regex, regex, escape, caseInsensitive + +# Helpful Data Structures + +These data structures are needed to help define functions like [`find`](#find) +and [`replace`](#replace). + +@docs HowMany, Match + +# Use +@docs contains, find, replace, split + +-} + +import Maybe exposing (Maybe) +import Native.Regex + + +{-| A regular expression, describing a certain set of strings. +-} +type Regex = Regex + + +{-| Escape strings to be regular expressions, making all special characters +safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series +of `a`’s that start at the beginning of the line. +-} +escape : String -> String +escape = + Native.Regex.escape + + +{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern). + +Be careful to escape backslashes properly! For example, `"\w"` is escaping the +letter `w` which is probably not what you want. You probably want `"\\w"` +instead, which escapes the backslash. +-} +regex : String -> Regex +regex = + Native.Regex.regex + + + +{-| Make a regex case insensitive -} +caseInsensitive : Regex -> Regex +caseInsensitive = + Native.Regex.caseInsensitive + + +{-| Check to see if a Regex is contained in a string. + + contains (regex "123") "12345" == True + contains (regex "b+") "aabbcc" == True + + contains (regex "789") "12345" == False + contains (regex "z+") "aabbcc" == False +-} +contains : Regex -> String -> Bool +contains = + Native.Regex.contains + + +{-| A `Match` represents all of the details about a particular match in a string. +Here are details on each field: + + * `match` — the full string of the match. + * `submatches` — a regex might have [subpatterns, surrounded by + parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches). + If there are N subpatterns, there will be N elements in the `submatches` list. + Each submatch in this list is a `Maybe` because not all subpatterns may trigger. + For example, `(regex "(a+)|(b+)")` will either match many `a`’s or + many `b`’s, but never both. + * `index` — the index of the match in the original string. + * `number` — if you find many matches, you can think of each one + as being labeled with a `number` starting at one. So the first time you + find a match, that is match `number` one. Second time is match `number` two. + This is useful when paired with `replace All` if replacement is dependent on how + many times a pattern has appeared before. +-} +type alias Match = + { match : String + , submatches : List (Maybe String) + , index : Int + , number : Int + } + + +{-| `HowMany` is used to specify how many matches you want to make. So +`replace All` would replace every match, but `replace (AtMost 2)` would +replace at most two matches (i.e. zero, one, two, but never three or more). +-} +type HowMany = All | AtMost Int + + +{-| Find matches in a string: + + findTwoCommas = find (AtMost 2) (regex ",") + + -- map .index (findTwoCommas "a,b,c,d,e") == [1,3] + -- map .index (findTwoCommas "a b c d e") == [] + + places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake." + + -- map .match places == ["on a boat", "in a lake"] + -- map .submatches places == [ [Just "boat"], [Just "lake"] ] +-} +find : HowMany -> Regex -> String -> List Match +find = + Native.Regex.find + + +{-| Replace matches. The function from `Match` to `String` lets +you use the details of a specific match when making replacements. + + devowel = replace All (regex "[aeiou]") (\_ -> "") + + -- devowel "The quick brown fox" == "Th qck brwn fx" + + reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match) + + -- reverseWords "deliver mined parts" == "reviled denim strap" +-} +replace : HowMany -> Regex -> (Match -> String) -> String -> String +replace = + Native.Regex.replace + + +{-| Split a string, using the regex as the separator. + + split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"] + + split All (regex ",") "a,b,c,d" == ["a","b","c","d"] +-} +split : HowMany -> Regex -> String -> List String +split = + Native.Regex.split diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm new file mode 100644 index 0000000..61c678c --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Result.elm @@ -0,0 +1,210 @@ +module Result exposing + ( Result(..) + , withDefault + , map, map2, map3, map4, map5 + , andThen + , toMaybe, fromMaybe, mapError + ) + +{-| A `Result` is the result of a computation that may fail. This is a great +way to manage errors in Elm. + +# Type and Constructors +@docs Result + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen + +# Handling Errors +@docs withDefault, toMaybe, fromMaybe, mapError +-} + +import Maybe exposing ( Maybe(Just, Nothing) ) + + +{-| A `Result` is either `Ok` meaning the computation succeeded, or it is an +`Err` meaning that there was some failure. +-} +type Result error value + = Ok value + | Err error + + +{-| If the result is `Ok` return the value, but if the result is an `Err` then +return a given default value. The following examples try to parse integers. + + Result.withDefault 0 (String.toInt "123") == 123 + Result.withDefault 0 (String.toInt "abc") == 0 +-} +withDefault : a -> Result x a -> a +withDefault def result = + case result of + Ok a -> + a + + Err _ -> + def + + +{-| Apply a function to a result. If the result is `Ok`, it will be converted. +If the result is an `Err`, the same error value will propagate through. + + map sqrt (Ok 4.0) == Ok 2.0 + map sqrt (Err "bad input") == Err "bad input" +-} +map : (a -> value) -> Result x a -> Result x value +map func ra = + case ra of + Ok a -> Ok (func a) + Err e -> Err e + + +{-| Apply a function to two results, if both results are `Ok`. If not, +the first argument which is an `Err` will propagate through. + + map2 (+) (String.toInt "1") (String.toInt "2") == Ok 3 + map2 (+) (String.toInt "1") (String.toInt "y") == Err "could not convert string 'y' to an Int" + map2 (+) (String.toInt "x") (String.toInt "y") == Err "could not convert string 'x' to an Int" +-} +map2 : (a -> b -> value) -> Result x a -> Result x b -> Result x value +map2 func ra rb = + case (ra,rb) of + (Ok a, Ok b) -> Ok (func a b) + (Err x, _) -> Err x + (_, Err x) -> Err x + + +{-|-} +map3 : (a -> b -> c -> value) -> Result x a -> Result x b -> Result x c -> Result x value +map3 func ra rb rc = + case (ra,rb,rc) of + (Ok a, Ok b, Ok c) -> Ok (func a b c) + (Err x, _, _) -> Err x + (_, Err x, _) -> Err x + (_, _, Err x) -> Err x + + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x value +map4 func ra rb rc rd = + case (ra,rb,rc,rd) of + (Ok a, Ok b, Ok c, Ok d) -> Ok (func a b c d) + (Err x, _, _, _) -> Err x + (_, Err x, _, _) -> Err x + (_, _, Err x, _) -> Err x + (_, _, _, Err x) -> Err x + + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x e -> Result x value +map5 func ra rb rc rd re = + case (ra,rb,rc,rd,re) of + (Ok a, Ok b, Ok c, Ok d, Ok e) -> Ok (func a b c d e) + (Err x, _, _, _, _) -> Err x + (_, Err x, _, _, _) -> Err x + (_, _, Err x, _, _) -> Err x + (_, _, _, Err x, _) -> Err x + (_, _, _, _, Err x) -> Err x + + +{-| Chain together a sequence of computations that may fail. It is helpful +to see its definition: + + andThen : (a -> Result e b) -> Result e a -> Result e b + andThen callback result = + case result of + Ok value -> callback value + Err msg -> Err msg + +This means we only continue with the callback if things are going well. For +example, say you need to use (`toInt : String -> Result String Int`) to parse +a month and make sure it is between 1 and 12: + + toValidMonth : Int -> Result String Int + toValidMonth month = + if month >= 1 && month <= 12 + then Ok month + else Err "months must be between 1 and 12" + + toMonth : String -> Result String Int + toMonth rawString = + toInt rawString + |> andThen toValidMonth + + -- toMonth "4" == Ok 4 + -- toMonth "9" == Ok 9 + -- toMonth "a" == Err "cannot parse to an Int" + -- toMonth "0" == Err "months must be between 1 and 12" + +This allows us to come out of a chain of operations with quite a specific error +message. It is often best to create a custom type that explicitly represents +the exact ways your computation may fail. This way it is easy to handle in your +code. +-} +andThen : (a -> Result x b) -> Result x a -> Result x b +andThen callback result = + case result of + Ok value -> + callback value + + Err msg -> + Err msg + + +{-| Transform an `Err` value. For example, say the errors we get have too much +information: + + parseInt : String -> Result ParseError Int + + type alias ParseError = + { message : String + , code : Int + , position : (Int,Int) + } + + mapError .message (parseInt "123") == Ok 123 + mapError .message (parseInt "abc") == Err "char 'a' is not a number" +-} +mapError : (x -> y) -> Result x a -> Result y a +mapError f result = + case result of + Ok v -> + Ok v + + Err e -> + Err (f e) + + +{-| Convert to a simpler `Maybe` if the actual error message is not needed or +you need to interact with some code that primarily uses maybes. + + parseInt : String -> Result ParseError Int + + maybeParseInt : String -> Maybe Int + maybeParseInt string = + toMaybe (parseInt string) +-} +toMaybe : Result x a -> Maybe a +toMaybe result = + case result of + Ok v -> Just v + Err _ -> Nothing + + +{-| Convert from a simple `Maybe` to interact with some code that primarily +uses `Results`. + + parseInt : String -> Maybe Int + + resultParseInt : String -> Result String Int + resultParseInt string = + fromMaybe ("error parsing string: " ++ toString string) (parseInt string) +-} +fromMaybe : x -> Maybe a -> Result x a +fromMaybe err maybe = + case maybe of + Just v -> Ok v + Nothing -> Err err diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm new file mode 100644 index 0000000..9b1914a --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Set.elm @@ -0,0 +1,168 @@ +module Set exposing + ( Set + , empty, singleton, insert, remove + , isEmpty, member, size + , foldl, foldr, map + , filter, partition + , union, intersect, diff + , toList, fromList + ) + +{-| A set of unique values. The values can be any comparable type. This +includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or lists +of comparable types. + +Insert, remove, and query operations all take *O(log n)* time. + +# Sets +@docs Set + +# Build +@docs empty, singleton, insert, remove + +# Query +@docs isEmpty, member, size + +# Combine +@docs union, intersect, diff + +# Lists +@docs toList, fromList + +# Transform +@docs map, foldl, foldr, filter, partition + +-} + +import Basics exposing ((<|)) +import Dict as Dict +import List as List + + +{-| Represents a set of unique values. So `(Set Int)` is a set of integers and +`(Set String)` is a set of strings. +-} +type Set t = + Set_elm_builtin (Dict.Dict t ()) + + +{-| Create an empty set. +-} +empty : Set a +empty = + Set_elm_builtin Dict.empty + + +{-| Create a set with one value. +-} +singleton : comparable -> Set comparable +singleton k = + Set_elm_builtin <| Dict.singleton k () + + +{-| Insert a value into a set. +-} +insert : comparable -> Set comparable -> Set comparable +insert k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.insert k () d + + +{-| Remove a value from a set. If the value is not found, no changes are made. +-} +remove : comparable -> Set comparable -> Set comparable +remove k (Set_elm_builtin d) = + Set_elm_builtin <| Dict.remove k d + + +{-| Determine if a set is empty. +-} +isEmpty : Set a -> Bool +isEmpty (Set_elm_builtin d) = + Dict.isEmpty d + + +{-| Determine if a value is in a set. +-} +member : comparable -> Set comparable -> Bool +member k (Set_elm_builtin d) = + Dict.member k d + + +{-| Determine the number of elements in a set. +-} +size : Set a -> Int +size (Set_elm_builtin d) = + Dict.size d + + +{-| Get the union of two sets. Keep all values. +-} +union : Set comparable -> Set comparable -> Set comparable +union (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.union d1 d2 + + +{-| Get the intersection of two sets. Keeps values that appear in both sets. +-} +intersect : Set comparable -> Set comparable -> Set comparable +intersect (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.intersect d1 d2 + + +{-| Get the difference between the first set and the second. Keeps values +that do not appear in the second set. +-} +diff : Set comparable -> Set comparable -> Set comparable +diff (Set_elm_builtin d1) (Set_elm_builtin d2) = + Set_elm_builtin <| Dict.diff d1 d2 + + +{-| Convert a set into a list, sorted from lowest to highest. +-} +toList : Set comparable -> List comparable +toList (Set_elm_builtin d) = + Dict.keys d + + +{-| Convert a list into a set, removing any duplicates. +-} +fromList : List comparable -> Set comparable +fromList xs = List.foldl insert empty xs + + +{-| Fold over the values in a set, in order from lowest to highest. +-} +foldl : (comparable -> b -> b) -> b -> Set comparable -> b +foldl f b (Set_elm_builtin d) = + Dict.foldl (\k _ b -> f k b) b d + + +{-| Fold over the values in a set, in order from highest to lowest. +-} +foldr : (comparable -> b -> b) -> b -> Set comparable -> b +foldr f b (Set_elm_builtin d) = + Dict.foldr (\k _ b -> f k b) b d + + +{-| Map a function onto a set, creating a new set with no duplicates. +-} +map : (comparable -> comparable2) -> Set comparable -> Set comparable2 +map f s = fromList (List.map f (toList s)) + + +{-| Create a new set consisting only of elements which satisfy a predicate. +-} +filter : (comparable -> Bool) -> Set comparable -> Set comparable +filter p (Set_elm_builtin d) = + Set_elm_builtin <| Dict.filter (\k _ -> p k) d + + +{-| Create two new sets; the first consisting of elements which satisfy a +predicate, the second consisting of elements which do not. +-} +partition : (comparable -> Bool) -> Set comparable -> (Set comparable, Set comparable) +partition p (Set_elm_builtin d) = + let + (p1, p2) = Dict.partition (\k _ -> p k) d + in + (Set_elm_builtin p1, Set_elm_builtin p2) diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm new file mode 100644 index 0000000..a648e8d --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/String.elm @@ -0,0 +1,464 @@ +module String exposing + ( isEmpty, length, reverse, repeat + , cons, uncons, fromChar, append, concat, split, join, words, lines + , slice, left, right, dropLeft, dropRight + , contains, startsWith, endsWith, indexes, indices + , toInt, toFloat, toList, fromList + , toUpper, toLower, pad, padLeft, padRight, trim, trimLeft, trimRight + , map, filter, foldl, foldr, any, all + ) + +{-| A built-in representation for efficient string manipulation. String literals +are enclosed in `"double quotes"`. Strings are *not* lists of characters. + +# Basics +@docs isEmpty, length, reverse, repeat + +# Building and Splitting +@docs cons, uncons, fromChar, append, concat, split, join, words, lines + +# Get Substrings +@docs slice, left, right, dropLeft, dropRight + +# Check for Substrings +@docs contains, startsWith, endsWith, indexes, indices + +# Conversions +@docs toInt, toFloat, toList, fromList + +# Formatting +Cosmetic operations such as padding with extra characters or trimming whitespace. + +@docs toUpper, toLower, + pad, padLeft, padRight, + trim, trimLeft, trimRight + +# Higher-Order Functions +@docs map, filter, foldl, foldr, any, all +-} + +import Native.String +import Char +import Maybe exposing (Maybe) +import Result exposing (Result) + + +{-| Determine if a string is empty. + + isEmpty "" == True + isEmpty "the world" == False +-} +isEmpty : String -> Bool +isEmpty = + Native.String.isEmpty + + +{-| Add a character to the beginning of a string. + + cons 'T' "he truth is out there" == "The truth is out there" +-} +cons : Char -> String -> String +cons = + Native.String.cons + + +{-| Create a string from a given character. + + fromChar 'a' == "a" +-} +fromChar : Char -> String +fromChar char = + cons char "" + + +{-| Split a non-empty string into its head and tail. This lets you +pattern match on strings exactly as you would with lists. + + uncons "abc" == Just ('a',"bc") + uncons "" == Nothing +-} +uncons : String -> Maybe (Char, String) +uncons = + Native.String.uncons + + +{-| Append two strings. You can also use [the `(++)` operator](Basics#++) +to do this. + + append "butter" "fly" == "butterfly" +-} +append : String -> String -> String +append = + Native.String.append + + +{-| Concatenate many strings into one. + + concat ["never","the","less"] == "nevertheless" +-} +concat : List String -> String +concat = + Native.String.concat + + +{-| Get the length of a string. + + length "innumerable" == 11 + length "" == 0 + +-} +length : String -> Int +length = + Native.String.length + + +{-| Transform every character in a string + + map (\c -> if c == '/' then '.' else c) "a/b/c" == "a.b.c" +-} +map : (Char -> Char) -> String -> String +map = + Native.String.map + + +{-| Keep only the characters that satisfy the predicate. + + filter isDigit "R2-D2" == "22" +-} +filter : (Char -> Bool) -> String -> String +filter = + Native.String.filter + + +{-| Reverse a string. + + reverse "stressed" == "desserts" +-} +reverse : String -> String +reverse = + Native.String.reverse + + +{-| Reduce a string from the left. + + foldl cons "" "time" == "emit" +-} +foldl : (Char -> b -> b) -> b -> String -> b +foldl = + Native.String.foldl + + +{-| Reduce a string from the right. + + foldr cons "" "time" == "time" +-} +foldr : (Char -> b -> b) -> b -> String -> b +foldr = + Native.String.foldr + + +{-| Split a string using a given separator. + + split "," "cat,dog,cow" == ["cat","dog","cow"] + split "/" "home/evan/Desktop/" == ["home","evan","Desktop", ""] + +Use [`Regex.split`](Regex#split) if you need something more flexible. +-} +split : String -> String -> List String +split = + Native.String.split + + +{-| Put many strings together with a given separator. + + join "a" ["H","w","ii","n"] == "Hawaiian" + join " " ["cat","dog","cow"] == "cat dog cow" + join "/" ["home","evan","Desktop"] == "home/evan/Desktop" +-} +join : String -> List String -> String +join = + Native.String.join + + +{-| Repeat a string *n* times. + + repeat 3 "ha" == "hahaha" +-} +repeat : Int -> String -> String +repeat = + Native.String.repeat + + +{-| Take a substring given a start and end index. Negative indexes +are taken starting from the *end* of the list. + + slice 7 9 "snakes on a plane!" == "on" + slice 0 6 "snakes on a plane!" == "snakes" + slice 0 -7 "snakes on a plane!" == "snakes on a" + slice -6 -1 "snakes on a plane!" == "plane" +-} +slice : Int -> Int -> String -> String +slice = + Native.String.slice + + +{-| Take *n* characters from the left side of a string. + + left 2 "Mulder" == "Mu" +-} +left : Int -> String -> String +left = + Native.String.left + + +{-| Take *n* characters from the right side of a string. + + right 2 "Scully" == "ly" +-} +right : Int -> String -> String +right = + Native.String.right + + +{-| Drop *n* characters from the left side of a string. + + dropLeft 2 "The Lone Gunmen" == "e Lone Gunmen" +-} +dropLeft : Int -> String -> String +dropLeft = + Native.String.dropLeft + + +{-| Drop *n* characters from the right side of a string. + + dropRight 2 "Cigarette Smoking Man" == "Cigarette Smoking M" +-} +dropRight : Int -> String -> String +dropRight = + Native.String.dropRight + + +{-| Pad a string on both sides until it has a given length. + + pad 5 ' ' "1" == " 1 " + pad 5 ' ' "11" == " 11 " + pad 5 ' ' "121" == " 121 " +-} +pad : Int -> Char -> String -> String +pad = + Native.String.pad + + +{-| Pad a string on the left until it has a given length. + + padLeft 5 '.' "1" == "....1" + padLeft 5 '.' "11" == "...11" + padLeft 5 '.' "121" == "..121" +-} +padLeft : Int -> Char -> String -> String +padLeft = + Native.String.padLeft + + +{-| Pad a string on the right until it has a given length. + + padRight 5 '.' "1" == "1...." + padRight 5 '.' "11" == "11..." + padRight 5 '.' "121" == "121.." +-} +padRight : Int -> Char -> String -> String +padRight = + Native.String.padRight + + +{-| Get rid of whitespace on both sides of a string. + + trim " hats \n" == "hats" +-} +trim : String -> String +trim = + Native.String.trim + + +{-| Get rid of whitespace on the left of a string. + + trimLeft " hats \n" == "hats \n" +-} +trimLeft : String -> String +trimLeft = + Native.String.trimLeft + + +{-| Get rid of whitespace on the right of a string. + + trimRight " hats \n" == " hats" +-} +trimRight : String -> String +trimRight = + Native.String.trimRight + + +{-| Break a string into words, splitting on chunks of whitespace. + + words "How are \t you? \n Good?" == ["How","are","you?","Good?"] +-} +words : String -> List String +words = + Native.String.words + + +{-| Break a string into lines, splitting on newlines. + + lines "How are you?\nGood?" == ["How are you?", "Good?"] +-} +lines : String -> List String +lines = + Native.String.lines + + +{-| Convert a string to all upper case. Useful for case-insensitive comparisons +and VIRTUAL YELLING. + + toUpper "skinner" == "SKINNER" +-} +toUpper : String -> String +toUpper = + Native.String.toUpper + + +{-| Convert a string to all lower case. Useful for case-insensitive comparisons. + + toLower "X-FILES" == "x-files" +-} +toLower : String -> String +toLower = + Native.String.toLower + + +{-| Determine whether *any* characters satisfy a predicate. + + any isDigit "90210" == True + any isDigit "R2-D2" == True + any isDigit "heart" == False +-} +any : (Char -> Bool) -> String -> Bool +any = + Native.String.any + + +{-| Determine whether *all* characters satisfy a predicate. + + all isDigit "90210" == True + all isDigit "R2-D2" == False + all isDigit "heart" == False +-} +all : (Char -> Bool) -> String -> Bool +all = + Native.String.all + + +{-| See if the second string contains the first one. + + contains "the" "theory" == True + contains "hat" "theory" == False + contains "THE" "theory" == False + +Use [`Regex.contains`](Regex#contains) if you need something more flexible. +-} +contains : String -> String -> Bool +contains = + Native.String.contains + + +{-| See if the second string starts with the first one. + + startsWith "the" "theory" == True + startsWith "ory" "theory" == False +-} +startsWith : String -> String -> Bool +startsWith = + Native.String.startsWith + + +{-| See if the second string ends with the first one. + + endsWith "the" "theory" == False + endsWith "ory" "theory" == True +-} +endsWith : String -> String -> Bool +endsWith = + Native.String.endsWith + + +{-| Get all of the indexes for a substring in another string. + + indexes "i" "Mississippi" == [1,4,7,10] + indexes "ss" "Mississippi" == [2,5] + indexes "needle" "haystack" == [] +-} +indexes : String -> String -> List Int +indexes = + Native.String.indexes + + +{-| Alias for `indexes`. -} +indices : String -> String -> List Int +indices = + Native.String.indexes + + +{-| Try to convert a string into an int, failing on improperly formatted strings. + + String.toInt "123" == Ok 123 + String.toInt "-42" == Ok -42 + String.toInt "3.1" == Err "could not convert string '3.1' to an Int" + String.toInt "31a" == Err "could not convert string '31a' to an Int" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toInt "42") == 42 + Result.withDefault 0 (String.toInt "ab") == 0 +-} +toInt : String -> Result String Int +toInt = + Native.String.toInt + + +{-| Try to convert a string into a float, failing on improperly formatted strings. + + String.toFloat "123" == Ok 123.0 + String.toFloat "-42" == Ok -42.0 + String.toFloat "3.1" == Ok 3.1 + String.toFloat "31a" == Err "could not convert string '31a' to a Float" + +If you are extracting a number from some raw user input, you will typically +want to use [`Result.withDefault`](Result#withDefault) to handle bad data: + + Result.withDefault 0 (String.toFloat "42.5") == 42.5 + Result.withDefault 0 (String.toFloat "cats") == 0 +-} +toFloat : String -> Result String Float +toFloat = + Native.String.toFloat + + +{-| Convert a string to a list of characters. + + toList "abc" == ['a','b','c'] +-} +toList : String -> List Char +toList = + Native.String.toList + + +{-| Convert a list of characters into a String. Can be useful if you +want to create a string primarily by consing, perhaps for decoding +something. + + fromList ['a','b','c'] == "abc" +-} +fromList : List Char -> String +fromList = + Native.String.fromList + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm new file mode 100644 index 0000000..94fde9e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Task.elm @@ -0,0 +1,277 @@ +effect module Task where { command = MyCmd } exposing + ( Task + , succeed, fail + , map, map2, map3, map4, map5 + , sequence + , andThen + , onError, mapError + , perform, attempt + ) + +{-| Tasks make it easy to describe asynchronous operations that may fail, like +HTTP requests or writing to a database. For more information, see the [Elm +documentation on Tasks](http://guide.elm-lang.org/error_handling/task.html). + +# Basics +@docs Task, succeed, fail + +# Mapping +@docs map, map2, map3, map4, map5 + +# Chaining +@docs andThen, sequence + +# Errors +@docs onError, mapError + +# Commands +@docs perform, attempt + +-} + +import Basics exposing (Never, (|>), (<<)) +import List exposing ((::)) +import Maybe exposing (Maybe(Just,Nothing)) +import Native.Scheduler +import Platform +import Platform.Cmd exposing (Cmd) +import Result exposing (Result(Ok,Err)) + + + +{-| Represents asynchronous effects that may fail. It is useful for stuff like +HTTP. + +For example, maybe we have a task with the type (`Task String User`). This means +that when we perform the task, it will either fail with a `String` message or +succeed with a `User`. So this could represent a task that is asking a server +for a certain user. +-} +type alias Task err ok = + Platform.Task err ok + + + +-- BASICS + + +{-| A task that succeeds immediately when run. + + succeed 42 -- results in 42 +-} +succeed : a -> Task x a +succeed = + Native.Scheduler.succeed + + +{-| A task that fails immediately when run. + + fail "file not found" : Task String a +-} +fail : x -> Task x a +fail = + Native.Scheduler.fail + + + +-- MAPPING + + +{-| Transform a task. + + map sqrt (succeed 9) -- succeed 3 +-} +map : (a -> b) -> Task x a -> Task x b +map func taskA = + taskA + |> andThen (\a -> succeed (func a)) + + +{-| Put the results of two tasks together. If either task fails, the whole +thing fails. It also runs in order so the first task will be completely +finished before the second task starts. + + map2 (+) (succeed 9) (succeed 3) -- succeed 12 +-} +map2 : (a -> b -> result) -> Task x a -> Task x b -> Task x result +map2 func taskA taskB = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> succeed (func a b))) + + +{-|-} +map3 : (a -> b -> c -> result) -> Task x a -> Task x b -> Task x c -> Task x result +map3 func taskA taskB taskC = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> succeed (func a b c)))) + + +{-|-} +map4 : (a -> b -> c -> d -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x result +map4 func taskA taskB taskC taskD = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> succeed (func a b c d))))) + + +{-|-} +map5 : (a -> b -> c -> d -> e -> result) -> Task x a -> Task x b -> Task x c -> Task x d -> Task x e -> Task x result +map5 func taskA taskB taskC taskD taskE = + taskA + |> andThen (\a -> taskB + |> andThen (\b -> taskC + |> andThen (\c -> taskD + |> andThen (\d -> taskE + |> andThen (\e -> succeed (func a b c d e)))))) + + +{-| Start with a list of tasks, and turn them into a single task that returns a +list. The tasks will be run in order one-by-one and if any task fails the whole +sequence fails. + + sequence [ succeed 1, succeed 2 ] -- succeed [ 1, 2 ] + +This can be useful if you need to make a bunch of HTTP requests one-by-one. +-} +sequence : List (Task x a) -> Task x (List a) +sequence tasks = + case tasks of + [] -> + succeed [] + + task :: remainingTasks -> + map2 (::) task (sequence remainingTasks) + + + +-- CHAINING + + +{-| Chain together a task and a callback. The first task will run, and if it is +successful, you give the result to the callback resulting in another task. This +task then gets run. + + succeed 2 + |> andThen (\n -> succeed (n + 2)) + -- succeed 4 + +This is useful for chaining tasks together. Maybe you need to get a user from +your servers *and then* lookup their picture once you know their name. +-} +andThen : (a -> Task x b) -> Task x a -> Task x b +andThen = + Native.Scheduler.andThen + + +-- ERRORS + +{-| Recover from a failure in a task. If the given task fails, we use the +callback to recover. + + fail "file not found" + |> onError (\msg -> succeed 42) + -- succeed 42 + + succeed 9 + |> onError (\msg -> succeed 42) + -- succeed 9 +-} +onError : (x -> Task y a) -> Task x a -> Task y a +onError = + Native.Scheduler.onError + + +{-| Transform the error value. This can be useful if you need a bunch of error +types to match up. + + type Error = Http Http.Error | WebGL WebGL.Error + + getResources : Task Error Resource + getResources = + sequence [ mapError Http serverTask, mapError WebGL textureTask ] +-} +mapError : (x -> y) -> Task x a -> Task y a +mapError convert task = + task + |> onError (fail << convert) + + + +-- COMMANDS + + +type MyCmd msg = + Perform (Task Never msg) + + +{-| The only way to *do* things in Elm is to give commands to the Elm runtime. +So we describe some complex behavior with a `Task` and then command the runtime +to `perform` that task. For example, getting the current time looks like this: + + import Task + import Time exposing (Time) + + type Msg = Click | NewTime Time + + update : Msg -> Model -> ( Model, Cmd Msg ) + update msg model = + case msg of + Click -> + ( model, Task.perform NewTime Time.now ) + + NewTime time -> + ... +-} +perform : (a -> msg) -> Task Never a -> Cmd msg +perform toMessage task = + command (Perform (map toMessage task)) + + +{-| Command the Elm runtime to attempt a task that might fail! +-} +attempt : (Result x a -> msg) -> Task x a -> Cmd msg +attempt resultToMessage task = + command (Perform ( + task + |> andThen (succeed << resultToMessage << Ok) + |> onError (succeed << resultToMessage << Err) + )) + + +cmdMap : (a -> b) -> MyCmd a -> MyCmd b +cmdMap tagger (Perform task) = + Perform (map tagger task) + + + +-- MANAGER + + +init : Task Never () +init = + succeed () + + +onEffects : Platform.Router msg Never -> List (MyCmd msg) -> () -> Task Never () +onEffects router commands state = + map + (\_ -> ()) + (sequence (List.map (spawnCmd router) commands)) + + +onSelfMsg : Platform.Router msg Never -> Never -> () -> Task Never () +onSelfMsg _ _ _ = + succeed () + + +spawnCmd : Platform.Router msg Never -> MyCmd msg -> Task x () +spawnCmd router (Perform task) = + Native.Scheduler.spawn ( + task + |> andThen (Platform.sendToApp router) + ) diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm new file mode 100644 index 0000000..b50cdfe --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Time.elm @@ -0,0 +1,243 @@ +effect module Time where { subscription = MySub } exposing + ( Time + , now, every + , millisecond, second, minute, hour + , inMilliseconds, inSeconds, inMinutes, inHours + ) + +{-| Library for working with time. + +# Time +@docs Time, now, every + +# Units +@docs millisecond, second, minute, hour, + inMilliseconds, inSeconds, inMinutes, inHours + +-} + + +import Basics exposing (..) +import Dict +import List exposing ((::)) +import Maybe exposing (Maybe(..)) +import Native.Scheduler +import Native.Time +import Platform +import Platform.Sub exposing (Sub) +import Task exposing (Task) + + + +-- TIMES + + +{-| Type alias to make it clearer when you are working with time values. +Using the `Time` helpers like `second` and `inSeconds` instead of raw numbers +is very highly recommended. +-} +type alias Time = Float + + +{-| Get the `Time` at the moment when this task is run. +-} +now : Task x Time +now = + Native.Time.now + + +{-| Subscribe to the current time. First you provide an interval describing how +frequently you want updates. Second, you give a tagger that turns a time into a +message for your `update` function. So if you want to hear about the current +time every second, you would say something like this: + + type Msg = Tick Time | ... + + subscriptions model = + every second Tick + +Check out the [Elm Architecture Tutorial][arch] for more info on how +subscriptions work. + +[arch]: https://github.com/evancz/elm-architecture-tutorial/ + +**Note:** this function is not for animation! You need to use something based +on `requestAnimationFrame` to get smooth animations. This is based on +`setInterval` which is better for recurring tasks like “check on something +every 30 seconds”. +-} +every : Time -> (Time -> msg) -> Sub msg +every interval tagger = + subscription (Every interval tagger) + + + +-- UNITS + + +{-| Units of time, making it easier to specify things like a half-second +`(500 * millisecond)` without remembering Elm’s underlying units of time. +-} +millisecond : Time +millisecond = + 1 + + +{-|-} +second : Time +second = + 1000 * millisecond + + +{-|-} +minute : Time +minute = + 60 * second + + +{-|-} +hour : Time +hour = + 60 * minute + + +{-|-} +inMilliseconds : Time -> Float +inMilliseconds t = + t + + +{-|-} +inSeconds : Time -> Float +inSeconds t = + t / second + + +{-|-} +inMinutes : Time -> Float +inMinutes t = + t / minute + + +{-|-} +inHours : Time -> Float +inHours t = + t / hour + + + +-- SUBSCRIPTIONS + + +type MySub msg = + Every Time (Time -> msg) + + +subMap : (a -> b) -> MySub a -> MySub b +subMap f (Every interval tagger) = + Every interval (f << tagger) + + + +-- EFFECT MANAGER + + +type alias State msg = + { taggers : Taggers msg + , processes : Processes + } + + +type alias Processes = + Dict.Dict Time Platform.ProcessId + + +type alias Taggers msg = + Dict.Dict Time (List (Time -> msg)) + + +init : Task Never (State msg) +init = + Task.succeed (State Dict.empty Dict.empty) + + +onEffects : Platform.Router msg Time -> List (MySub msg) -> State msg -> Task Never (State msg) +onEffects router subs {processes} = + let + newTaggers = + List.foldl addMySub Dict.empty subs + + leftStep interval taggers (spawnList, existingDict, killTask) = + (interval :: spawnList, existingDict, killTask) + + bothStep interval taggers id (spawnList, existingDict, killTask) = + (spawnList, Dict.insert interval id existingDict, killTask) + + rightStep _ id (spawnList, existingDict, killTask) = + ( spawnList + , existingDict + , Native.Scheduler.kill id + |> Task.andThen (\_ -> killTask) + ) + + (spawnList, existingDict, killTask) = + Dict.merge + leftStep + bothStep + rightStep + newTaggers + processes + ([], Dict.empty, Task.succeed ()) + in + killTask + |> Task.andThen (\_ -> spawnHelp router spawnList existingDict) + |> Task.andThen (\newProcesses -> Task.succeed (State newTaggers newProcesses)) + + +addMySub : MySub msg -> Taggers msg -> Taggers msg +addMySub (Every interval tagger) state = + case Dict.get interval state of + Nothing -> + Dict.insert interval [tagger] state + + Just taggers -> + Dict.insert interval (tagger :: taggers) state + + +spawnHelp : Platform.Router msg Time -> List Time -> Processes -> Task.Task x Processes +spawnHelp router intervals processes = + case intervals of + [] -> + Task.succeed processes + + interval :: rest -> + let + spawnTimer = + Native.Scheduler.spawn (setInterval interval (Platform.sendToSelf router interval)) + + spawnRest id = + spawnHelp router rest (Dict.insert interval id processes) + in + spawnTimer + |> Task.andThen spawnRest + + +onSelfMsg : Platform.Router msg Time -> Time -> State msg -> Task Never (State msg) +onSelfMsg router interval state = + case Dict.get interval state.taggers of + Nothing -> + Task.succeed state + + Just taggers -> + let + tellTaggers time = + Task.sequence (List.map (\tagger -> Platform.sendToApp router (tagger time)) taggers) + in + now + |> Task.andThen tellTaggers + |> Task.andThen (\_ -> Task.succeed state) + + +setInterval : Time -> Task Never () -> Task x Never +setInterval = + Native.Time.setInterval_ diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm new file mode 100644 index 0000000..ab4c401 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/src/Tuple.elm @@ -0,0 +1,61 @@ +module Tuple exposing + ( first, second + , mapFirst, mapSecond + ) + +{-| Some helpers for working with 2-tuples. + +**Note:** For larger chunks of data, it is best to switch to using records. So +instead of representing a 3D point as `(3,4,5)` and wondering why there are no +helper functions, represent it as `{ x = 3, y = 4, z = 5 }` and use all the +built-in syntax for records. + +@docs first, second, mapFirst, mapSecond + +-} + + + +{-| Extract the first value from a tuple. + + first (3, 4) == 3 + first ("john", "doe") == "john" +-} +first : (a1, a2) -> a1 +first (x,_) = + x + + +{-| Extract the second value from a tuple. + + second (3, 4) == 4 + second ("john", "doe") == "doe" +-} +second : (a1, a2) -> a2 +second (_,y) = + y + + +{-| Transform the first value in a tuple. + + import String + + mapFirst String.reverse ("stressed", 16) == ("desserts", 16) + mapFirst String.length ("stressed", 16) == (8, 16) +-} +mapFirst : (a -> b) -> (a, a2) -> (b, a2) +mapFirst func (x,y) = + (func x, y) + + +{-| Transform the second value in a tuple. + + import String + + mapSecond sqrt ("stressed", 16) == ("stressed", 4) + mapSecond (\x -> x + 1) ("stressed", 16) == ("stressed", 17) +-} +mapSecond : (a -> b) -> (a1, a) -> (a1, b) +mapSecond func (x,y) = + (x, func y) + diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm new file mode 100644 index 0000000..0fb81c9 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Main.elm @@ -0,0 +1,50 @@ +port module Main exposing (..) + +import Basics exposing (..) +import Task exposing (..) +import Test exposing (..) +import Platform.Cmd exposing (Cmd) +import Json.Decode exposing (Value) +import Test.Runner.Node exposing (run, TestProgram) +import Test.Array as Array +import Test.Basics as Basics +import Test.Bitwise as Bitwise +import Test.Char as Char +import Test.CodeGen as CodeGen +import Test.Dict as Dict +import Test.Maybe as Maybe +import Test.Equality as Equality +import Test.Json as Json +import Test.List as List +import Test.Result as Result +import Test.Set as Set +import Test.String as String +import Test.Regex as Regex + + +tests : Test +tests = + describe "Elm Standard Library Tests" + [ Array.tests + , Basics.tests + , Bitwise.tests + , Char.tests + , CodeGen.tests + , Dict.tests + , Equality.tests + , Json.tests + , List.tests + , Result.tests + , Set.tests + , String.tests + , Regex.tests + , Maybe.tests + ] + + +main : TestProgram +main = + run emit tests + + +port emit : ( String, Value ) -> Cmd msg diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm new file mode 100644 index 0000000..e32b49d --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Array.elm @@ -0,0 +1,120 @@ +module Test.Array exposing (tests) + +import Array +import Basics exposing (..) +import List +import List exposing ((::)) +import Maybe exposing (..) +import Native.Array +import Test exposing (..) +import Expect + + +mergeSplit : Int -> Array.Array a -> Array.Array a +mergeSplit n arr = + let + left = + Array.slice 0 n arr + + right = + Array.slice n (Array.length arr) arr + in + Array.append left right + + +holeArray : Array.Array Int +holeArray = + List.foldl mergeSplit (Array.fromList (List.range 0 100)) (List.range 0 100) + + +mapArray : Array.Array a -> Array.Array a +mapArray array = + Array.indexedMap + (\i el -> + case (Array.get i array) of + Just x -> + x + + Nothing -> + el + ) + array + + +tests : Test +tests = + let + creationTests = + describe "Creation" + [ test "empty" <| \() -> Expect.equal Array.empty (Array.fromList []) + , test "initialize" <| \() -> Expect.equal (Array.initialize 4 identity) (Array.fromList [ 0, 1, 2, 3 ]) + , test "initialize 2" <| \() -> Expect.equal (Array.initialize 4 (\n -> n * n)) (Array.fromList [ 0, 1, 4, 9 ]) + , test "initialize 3" <| \() -> Expect.equal (Array.initialize 4 (always 0)) (Array.fromList [ 0, 0, 0, 0 ]) + , test "initialize Empty" <| \() -> Expect.equal (Array.initialize 0 identity) Array.empty + , test "initialize 4" <| \() -> Expect.equal (Array.initialize 2 (always 0)) (Array.fromList [ 0, 0 ]) + , test "initialize negative" <| \() -> Expect.equal (Array.initialize -1 identity) Array.empty + , test "repeat" <| \() -> Expect.equal (Array.repeat 5 40) (Array.fromList [ 40, 40, 40, 40, 40 ]) + , test "repeat 2" <| \() -> Expect.equal (Array.repeat 5 0) (Array.fromList [ 0, 0, 0, 0, 0 ]) + , test "repeat 3" <| \() -> Expect.equal (Array.repeat 3 "cat") (Array.fromList [ "cat", "cat", "cat" ]) + , test "fromList" <| \() -> Expect.equal (Array.fromList []) Array.empty + ] + + basicsTests = + describe "Basics" + [ test "length" <| \() -> Expect.equal 3 (Array.length (Array.fromList [ 1, 2, 3 ])) + , test "length - Long" <| \() -> Expect.equal 10000 (Array.length (Array.repeat 10000 0)) + , test "push" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.push 3 (Array.fromList [ 1, 2 ])) + , test "append" <| \() -> Expect.equal [ 42, 42, 81, 81, 81 ] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81))) + , test "appendEmpty 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append Array.empty (Array.fromList <| List.range 1 33))) + , test "appendEmpty 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 33) Array.empty)) + , test "appendSmall 1" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 30) (Array.fromList <| List.range 31 33))) + , test "appendSmall 2" <| \() -> Expect.equal (List.range 1 33) (Array.toList (Array.append (Array.fromList <| List.range 1 3) (Array.fromList <| List.range 4 33))) + , test "appendAndSlice" <| \() -> Expect.equal (List.range 0 100) (Array.toList holeArray) + ] + + getAndSetTests = + describe "Get and Set" + [ test "get" <| \() -> Expect.equal (Just 2) (Array.get 1 (Array.fromList [ 3, 2, 1 ])) + , test "get 2" <| \() -> Expect.equal Nothing (Array.get 5 (Array.fromList [ 3, 2, 1 ])) + , test "get 3" <| \() -> Expect.equal Nothing (Array.get -1 (Array.fromList [ 3, 2, 1 ])) + , test "set" <| \() -> Expect.equal (Array.fromList [ 1, 7, 3 ]) (Array.set 1 7 (Array.fromList [ 1, 2, 3 ])) + ] + + takingArraysApartTests = + describe "Taking Arrays Apart" + [ test "toList" <| \() -> Expect.equal [ 3, 5, 8 ] (Array.toList (Array.fromList [ 3, 5, 8 ])) + , test "toIndexedList" <| \() -> Expect.equal [ ( 0, "cat" ), ( 1, "dog" ) ] (Array.toIndexedList (Array.fromList [ "cat", "dog" ])) + , test "slice 1" <| \() -> Expect.equal (Array.fromList [ 0, 1, 2 ]) (Array.slice 0 3 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 2" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 4 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 3" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.slice 1 -1 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 4" <| \() -> Expect.equal (Array.fromList [ 2 ]) (Array.slice -3 -2 (Array.fromList [ 0, 1, 2, 3, 4 ])) + , test "slice 5" <| \() -> Expect.equal 63 (Array.length <| Array.slice 65 (65 + 63) <| Array.fromList (List.range 1 200)) + ] + + mappingAndFoldingTests = + describe "Mapping and Folding" + [ test "map" <| \() -> Expect.equal (Array.fromList [ 1, 2, 3 ]) (Array.map sqrt (Array.fromList [ 1, 4, 9 ])) + , test "indexedMap 1" <| \() -> Expect.equal (Array.fromList [ 0, 5, 10 ]) (Array.indexedMap (*) (Array.fromList [ 5, 5, 5 ])) + , test "indexedMap 2" <| \() -> Expect.equal (List.range 0 99) (Array.toList (Array.indexedMap always (Array.repeat 100 0))) + , test "large indexed map" <| \() -> Expect.equal (List.range 0 <| 32768 - 1) (Array.toList <| mapArray <| Array.initialize 32768 identity) + , test "foldl 1" <| \() -> Expect.equal [ 3, 2, 1 ] (Array.foldl (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldl 2" <| \() -> Expect.equal 33 (Array.foldl (+) 0 (Array.repeat 33 1)) + , test "foldr 1" <| \() -> Expect.equal 15 (Array.foldr (+) 0 (Array.repeat 3 5)) + , test "foldr 2" <| \() -> Expect.equal [ 1, 2, 3 ] (Array.foldr (::) [] (Array.fromList [ 1, 2, 3 ])) + , test "foldr 3" <| \() -> Expect.equal 53 (Array.foldr (-) 54 (Array.fromList [ 10, 11 ])) + , test "filter" <| \() -> Expect.equal (Array.fromList [ 2, 4, 6 ]) (Array.filter (\x -> x % 2 == 0) (Array.fromList <| List.range 1 6)) + ] + + nativeTests = + describe "Conversion to JS Arrays" + [ test "jsArrays" <| \() -> Expect.equal (Array.fromList <| List.range 1 1100) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList <| List.range 1 1100))) + ] + in + describe "Array" + [ creationTests + , basicsTests + , getAndSetTests + , takingArraysApartTests + , mappingAndFoldingTests + , nativeTests + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm new file mode 100644 index 0000000..56742cb --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Basics.elm @@ -0,0 +1,220 @@ +module Test.Basics exposing (tests) + +import Array +import Tuple exposing (first, second) +import Basics exposing (..) +import Date +import Set +import Dict +import Test exposing (..) +import Expect +import List +import String + + +tests : Test +tests = + let + comparison = + describe "Comparison" + [ test "max" <| \() -> Expect.equal 42 (max 32 42) + , test "min" <| \() -> Expect.equal 42 (min 91 42) + , test "clamp low" <| \() -> Expect.equal 10 (clamp 10 20 5) + , test "clamp mid" <| \() -> Expect.equal 15 (clamp 10 20 15) + , test "clamp high" <| \() -> Expect.equal 20 (clamp 10 20 25) + , test "5 < 6" <| \() -> Expect.equal True (5 < 6) + , test "6 < 5" <| \() -> Expect.equal False (6 < 5) + , test "6 < 6" <| \() -> Expect.equal False (6 < 6) + , test "5 > 6" <| \() -> Expect.equal False (5 > 6) + , test "6 > 5" <| \() -> Expect.equal True (6 > 5) + , test "6 > 6" <| \() -> Expect.equal False (6 > 6) + , test "5 <= 6" <| \() -> Expect.equal True (5 <= 6) + , test "6 <= 5" <| \() -> Expect.equal False (6 <= 5) + , test "6 <= 6" <| \() -> Expect.equal True (6 <= 6) + , test "compare \"A\" \"B\"" <| \() -> Expect.equal LT (compare "A" "B") + , test "compare 'f' 'f'" <| \() -> Expect.equal EQ (compare 'f' 'f') + , test "compare (1, 2, 3, 4, 5, 6) (0, 1, 2, 3, 4, 5)" <| \() -> Expect.equal GT (compare ( 1, 2, 3, 4, 5, 6 ) ( 0, 1, 2, 3, 4, 5 )) + , test "compare ['a'] ['b']" <| \() -> Expect.equal LT (compare [ 'a' ] [ 'b' ]) + , test "array equality" <| \() -> Expect.equal (Array.fromList [ 1, 1, 1, 1 ]) (Array.repeat 4 1) + , test "set equality" <| \() -> Expect.equal (Set.fromList [ 1, 2 ]) (Set.fromList [ 2, 1 ]) + , test "dict equality" <| \() -> Expect.equal (Dict.fromList [ ( 1, 1 ), ( 2, 2 ) ]) (Dict.fromList [ ( 2, 2 ), ( 1, 1 ) ]) + , test "char equality" <| \() -> Expect.notEqual '0' '饑' + , test "date equality" <| \() -> Expect.equal (Date.fromString "2/7/1992") (Date.fromString "2/7/1992") + , test "date equality" <| \() -> Expect.notEqual (Date.fromString "11/16/1995") (Date.fromString "2/7/1992") + ] + + toStringTests = + describe "toString Tests" + [ test "toString Int" <| \() -> Expect.equal "42" (toString 42) + , test "toString Float" <| \() -> Expect.equal "42.52" (toString 42.52) + , test "toString Char" <| \() -> Expect.equal "'c'" (toString 'c') + , test "toString Char single quote" <| \() -> Expect.equal "'\\''" (toString '\'') + , test "toString Char double quote" <| \() -> Expect.equal "'\"'" (toString '"') + , test "toString String single quote" <| \() -> Expect.equal "\"not 'escaped'\"" (toString "not 'escaped'") + , test "toString String double quote" <| \() -> Expect.equal "\"are \\\"escaped\\\"\"" (toString "are \"escaped\"") + , test "toString record" <| \() -> Expect.equal "{ field = [0] }" (toString { field = [ 0 ] }) + -- TODO + --, test "toString record, special case" <| \() -> Expect.equal "{ ctor = [0] }" (toString { ctor = [ 0 ] }) + ] + + trigTests = + describe "Trigonometry Tests" + [ test "radians 0" <| \() -> Expect.equal 0 (radians 0) + , test "radians positive" <| \() -> Expect.equal 5 (radians 5) + , test "radians negative" <| \() -> Expect.equal -5 (radians -5) + , test "degrees 0" <| \() -> Expect.equal 0 (degrees 0) + , test "degrees 90" <| \() -> Expect.lessThan 0.01 (abs (1.57 - degrees 90)) + -- This should test to enough precision to know if anything's breaking + , test "degrees -145" <| \() -> Expect.lessThan 0.01 (abs (-2.53 - degrees -145)) + -- This should test to enough precision to know if anything's breaking + , test "turns 0" <| \() -> Expect.equal 0 (turns 0) + , test "turns 8" <| \() -> Expect.lessThan 0.01 (abs (50.26 - turns 8)) + -- This should test to enough precision to know if anything's breaking + , test "turns -133" <| \() -> Expect.lessThan 0.01 (abs (-835.66 - turns -133)) + -- This should test to enough precision to know if anything's breaking + , test "fromPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 0 )) + , test "fromPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (fromPolar ( 1, 0 )) + , test "fromPolar (0, 1)" <| \() -> Expect.equal ( 0, 0 ) (fromPolar ( 0, 1 )) + , test "fromPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( x, y ) = + fromPolar ( 1, 1 ) + in + 0.54 - x < 0.01 && 0.84 - y < 0.01 + ) + , test "toPolar (0, 0)" <| \() -> Expect.equal ( 0, 0 ) (toPolar ( 0, 0 )) + , test "toPolar (1, 0)" <| \() -> Expect.equal ( 1, 0 ) (toPolar ( 1, 0 )) + , test "toPolar (0, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 0, 1 ) + in + r == 1 && abs (1.57 - theta) < 0.01 + ) + , test "toPolar (1, 1)" <| + \() -> + Expect.equal True + (let + ( r, theta ) = + toPolar ( 1, 1 ) + in + abs (1.41 - r) < 0.01 && abs (0.78 - theta) < 0.01 + ) + , test "cos" <| \() -> Expect.equal 1 (cos 0) + , test "sin" <| \() -> Expect.equal 0 (sin 0) + , test "tan" <| \() -> Expect.lessThan 0.01 (abs (12.67 - tan 17.2)) + , test "acos" <| \() -> Expect.lessThan 0.01 (abs (3.14 - acos -1)) + , test "asin" <| \() -> Expect.lessThan 0.01 (abs (0.3 - asin 0.3)) + , test "atan" <| \() -> Expect.lessThan 0.01 (abs (1.57 - atan 4567.8)) + , test "atan2" <| \() -> Expect.lessThan 0.01 (abs (1.55 - atan2 36 0.65)) + , test "pi" <| \() -> Expect.lessThan 0.01 (abs (3.14 - pi)) + ] + + basicMathTests = + describe "Basic Math Tests" + [ test "add float" <| \() -> Expect.equal 159 (155.6 + 3.4) + , test "add int" <| \() -> Expect.equal 17 ((round 10) + (round 7)) + , test "subtract float" <| \() -> Expect.equal -6.3 (1 - 7.3) + , test "subtract int" <| \() -> Expect.equal 1130 ((round 9432) - (round 8302)) + , test "multiply float" <| \() -> Expect.equal 432 (96 * 4.5) + , test "multiply int" <| \() -> Expect.equal 90 ((round 10) * (round 9)) + , test "divide float" <| \() -> Expect.equal 13.175 (527 / 40) + , test "divide int" <| \() -> Expect.equal 23 (70 // 3) + , test "2 |> rem 7" <| \() -> Expect.equal 1 (2 |> rem 7) + , test "4 |> rem -1" <| \() -> Expect.equal -1 (4 |> rem -1) + , test "7 % 2" <| \() -> Expect.equal 1 (7 % 2) + , test "-1 % 4" <| \() -> Expect.equal 3 (-1 % 4) + , test "3^2" <| \() -> Expect.equal 9 (3 ^ 2) + , test "sqrt" <| \() -> Expect.equal 9 (sqrt 81) + , test "negate 42" <| \() -> Expect.equal -42 (negate 42) + , test "negate -42" <| \() -> Expect.equal 42 (negate -42) + , test "negate 0" <| \() -> Expect.equal 0 (negate 0) + , test "abs -25" <| \() -> Expect.equal 25 (abs -25) + , test "abs 76" <| \() -> Expect.equal 76 (abs 76) + , test "logBase 10 100" <| \() -> Expect.equal 2 (logBase 10 100) + , test "logBase 2 256" <| \() -> Expect.equal 8 (logBase 2 256) + , test "e" <| \() -> Expect.lessThan 0.01 (abs (2.72 - e)) + ] + + booleanTests = + describe "Boolean Tests" + [ test "False && False" <| \() -> Expect.equal False (False && False) + , test "False && True" <| \() -> Expect.equal False (False && True) + , test "True && False" <| \() -> Expect.equal False (True && False) + , test "True && True" <| \() -> Expect.equal True (True && True) + , test "False || False" <| \() -> Expect.equal False (False || False) + , test "False || True" <| \() -> Expect.equal True (False || True) + , test "True || False" <| \() -> Expect.equal True (True || False) + , test "True || True" <| \() -> Expect.equal True (True || True) + , test "xor False False" <| \() -> Expect.equal False (xor False False) + , test "xor False True" <| \() -> Expect.equal True (xor False True) + , test "xor True False" <| \() -> Expect.equal True (xor True False) + , test "xor True True" <| \() -> Expect.equal False (xor True True) + , test "not True" <| \() -> Expect.equal False (not True) + , test "not False" <| \() -> Expect.equal True (not False) + ] + + conversionTests = + describe "Conversion Tests" + [ test "round 0.6" <| \() -> Expect.equal 1 (round 0.6) + , test "round 0.4" <| \() -> Expect.equal 0 (round 0.4) + , test "round 0.5" <| \() -> Expect.equal 1 (round 0.5) + , test "truncate -2367.9267" <| \() -> Expect.equal -2367 (truncate -2367.9267) + , test "floor -2367.9267" <| \() -> Expect.equal -2368 (floor -2367.9267) + , test "ceiling 37.2" <| \() -> Expect.equal 38 (ceiling 37.2) + , test "toFloat 25" <| \() -> Expect.equal 25 (toFloat 25) + ] + + miscTests = + describe "Miscellaneous Tests" + [ test "isNaN (0/0)" <| \() -> Expect.equal True (isNaN (0 / 0)) + , test "isNaN (sqrt -1)" <| \() -> Expect.equal True (isNaN (sqrt -1)) + , test "isNaN (1/0)" <| \() -> Expect.equal False (isNaN (1 / 0)) + , test "isNaN 1" <| \() -> Expect.equal False (isNaN 1) + , test "isInfinite (0/0)" <| \() -> Expect.equal False (isInfinite (0 / 0)) + , test "isInfinite (sqrt -1)" <| \() -> Expect.equal False (isInfinite (sqrt -1)) + , test "isInfinite (1/0)" <| \() -> Expect.equal True (isInfinite (1 / 0)) + , test "isInfinite 1" <| \() -> Expect.equal False (isInfinite 1) + , test "\"hello\" ++ \"world\"" <| \() -> Expect.equal "helloworld" ("hello" ++ "world") + , test "[1, 1, 2] ++ [3, 5, 8]" <| \() -> Expect.equal [ 1, 1, 2, 3, 5, 8 ] ([ 1, 1, 2 ] ++ [ 3, 5, 8 ]) + , test "first (1, 2)" <| \() -> Expect.equal 1 (first ( 1, 2 )) + , test "second (1, 2)" <| \() -> Expect.equal 2 (second ( 1, 2 )) + ] + + higherOrderTests = + describe "Higher Order Helpers" + [ test "identity 'c'" <| \() -> Expect.equal 'c' (identity 'c') + , test "always 42 ()" <| \() -> Expect.equal 42 (always 42 ()) + , test "<|" <| \() -> Expect.equal 9 (identity <| 3 + 6) + , test "|>" <| \() -> Expect.equal 9 (3 + 6 |> identity) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , test "<<" <| \() -> Expect.equal True (not << xor True <| True) + , describe ">>" + [ test "with xor" <| + \() -> + (True |> xor True >> not) + |> Expect.equal True + , test "with a record accessor" <| + \() -> + [ { foo = "NaS", bar = "baz" } ] + |> List.map (.foo >> String.reverse) + |> Expect.equal [ "SaN" ] + ] + , test "flip" <| \() -> Expect.equal 10 ((flip (//)) 2 20) + , test "curry" <| \() -> Expect.equal 1 ((curry (\( a, b ) -> a + b)) -5 6) + , test "uncurry" <| \() -> Expect.equal 1 ((uncurry (+)) ( -5, 6 )) + ] + in + describe "Basics" + [ comparison + , toStringTests + , trigTests + , basicMathTests + , booleanTests + , miscTests + , higherOrderTests + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm new file mode 100644 index 0000000..844ebba --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Bitwise.elm @@ -0,0 +1,51 @@ +module Test.Bitwise exposing (tests) + +import Basics exposing (..) +import Bitwise +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Bitwise" + [ describe "and" + [ test "and with 32 bit integers" <| \() -> Expect.equal 1 (Bitwise.and 5 3) + , test "and with 0 as first argument" <| \() -> Expect.equal 0 (Bitwise.and 0 1450) + , test "and with 0 as second argument" <| \() -> Expect.equal 0 (Bitwise.and 274 0) + , test "and with -1 as first argument" <| \() -> Expect.equal 2671 (Bitwise.and -1 2671) + , test "and with -1 as second argument" <| \() -> Expect.equal 96 (Bitwise.and 96 -1) + ] + , describe "or" + [ test "or with 32 bit integers" <| \() -> Expect.equal 15 (Bitwise.or 9 14) + , test "or with 0 as first argument" <| \() -> Expect.equal 843 (Bitwise.or 0 843) + , test "or with 0 as second argument" <| \() -> Expect.equal 19 (Bitwise.or 19 0) + , test "or with -1 as first argument" <| \() -> Expect.equal -1 (Bitwise.or -1 2360) + , test "or with -1 as second argument" <| \() -> Expect.equal -1 (Bitwise.or 3 -1) + ] + , describe "xor" + [ test "xor with 32 bit integers" <| \() -> Expect.equal 604 (Bitwise.xor 580 24) + , test "xor with 0 as first argument" <| \() -> Expect.equal 56 (Bitwise.xor 0 56) + , test "xor with 0 as second argument" <| \() -> Expect.equal -268 (Bitwise.xor -268 0) + , test "xor with -1 as first argument" <| \() -> Expect.equal -25 (Bitwise.xor -1 24) + , test "xor with -1 as second argument" <| \() -> Expect.equal 25601 (Bitwise.xor -25602 -1) + ] + , describe "complement" + [ test "complement a positive" <| \() -> Expect.equal -9 (Bitwise.complement 8) + , test "complement a negative" <| \() -> Expect.equal 278 (Bitwise.complement -279) + ] + , describe "shiftLeftBy" + [ test "8 |> shiftLeftBy 1 == 16" <| \() -> Expect.equal 16 (8 |> Bitwise.shiftLeftBy 1) + , test "8 |> shiftLeftby 2 == 32" <| \() -> Expect.equal 32 (8 |> Bitwise.shiftLeftBy 2) + ] + , describe "shiftRightBy" + [ test "32 |> shiftRight 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightBy 1) + , test "32 |> shiftRight 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightBy 2) + , test "-32 |> shiftRight 1 == -16" <| \() -> Expect.equal -16 (-32 |> Bitwise.shiftRightBy 1) + ] + , describe "shiftRightZfBy" + [ test "32 |> shiftRightZfBy 1 == 16" <| \() -> Expect.equal 16 (32 |> Bitwise.shiftRightZfBy 1) + , test "32 |> shiftRightZfBy 2 == 8" <| \() -> Expect.equal 8 (32 |> Bitwise.shiftRightZfBy 2) + , test "-32 |> shiftRightZfBy 1 == 2147483632" <| \() -> Expect.equal 2147483632 (-32 |> Bitwise.shiftRightZfBy 1) + ] + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm new file mode 100644 index 0000000..598aae3 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Char.elm @@ -0,0 +1,113 @@ +module Test.Char exposing (tests) + +import Basics exposing (..) +import Char exposing (..) +import List +import Test exposing (..) +import Expect + + +lower = + [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] + + +upper = + [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] + + +dec = + [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] + + +oct = + List.take 8 dec + + +hexLower = + List.take 6 lower + + +hexUpper = + List.take 6 upper + + +hex = + List.append hexLower hexUpper |> List.append dec + + +lowerCodes = + List.range 97 (97 + List.length lower - 1) + + +upperCodes = + List.range 65 (65 + List.length upper - 1) + + +decCodes = + List.range 48 (48 + List.length dec - 1) + + +oneOf : List a -> a -> Bool +oneOf = + flip List.member + + +tests : Test +tests = + describe "Char" + [ describe "toCode" + [ test "a-z" <| \() -> Expect.equal (lowerCodes) (List.map toCode lower) + , test "A-Z" <| \() -> Expect.equal (upperCodes) (List.map toCode upper) + , test "0-9" <| \() -> Expect.equal (decCodes) (List.map toCode dec) + ] + , describe "fromCode" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map fromCode lowerCodes) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map fromCode upperCodes) + , test "0-9" <| \() -> Expect.equal (dec) (List.map fromCode decCodes) + ] + , describe "toLocaleLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLocaleLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLocaleLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleLower dec) + ] + , describe "toLocaleUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toLocaleUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLocaleUpper dec) + ] + , describe "toLower" + [ test "a-z" <| \() -> Expect.equal (lower) (List.map toLower lower) + , test "A-Z" <| \() -> Expect.equal (lower) (List.map toLower upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toLower dec) + ] + , describe "toUpper" + [ test "a-z" <| \() -> Expect.equal (upper) (List.map toUpper lower) + , test "A-Z" <| \() -> Expect.equal (upper) (List.map toUpper upper) + , test "0-9" <| \() -> Expect.equal (dec) (List.map toUpper dec) + ] + , describe "isLower" + [ test "a-z" <| \() -> Expect.equal (True) (List.all isLower lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isLower upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isLower dec) + ] + , describe "isUpper" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isUpper lower) + , test "A-Z" <| \() -> Expect.equal (True) (List.all isUpper upper) + , test "0-9" <| \() -> Expect.equal (False) (List.any isUpper dec) + ] + , describe "isDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isDigit dec) + ] + , describe "isHexDigit" + [ test "a-z" <| \() -> Expect.equal (List.map (oneOf hex) lower) (List.map isHexDigit lower) + , test "A-Z" <| \() -> Expect.equal (List.map (oneOf hex) upper) (List.map isHexDigit upper) + , test "0-9" <| \() -> Expect.equal (True) (List.all isHexDigit dec) + ] + , describe "isOctDigit" + [ test "a-z" <| \() -> Expect.equal (False) (List.any isOctDigit lower) + , test "A-Z" <| \() -> Expect.equal (False) (List.any isOctDigit upper) + , test "0-9" <| \() -> Expect.equal (List.map (oneOf oct) dec) (List.map isOctDigit dec) + ] + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm new file mode 100644 index 0000000..4a89c63 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/CodeGen.elm @@ -0,0 +1,109 @@ +module Test.CodeGen exposing (tests) + +import Basics exposing (..) +import Test exposing (..) +import Expect +import Maybe +import Maybe exposing (..) + + +type Wrapper a + = Wrapper a + + +caseUnderscore : Maybe number -> number +caseUnderscore m_ = + case m_ of + Just x -> + x + + Nothing -> + 0 + + +patternUnderscore : number +patternUnderscore = + case Just 42 of + Just x_ -> + x_ + + Nothing -> + 0 + + +letQualified : number +letQualified = + let + (Wrapper x) = + Wrapper 42 + in + x + + +caseQualified : number +caseQualified = + case Just 42 of + Maybe.Just x -> + x + + Nothing -> + 0 + + +caseScope : String +caseScope = + case "Not this one!" of + string -> + case "Hi" of + string -> + string + + +tests : Test +tests = + let + -- We don't strictly speaking need annotations in this let-expression, + -- but having these here exercises the parser to avoid regressions like + -- https://github.com/elm-lang/elm-compiler/issues/1535 + underscores : Test + underscores = + describe "Underscores" + [ test "case" <| \() -> Expect.equal 42 (caseUnderscore (Just 42)) + , test "pattern" <| \() -> Expect.equal 42 patternUnderscore + ] + + qualifiedPatterns : Test + qualifiedPatterns = + describe "Qualified Patterns" + [ test "let" <| \() -> Expect.equal 42 letQualified + , test "case" <| \() -> Expect.equal 42 caseQualified + ] + + scope : Test + scope = + describe "Scoping" + [ test "case" <| \() -> Expect.equal "Hi" caseScope ] + + hex : Test + hex = + describe "Hex" + [ test "0xFFFFFFFF" <| + \() -> + 0xFFFFFFFF + |> Expect.equal 4294967295 + , test "0xD066F00D" <| + \() -> + 0xD066F00D + |> Expect.equal 3496407053 + , test "0x00" <| + \() -> + 0x00 + |> Expect.equal 0 + ] + in + describe "CodeGen" + [ underscores + , qualifiedPatterns + , scope + , hex + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm new file mode 100644 index 0000000..372b2c9 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Dict.elm @@ -0,0 +1,107 @@ +module Test.Dict exposing (tests) + +import Basics exposing (..) +import Dict +import List +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +animals : Dict.Dict String String +animals = + Dict.fromList [ ( "Tom", "cat" ), ( "Jerry", "mouse" ) ] + + +tests : Test +tests = + let + buildTests = + describe "build Tests" + [ test "empty" <| \() -> Expect.equal (Dict.fromList []) (Dict.empty) + , test "singleton" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.singleton "k" "v") + , test "insert" <| \() -> Expect.equal (Dict.fromList [ ( "k", "v" ) ]) (Dict.insert "k" "v" Dict.empty) + , test "insert replace" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.insert "k" "vv" (Dict.singleton "k" "v")) + , test "update" <| \() -> Expect.equal (Dict.fromList [ ( "k", "vv" ) ]) (Dict.update "k" (\v -> Just "vv") (Dict.singleton "k" "v")) + , test "update Nothing" <| \() -> Expect.equal Dict.empty (Dict.update "k" (\v -> Nothing) (Dict.singleton "k" "v")) + , test "remove" <| \() -> Expect.equal Dict.empty (Dict.remove "k" (Dict.singleton "k" "v")) + , test "remove not found" <| \() -> Expect.equal (Dict.singleton "k" "v") (Dict.remove "kk" (Dict.singleton "k" "v")) + ] + + queryTests = + describe "query Tests" + [ test "member 1" <| \() -> Expect.equal True (Dict.member "Tom" animals) + , test "member 2" <| \() -> Expect.equal False (Dict.member "Spike" animals) + , test "get 1" <| \() -> Expect.equal (Just "cat") (Dict.get "Tom" animals) + , test "get 2" <| \() -> Expect.equal Nothing (Dict.get "Spike" animals) + , test "size of empty dictionary" <| \() -> Expect.equal 0 (Dict.size Dict.empty) + , test "size of example dictionary" <| \() -> Expect.equal 2 (Dict.size animals) + ] + + combineTests = + describe "combine Tests" + [ test "union" <| \() -> Expect.equal animals (Dict.union (Dict.singleton "Jerry" "mouse") (Dict.singleton "Tom" "cat")) + , test "union collison" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.union (Dict.singleton "Tom" "cat") (Dict.singleton "Tom" "mouse")) + , test "intersect" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.intersect animals (Dict.singleton "Tom" "cat")) + , test "diff" <| \() -> Expect.equal (Dict.singleton "Jerry" "mouse") (Dict.diff animals (Dict.singleton "Tom" "cat")) + ] + + transformTests = + describe "transform Tests" + [ test "filter" <| \() -> Expect.equal (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals) + , test "partition" <| \() -> Expect.equal ( Dict.singleton "Tom" "cat", Dict.singleton "Jerry" "mouse" ) (Dict.partition (\k v -> k == "Tom") animals) + ] + + mergeTests = + let + insertBoth key leftVal rightVal dict = + Dict.insert key (leftVal ++ rightVal) dict + + s1 = + Dict.empty |> Dict.insert "u1" [ 1 ] + + s2 = + Dict.empty |> Dict.insert "u2" [ 2 ] + + s23 = + Dict.empty |> Dict.insert "u2" [ 3 ] + + b1 = + List.map (\i -> ( i, [ i ] )) (List.range 1 10) |> Dict.fromList + + b2 = + List.map (\i -> ( i, [ i ] )) (List.range 5 15) |> Dict.fromList + + bExpected = + [ ( 1, [ 1 ] ), ( 2, [ 2 ] ), ( 3, [ 3 ] ), ( 4, [ 4 ] ), ( 5, [ 5, 5 ] ), ( 6, [ 6, 6 ] ), ( 7, [ 7, 7 ] ), ( 8, [ 8, 8 ] ), ( 9, [ 9, 9 ] ), ( 10, [ 10, 10 ] ), ( 11, [ 11 ] ), ( 12, [ 12 ] ), ( 13, [ 13 ] ), ( 14, [ 14 ] ), ( 15, [ 15 ] ) ] + in + describe "merge Tests" + [ test "merge empties" <| + \() -> + Expect.equal (Dict.empty) + (Dict.merge Dict.insert insertBoth Dict.insert Dict.empty Dict.empty Dict.empty) + , test "merge singletons in order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s1 s2 Dict.empty) |> Dict.toList) + , test "merge singletons out of order" <| + \() -> + Expect.equal [ ( "u1", [ 1 ] ), ( "u2", [ 2 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s1 Dict.empty) |> Dict.toList) + , test "merge with duplicate key" <| + \() -> + Expect.equal [ ( "u2", [ 2, 3 ] ) ] + ((Dict.merge Dict.insert insertBoth Dict.insert s2 s23 Dict.empty) |> Dict.toList) + , test "partially overlapping" <| + \() -> + Expect.equal bExpected + ((Dict.merge Dict.insert insertBoth Dict.insert b1 b2 Dict.empty) |> Dict.toList) + ] + in + describe "Dict Tests" + [ buildTests + , queryTests + , combineTests + , transformTests + , mergeTests + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm new file mode 100644 index 0000000..1737477 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Equality.elm @@ -0,0 +1,34 @@ +module Test.Equality exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + + +type Different + = A String + | B (List Int) + + +tests : Test +tests = + let + diffTests = + describe "ADT equality" + [ test "As eq" <| \() -> Expect.equal True (A "a" == A "a") + , test "Bs eq" <| \() -> Expect.equal True (B [ 1 ] == B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (A "a" /= B [ 1 ]) + , test "A left neq" <| \() -> Expect.equal True (B [ 1 ] /= A "a") + ] + + recordTests = + describe "Record equality" + [ test "empty same" <| \() -> Expect.equal True ({} == {}) + , test "ctor same" <| \() -> Expect.equal True ({ field = Just 3 } == { field = Just 3 }) + , test "ctor same, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } == { ctor = Just 3 }) + , test "ctor diff" <| \() -> Expect.equal True ({ field = Just 3 } /= { field = Nothing }) + , test "ctor diff, special case" <| \() -> Expect.equal True ({ ctor = Just 3 } /= { ctor = Nothing }) + ] + in + describe "Equality Tests" [ diffTests, recordTests ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm new file mode 100644 index 0000000..614a1dd --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Json.elm @@ -0,0 +1,84 @@ +module Test.Json exposing (tests) + +import Basics exposing (..) +import Result exposing (..) +import Json.Decode as Json +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + describe "Json decode" + [ intTests + , customTests + ] + + +intTests : Test +intTests = + let + testInt val str = + case Json.decodeString Json.int str of + Ok _ -> + Expect.equal val True + + Err _ -> + Expect.equal val False + in + describe "Json decode int" + [ test "whole int" <| \() -> testInt True "4" + , test "-whole int" <| \() -> testInt True "-4" + , test "whole float" <| \() -> testInt True "4.0" + , test "-whole float" <| \() -> testInt True "-4.0" + , test "large int" <| \() -> testInt True "1801439850948" + , test "-large int" <| \() -> testInt True "-1801439850948" + , test "float" <| \() -> testInt False "4.2" + , test "-float" <| \() -> testInt False "-4.2" + , test "Infinity" <| \() -> testInt False "Infinity" + , test "-Infinity" <| \() -> testInt False "-Infinity" + , test "NaN" <| \() -> testInt False "NaN" + , test "-NaN" <| \() -> testInt False "-NaN" + , test "true" <| \() -> testInt False "true" + , test "false" <| \() -> testInt False "false" + , test "string" <| \() -> testInt False "\"string\"" + , test "object" <| \() -> testInt False "{}" + , test "null" <| \() -> testInt False "null" + , test "undefined" <| \() -> testInt False "undefined" + , test "Decoder expects object finds array, was crashing runtime." <| + \() -> + Expect.equal + (Err "Expecting an object but instead got: []") + (Json.decodeString (Json.dict Json.float) "[]") + ] + + +customTests : Test +customTests = + let + jsonString = + """{ "foo": "bar" }""" + + customErrorMessage = + "I want to see this message!" + + myDecoder = + Json.field "foo" Json.string |> Json.andThen (\_ -> Json.fail customErrorMessage) + + assertion = + case Json.decodeString myDecoder jsonString of + Ok _ -> + Expect.fail "expected `customDecoder` to produce a value of type Err, but got Ok" + + Err message -> + if String.contains customErrorMessage message then + Expect.pass + else + Expect.fail <| + "expected `customDecoder` to preserve user's error message '" + ++ customErrorMessage + ++ "', but instead got: " + ++ message + in + test "customDecoder preserves user error messages" <| \() -> assertion diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm new file mode 100644 index 0000000..ed26f0f --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/List.elm @@ -0,0 +1,160 @@ +module Test.List exposing (tests) + +import Test exposing (..) +import Expect +import Basics exposing (..) +import Maybe exposing (Maybe(Nothing, Just)) +import List exposing (..) + + +tests : Test +tests = + describe "List Tests" + [ testListOfN 0 + , testListOfN 1 + , testListOfN 2 + , testListOfN 5000 + ] + + +testListOfN : Int -> Test +testListOfN n = + let + xs = + List.range 1 n + + xsOpp = + List.range -n -1 + + xsNeg = + foldl (::) [] xsOpp + + -- assume foldl and (::) work + zs = + List.range 0 n + + sumSeq k = + k * (k + 1) // 2 + + xsSum = + sumSeq n + + mid = + n // 2 + in + describe (toString n ++ " elements") + [ describe "foldl" + [ test "order" <| \() -> Expect.equal (n) (foldl (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "foldr" + [ test "order" <| \() -> Expect.equal (min 1 n) (foldr (\x acc -> x) 0 xs) + , test "total" <| \() -> Expect.equal (xsSum) (foldl (+) 0 xs) + ] + , describe "map" + [ test "identity" <| \() -> Expect.equal (xs) (map identity xs) + , test "linear" <| \() -> Expect.equal (List.range 2 (n + 1)) (map ((+) 1) xs) + ] + , test "isEmpty" <| \() -> Expect.equal (n == 0) (isEmpty xs) + , test "length" <| \() -> Expect.equal (n) (length xs) + , test "reverse" <| \() -> Expect.equal (xsOpp) (reverse xsNeg) + , describe "member" + [ test "positive" <| \() -> Expect.equal (True) (member n zs) + , test "negative" <| \() -> Expect.equal (False) (member (n + 1) xs) + ] + , test "head" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (head xs) + else + Expect.equal (Just 1) (head xs) + , describe "List.filter" + [ test "none" <| \() -> Expect.equal ([]) (List.filter (\x -> x > n) xs) + , test "one" <| \() -> Expect.equal ([ n ]) (List.filter (\z -> z == n) zs) + , test "all" <| \() -> Expect.equal (xs) (List.filter (\x -> x <= n) xs) + ] + , describe "take" + [ test "none" <| \() -> Expect.equal ([]) (take 0 xs) + , test "some" <| \() -> Expect.equal (List.range 0 (n - 1)) (take n zs) + , test "all" <| \() -> Expect.equal (xs) (take n xs) + , test "all+" <| \() -> Expect.equal (xs) (take (n + 1) xs) + ] + , describe "drop" + [ test "none" <| \() -> Expect.equal (xs) (drop 0 xs) + , test "some" <| \() -> Expect.equal ([ n ]) (drop n zs) + , test "all" <| \() -> Expect.equal ([]) (drop n xs) + , test "all+" <| \() -> Expect.equal ([]) (drop (n + 1) xs) + ] + , test "repeat" <| \() -> Expect.equal (map (\x -> -1) xs) (repeat n -1) + , test "append" <| \() -> Expect.equal (xsSum * 2) (append xs xs |> foldl (+) 0) + , test "(::)" <| \() -> Expect.equal (append [ -1 ] xs) (-1 :: xs) + , test "List.concat" <| \() -> Expect.equal (append xs (append zs xs)) (List.concat [ xs, zs, xs ]) + , test "intersperse" <| + \() -> + Expect.equal + ( min -(n - 1) 0, xsSum ) + (intersperse -1 xs |> foldl (\x ( c1, c2 ) -> ( c2, c1 + x )) ( 0, 0 )) + , describe "partition" + [ test "left" <| \() -> Expect.equal ( xs, [] ) (partition (\x -> x > 0) xs) + , test "right" <| \() -> Expect.equal ( [], xs ) (partition (\x -> x < 0) xs) + , test "split" <| \() -> Expect.equal ( List.range (mid + 1) n, List.range 1 mid ) (partition (\x -> x > mid) xs) + ] + , describe "map2" + [ test "same length" <| \() -> Expect.equal (map ((*) 2) xs) (map2 (+) xs xs) + , test "long first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) zs xs) + , test "short first" <| \() -> Expect.equal (map (\x -> x * 2 - 1) xs) (map2 (+) xs zs) + ] + , test "unzip" <| \() -> Expect.equal ( xsNeg, xs ) (map (\x -> ( -x, x )) xs |> unzip) + , describe "filterMap" + [ test "none" <| \() -> Expect.equal ([]) (filterMap (\x -> Nothing) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (filterMap (\x -> Just -x) xs) + , let + halve x = + if x % 2 == 0 then + Just (x // 2) + else + Nothing + in + test "some" <| \() -> Expect.equal (List.range 1 mid) (filterMap halve xs) + ] + , describe "concatMap" + [ test "none" <| \() -> Expect.equal ([]) (concatMap (\x -> []) xs) + , test "all" <| \() -> Expect.equal (xsNeg) (concatMap (\x -> [ -x ]) xs) + ] + , test "indexedMap" <| \() -> Expect.equal (map2 (,) zs xsNeg) (indexedMap (\i x -> ( i, -x )) xs) + , test "sum" <| \() -> Expect.equal (xsSum) (sum xs) + , test "product" <| \() -> Expect.equal (0) (product zs) + , test "maximum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (maximum xs) + else + Expect.equal (Just n) (maximum xs) + , test "minimum" <| + \() -> + if n == 0 then + Expect.equal (Nothing) (minimum xs) + else + Expect.equal (Just 1) (minimum xs) + , describe "all" + [ test "false" <| \() -> Expect.equal (False) (all (\z -> z < n) zs) + , test "true" <| \() -> Expect.equal (True) (all (\x -> x <= n) xs) + ] + , describe "any" + [ test "false" <| \() -> Expect.equal (False) (any (\x -> x > n) xs) + , test "true" <| \() -> Expect.equal (True) (any (\z -> z >= n) zs) + ] + , describe "sort" + [ test "sorted" <| \() -> Expect.equal (xs) (sort xs) + , test "unsorted" <| \() -> Expect.equal (xsOpp) (sort xsNeg) + ] + , describe "sortBy" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortBy negate xsOpp) + ] + , describe "sortWith" + [ test "sorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsNeg) + , test "unsorted" <| \() -> Expect.equal (xsNeg) (sortWith (flip compare) xsOpp) + ] + , test "scanl" <| \() -> Expect.equal (0 :: map sumSeq xs) (scanl (+) 0 xs) + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm new file mode 100644 index 0000000..dfa8e5e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Maybe.elm @@ -0,0 +1,169 @@ +module Test.Maybe exposing (tests) + +import Basics exposing (..) +import Maybe exposing (..) +import Test exposing (..) +import Expect + +tests : Test +tests = + describe "Maybe Tests" + + [ describe "Common Helpers Tests" + + [ describe "withDefault Tests" + [ test "no default used" <| + \() -> Expect.equal 0 (Maybe.withDefault 5 (Just 0)) + , test "default used" <| + \() -> Expect.equal 5 (Maybe.withDefault 5 (Nothing)) + ] + + , describe "map Tests" + ( let f = (\n -> n + 1) in + [ test "on Just" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map f (Just 0)) + , test "on Nothing" <| + \() -> + Expect.equal + Nothing + (Maybe.map f Nothing) + ] + ) + + , describe "map2 Tests" + ( let f = (+) in + [ test "on (Just, Just)" <| + \() -> + Expect.equal + (Just 1) + (Maybe.map2 f (Just 0) (Just 1)) + , test "on (Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f (Just 0) Nothing) + , test "on (Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map2 f Nothing (Just 0)) + ] + ) + + , describe "map3 Tests" + ( let f = (\a b c -> a + b + c) in + [ test "on (Just, Just, Just)" <| + \() -> + Expect.equal + (Just 3) + (Maybe.map3 f (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) (Just 1) Nothing) + , test "on (Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f (Just 1) Nothing (Just 1)) + , test "on (Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map3 f Nothing (Just 1) (Just 1)) + ] + ) + + , describe "map4 Tests" + ( let f = (\a b c d -> a + b + c + d) in + [ test "on (Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 4) + (Maybe.map4 f (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map4 f Nothing (Just 1) (Just 1) (Just 1)) + ] + ) + + , describe "map5 Tests" + ( let f = (\a b c d e -> a + b + c + d + e) in + [ test "on (Just, Just, Just, Just, Just)" <| + \() -> + Expect.equal + (Just 5) + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) (Just 1)) + , test "on (Just, Just, Just, Just, Nothing)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) (Just 1) Nothing) + , test "on (Just, Just, Just, Nothing, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) (Just 1) Nothing (Just 1)) + , test "on (Just, Just, Nothing, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) (Just 1) Nothing (Just 1) (Just 1)) + , test "on (Just, Nothing, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f (Just 1) Nothing (Just 1) (Just 1) (Just 1)) + , test "on (Nothing, Just, Just, Just, Just)" <| + \() -> + Expect.equal + Nothing + (Maybe.map5 f Nothing (Just 1) (Just 1) (Just 1) (Just 1)) + ] + ) + + ] + + , describe "Chaining Maybes Tests" + + [ describe "andThen Tests" + [ test "succeeding chain" <| + \() -> + Expect.equal + (Just 1) + (Maybe.andThen (\a -> Just a) (Just 1)) + , test "failing chain (original Maybe failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Just a) Nothing) + , test "failing chain (chained function failed)" <| + \() -> + Expect.equal + Nothing + (Maybe.andThen (\a -> Nothing) (Just 1)) + ] + ] + + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm new file mode 100644 index 0000000..478d44b --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Regex.elm @@ -0,0 +1,57 @@ +module Test.Regex exposing (tests) + +import Basics exposing (..) +import Regex exposing (..) +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "split All" <| \() -> Expect.equal [ "a", "b" ] (split All (regex ",") "a,b") + , test "split" <| \() -> Expect.equal [ "a", "b,c" ] (split (AtMost 1) (regex ",") "a,b,c") + , test "split idempotent" <| + \() -> + let + findComma = + regex "," + in + Expect.equal + (split (AtMost 1) findComma "a,b,c,d,e") + (split (AtMost 1) findComma "a,b,c,d,e") + , test "find All" <| + \() -> + Expect.equal + ([ Match "a" [] 0 1, Match "b" [] 1 2 ]) + (find All (regex ".") "ab") + , test "find All" <| + \() -> + Expect.equal + ([ Match "" [] 0 1 ]) + (find All (regex ".*") "") + , test "replace AtMost 0" <| + \() -> + Expect.equal "The quick brown fox" + (replace (AtMost 0) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 1" <| + \() -> + Expect.equal "Th quick brown fox" + (replace (AtMost 1) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace AtMost 2" <| + \() -> + Expect.equal "Th qick brown fox" + (replace (AtMost 2) (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace All" <| + \() -> + Expect.equal "Th qck brwn fx" + (replace All (regex "[aeiou]") (\_ -> "") "The quick brown fox") + , test "replace using index" <| + \() -> + Expect.equal "a1b3c" + (replace All (regex ",") (\match -> toString match.index) "a,b,c") + ] + in + describe "Regex" [ simpleTests ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm new file mode 100644 index 0000000..6679e7e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Result.elm @@ -0,0 +1,70 @@ +module Test.Result exposing (tests) + +import Basics exposing (..) +import Result +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +isEven n = + if n % 2 == 0 then + Ok n + else + Err "number is odd" + + +add3 a b c = + a + b + c + + +add4 a b c d = + a + b + c + d + + +add5 a b c d e = + a + b + c + d + e + + +tests : Test +tests = + let + mapTests = + describe "map Tests" + [ test "map Ok" <| \() -> Expect.equal (Ok 3) (Result.map ((+) 1) (Ok 2)) + , test "map Err" <| \() -> Expect.equal (Err "error") (Result.map ((+) 1) (Err "error")) + ] + + mapNTests = + describe "mapN Tests" + [ test "map2 Ok" <| \() -> Expect.equal (Ok 3) (Result.map2 (+) (Ok 1) (Ok 2)) + , test "map2 Err" <| \() -> Expect.equal (Err "x") (Result.map2 (+) (Ok 1) (Err "x")) + , test "map3 Ok" <| \() -> Expect.equal (Ok 6) (Result.map3 add3 (Ok 1) (Ok 2) (Ok 3)) + , test "map3 Err" <| \() -> Expect.equal (Err "x") (Result.map3 add3 (Ok 1) (Ok 2) (Err "x")) + , test "map4 Ok" <| \() -> Expect.equal (Ok 10) (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Ok 4)) + , test "map4 Err" <| \() -> Expect.equal (Err "x") (Result.map4 add4 (Ok 1) (Ok 2) (Ok 3) (Err "x")) + , test "map5 Ok" <| \() -> Expect.equal (Ok 15) (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Ok 5)) + , test "map5 Err" <| \() -> Expect.equal (Err "x") (Result.map5 add5 (Ok 1) (Ok 2) (Ok 3) (Ok 4) (Err "x")) + ] + + andThenTests = + describe "andThen Tests" + [ test "andThen Ok" <| \() -> Expect.equal (Ok 42) ((String.toInt "42") |> Result.andThen isEven) + , test "andThen first Err" <| + \() -> + Expect.equal + (Err "could not convert string '4.2' to an Int") + (String.toInt "4.2" |> Result.andThen isEven) + , test "andThen second Err" <| + \() -> + Expect.equal + (Err "number is odd") + (String.toInt "41" |> Result.andThen isEven) + ] + in + describe "Result Tests" + [ mapTests + , mapNTests + , andThenTests + ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm new file mode 100644 index 0000000..e98caaa --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/Set.elm @@ -0,0 +1,52 @@ +module Test.Set exposing (tests) + +import Basics exposing (..) +import Set +import Set exposing (Set) +import List +import Test exposing (..) +import Expect + + +set : Set Int +set = + Set.fromList <| List.range 1 100 + + +setPart1 : Set Int +setPart1 = + Set.fromList <| List.range 1 50 + + +setPart2 : Set Int +setPart2 = + Set.fromList <| List.range 51 100 + + +pred : Int -> Bool +pred x = + x <= 50 + + +tests : Test +tests = + let + queryTests = + describe "query Tests" + [ test "size of set of 100 elements" <| + \() -> Expect.equal 100 (Set.size set) + ] + + filterTests = + describe "filter Tests" + [ test "Simple filter" <| + \() -> Expect.equal setPart1 <| Set.filter pred set + ] + + partitionTests = + describe "partition Tests" + [ test "Simple partition" <| + \() -> Expect.equal ( setPart1, setPart2 ) <| Set.partition pred set + ] + in + describe "Set Tests" [ queryTests, partitionTests, filterTests ] diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm new file mode 100644 index 0000000..f682775 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/Test/String.elm @@ -0,0 +1,110 @@ +module Test.String exposing (tests) + +import Basics exposing (..) +import List +import Maybe exposing (..) +import Result exposing (Result(..)) +import String +import Test exposing (..) +import Expect + + +tests : Test +tests = + let + simpleTests = + describe "Simple Stuff" + [ test "is empty" <| \() -> Expect.equal True (String.isEmpty "") + , test "is not empty" <| \() -> Expect.equal True (not (String.isEmpty ("the world"))) + , test "length" <| \() -> Expect.equal 11 (String.length "innumerable") + , test "endsWith" <| \() -> Expect.equal True <| String.endsWith "ship" "spaceship" + , test "reverse" <| \() -> Expect.equal "desserts" (String.reverse "stressed") + , test "repeat" <| \() -> Expect.equal "hahaha" (String.repeat 3 "ha") + , test "indexes" <| \() -> Expect.equal [ 0, 2 ] (String.indexes "a" "aha") + , test "empty indexes" <| \() -> Expect.equal [] (String.indexes "" "aha") + ] + + combiningTests = + describe "Combining Strings" + [ test "uncons non-empty" <| \() -> Expect.equal (Just ( 'a', "bc" )) (String.uncons "abc") + , test "uncons empty" <| \() -> Expect.equal Nothing (String.uncons "") + , test "append 1" <| \() -> Expect.equal "butterfly" (String.append "butter" "fly") + , test "append 2" <| \() -> Expect.equal "butter" (String.append "butter" "") + , test "append 3" <| \() -> Expect.equal "butter" (String.append "" "butter") + , test "concat" <| \() -> Expect.equal "nevertheless" (String.concat [ "never", "the", "less" ]) + , test "split commas" <| \() -> Expect.equal [ "cat", "dog", "cow" ] (String.split "," "cat,dog,cow") + , test "split slashes" <| \() -> Expect.equal [ "home", "steve", "Desktop", "" ] (String.split "/" "home/steve/Desktop/") + , test "join spaces" <| \() -> Expect.equal "cat dog cow" (String.join " " [ "cat", "dog", "cow" ]) + , test "join slashes" <| \() -> Expect.equal "home/steve/Desktop" (String.join "/" [ "home", "steve", "Desktop" ]) + , test "slice 1" <| \() -> Expect.equal "c" (String.slice 2 3 "abcd") + , test "slice 2" <| \() -> Expect.equal "abc" (String.slice 0 3 "abcd") + , test "slice 3" <| \() -> Expect.equal "abc" (String.slice 0 -1 "abcd") + , test "slice 4" <| \() -> Expect.equal "cd" (String.slice -2 4 "abcd") + ] + + intTests = + describe "String.toInt" + [ goodInt "1234" 1234 + , goodInt "+1234" 1234 + , goodInt "-1234" -1234 + , badInt "1.34" + , badInt "1e31" + , badInt "123a" + , goodInt "0123" 123 + , goodInt "0x001A" 26 + , goodInt "0x001a" 26 + , goodInt "0xBEEF" 48879 + , badInt "0x12.0" + , badInt "0x12an" + ] + + floatTests = + describe "String.toFloat" + [ goodFloat "123" 123 + , goodFloat "3.14" 3.14 + , goodFloat "+3.14" 3.14 + , goodFloat "-3.14" -3.14 + , goodFloat "0.12" 0.12 + , goodFloat ".12" 0.12 + , goodFloat "1e-42" 1e-42 + , goodFloat "6.022e23" 6.022e23 + , goodFloat "6.022E23" 6.022e23 + , goodFloat "6.022e+23" 6.022e23 + , badFloat "6.022e" + , badFloat "6.022n" + , badFloat "6.022.31" + ] + in + describe "String" [ simpleTests, combiningTests, intTests, floatTests ] + + + +-- NUMBER HELPERS + + +goodInt : String -> Int -> Test +goodInt str int = + test str <| \_ -> + Expect.equal (Ok int) (String.toInt str) + + +badInt : String -> Test +badInt str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to an Int")) + (String.toInt str) + + +goodFloat : String -> Float -> Test +goodFloat str float = + test str <| \_ -> + Expect.equal (Ok float) (String.toFloat str) + + +badFloat : String -> Test +badFloat str = + test str <| \_ -> + Expect.equal + (Err ("could not convert string '" ++ str ++ "' to a Float")) + (String.toFloat str) diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json new file mode 100644 index 0000000..e27cfa4 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "1.1.1", + "summary": "Tests for Elm's standard libraries", + "repository": "http://github.com/elm-lang/core.git", + "license": "BSD3", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [ ], + "native-modules": true, + "dependencies": { + "elm-community/elm-test": "3.1.0 <= v < 4.0.0", + "rtfeldman/node-test-runner": "3.0.0 <= v < 4.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/run-tests.sh b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/run-tests.sh new file mode 100644 index 0000000..9e2f9bc --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/core/5.1.1/tests/run-tests.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +cd "$(dirname "$0")" +set -e + + +elm-package install -y + +VERSION_DIR="$(ls elm-stuff/packages/elm-lang/core/)" +CORE_PACKAGE_DIR="elm-stuff/packages/elm-lang/core/$VERSION_DIR" +CORE_GIT_DIR="$(dirname $PWD)" + +echo "Linking $CORE_PACKAGE_DIR to $CORE_GIT_DIR" +rm -rf $CORE_PACKAGE_DIR +ln -s $CORE_GIT_DIR $CORE_PACKAGE_DIR + +elm-make --yes --output test.js Main.elm + +elm-test Main.elm diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore b/part10/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore new file mode 100644 index 0000000..e185314 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/.gitignore @@ -0,0 +1 @@ +elm-stuff \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE b/part10/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE new file mode 100644 index 0000000..e0419a4 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/README.md b/part10/elm-stuff/packages/elm-lang/html/2.0.0/README.md new file mode 100644 index 0000000..baed9a7 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/README.md @@ -0,0 +1,5 @@ +# HTML for Elm + +The core HTML library for Elm. It is backed by [elm-lang/virtual-dom](http://package.elm-lang.org/packages/elm-lang/virtual-dom/latest/) which handles the dirty details of rendering things quickly. + +The best way to learn how to use this library is to read [guide.elm-lang.org](http://guide.elm-lang.org/), particularly the section on [The Elm Architecture](http://guide.elm-lang.org/architecture/index.html). diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json b/part10/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json new file mode 100644 index 0000000..952aed5 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/elm-package.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "summary": "Fast HTML, rendered with virtual DOM diffing", + "repository": "https://github.com/elm-lang/html.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Html", + "Html.Attributes", + "Html.Events", + "Html.Keyed", + "Html.Lazy" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/virtual-dom": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/properties-vs-attributes.md b/part10/elm-stuff/packages/elm-lang/html/2.0.0/properties-vs-attributes.md new file mode 100644 index 0000000..41f7565 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/properties-vs-attributes.md @@ -0,0 +1,15 @@ +# Properties vs. Attributes + +When you are working with HTML, you can have DOM nodes like `
`. And you can add *attributes* to those DOM nodes, like ``. + +When you are creating DOM nodes in JavaScript, there are two ways to add attributes like this: + + 1. **Attributes** — You can use the `setAttribute` function. So adding a class attribute would look like this: `domNode.setAttribute('class', 'user-info')`. + + 2. **Properties** — JavaScript often exposes an alternate way to set these attributes. Another way to add a class attribute would be like this: `domNode.className = 'user-info'` + +Notice that the attribute is called `class` but the property is called `className`. This is because `class` is a reserved word in JavaScript. Point is, **attributes and properties do not always match up.** + +It is actually a bit crazier than that though. **Sometimes an attribute exists, but there is no corresponding property.** For example, as of this writing the `webkit-playsinline` can be added with `setAttribute`, but there is no corresponding property. And with SVG, you cannot use properties at all, you must to use `setAttributeNS` for everything. + +With all the corner cases here, it makes sense to have access to both approaches. \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm new file mode 100644 index 0000000..b872a3b --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html.elm @@ -0,0 +1,923 @@ +module Html exposing + ( Html, Attribute + , text, node, map + , beginnerProgram, program, programWithFlags + , h1, h2, h3, h4, h5, h6 + , div, p, hr, pre, blockquote + , span, a, code, em, strong, i, b, u, sub, sup, br + , ol, ul, li, dl, dt, dd + , img, iframe, canvas, math + , form, input, textarea, button, select, option + , section, nav, article, aside, header, footer, address, main_, body + , figure, figcaption + , table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + , fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + , audio, video, source, track + , embed, object, param + , ins, del + , small, cite, dfn, abbr, time, var, samp, kbd, s, q + , mark, ruby, rt, rp, bdi, bdo, wbr + , details, summary, menuitem, menu + ) + +{-| This file is organized roughly in order of popularity. The tags which you'd +expect to use frequently will be closer to the top. + +# Primitives +@docs Html, Attribute, text, node, map + +# Programs +@docs beginnerProgram, program, programWithFlags + +# Tags + +## Headers +@docs h1, h2, h3, h4, h5, h6 + +## Grouping Content +@docs div, p, hr, pre, blockquote + +## Text +@docs span, a, code, em, strong, i, b, u, sub, sup, br + +## Lists +@docs ol, ul, li, dl, dt, dd + +## Emdedded Content +@docs img, iframe, canvas, math + +## Inputs +@docs form, input, textarea, button, select, option + +## Sections +@docs section, nav, article, aside, header, footer, address, main_, body + +## Figures +@docs figure, figcaption + +## Tables +@docs table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th + + +## Less Common Elements + +### Less Common Inputs +@docs fieldset, legend, label, datalist, optgroup, keygen, output, progress, meter + +### Audio and Video +@docs audio, video, source, track + +### Embedded Objects +@docs embed, object, param + +### Text Edits +@docs ins, del + +### Semantic Text +@docs small, cite, dfn, abbr, time, var, samp, kbd, s, q + +### Less Common Text Tags +@docs mark, ruby, rt, rp, bdi, bdo, wbr + +## Interactive Elements +@docs details, summary, menuitem, menu + +-} + +import VirtualDom + + + +-- CORE TYPES + + +{-| The core building block used to build up HTML. Here we create an `Html` +value with no attributes and one child: + + hello : Html msg + hello = + div [] [ text "Hello!" ] +-} +type alias Html msg = VirtualDom.Node msg + + +{-| Set attributes on your `Html`. Learn more in the +[`Html.Attributes`](Html-Attributes) module. +-} +type alias Attribute msg = VirtualDom.Property msg + + + +-- PRIMITIVES + + +{-| General way to create HTML nodes. It is used to define all of the helper +functions in this library. + + div : List (Attribute msg) -> List (Html msg) -> Html msg + div attributes children = + node "div" attributes children + +You can use this to create custom nodes if you need to create something that +is not covered by the helper functions in this library. +-} +node : String -> List (Attribute msg) -> List (Html msg) -> Html msg +node = + VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Html msg +text = + VirtualDom.text + + + +-- NESTING VIEWS + + +{-| Transform the messages produced by some `Html`. In the following example, +we have `viewButton` that produces `()` messages, and we transform those values +into `Msg` values in `view`. + + type Msg = Left | Right + + view : model -> Html Msg + view model = + div [] + [ map (\_ -> Left) (viewButton "Left") + , map (\_ -> Right) (viewButton "Right") + ] + + viewButton : String -> Html () + viewButton name = + button [ onClick () ] [ text name ] + +This should not come in handy too often. Definitely read [this][reuse] before +deciding if this is what you want. + +[reuse]: https://guide.elm-lang.org/reuse/ +-} +map : (a -> msg) -> Html a -> Html msg +map = + VirtualDom.map + + + +-- CREATING PROGRAMS + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +The additional context is very worthwhile! (Honestly, it is best to just read +that guide from front to back instead of muddling around and reading it +piecemeal.) + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +beginnerProgram + : { model : model + , view : model -> Html msg + , update : msg -> model -> model + } + -> Program Never model msg +beginnerProgram {model, view, update} = + program + { init = model ! [] + , update = \msg model -> update msg model ! [] + , view = view + , subscriptions = \_ -> Sub.none + } + + +{-| Create a [`Program`][program] that describes how your whole app works. + +Read about [The Elm Architecture][tea] to learn how to use this. Just do it. +Commands and subscriptions make way more sense when you work up to them +gradually and see them in context with examples. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[tea]: https://guide.elm-lang.org/architecture/ +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program Never model msg +program = + VirtualDom.program + + +{-| Create a [`Program`][program] that describes how your whole app works. + +It works just like `program` but you can provide “flags” from +JavaScript to configure your application. Read more about that [here][]. + +[program]: http://package.elm-lang.org/packages/elm-lang/core/latest/Platform#Program +[here]: https://guide.elm-lang.org/interop/javascript.html +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Html msg + } + -> Program flags model msg +programWithFlags = + VirtualDom.programWithFlags + + + +-- SECTIONS + + +{-| Represents the content of an HTML document. There is only one `body` +element in a document. +-} +body : List (Attribute msg) -> List (Html msg) -> Html msg +body = + node "body" + + +{-| Defines a section in a document. +-} +section : List (Attribute msg) -> List (Html msg) -> Html msg +section = + node "section" + + +{-| Defines a section that contains only navigation links. +-} +nav : List (Attribute msg) -> List (Html msg) -> Html msg +nav = + node "nav" + + +{-| Defines self-contained content that could exist independently of the rest +of the content. +-} +article : List (Attribute msg) -> List (Html msg) -> Html msg +article = + node "article" + + +{-| Defines some content loosely related to the page content. If it is removed, +the remaining content still makes sense. +-} +aside : List (Attribute msg) -> List (Html msg) -> Html msg +aside = + node "aside" + + +{-|-} +h1 : List (Attribute msg) -> List (Html msg) -> Html msg +h1 = + node "h1" + + +{-|-} +h2 : List (Attribute msg) -> List (Html msg) -> Html msg +h2 = + node "h2" + + +{-|-} +h3 : List (Attribute msg) -> List (Html msg) -> Html msg +h3 = + node "h3" + + +{-|-} +h4 : List (Attribute msg) -> List (Html msg) -> Html msg +h4 = + node "h4" + + +{-|-} +h5 : List (Attribute msg) -> List (Html msg) -> Html msg +h5 = + node "h5" + + +{-|-} +h6 : List (Attribute msg) -> List (Html msg) -> Html msg +h6 = + node "h6" + + +{-| Defines the header of a page or section. It often contains a logo, the +title of the web site, and a navigational table of content. +-} +header : List (Attribute msg) -> List (Html msg) -> Html msg +header = + node "header" + + +{-| Defines the footer for a page or section. It often contains a copyright +notice, some links to legal information, or addresses to give feedback. +-} +footer : List (Attribute msg) -> List (Html msg) -> Html msg +footer = + node "footer" + + +{-| Defines a section containing contact information. -} +address : List (Attribute msg) -> List (Html msg) -> Html msg +address = + node "address" + + +{-| Defines the main or important content in the document. There is only one +`main` element in the document. +-} +main_ : List (Attribute msg) -> List (Html msg) -> Html msg +main_ = + node "main" + + +-- GROUPING CONTENT + +{-| Defines a portion that should be displayed as a paragraph. -} +p : List (Attribute msg) -> List (Html msg) -> Html msg +p = + node "p" + + +{-| Represents a thematic break between paragraphs of a section or article or +any longer content. +-} +hr : List (Attribute msg) -> List (Html msg) -> Html msg +hr = + node "hr" + + +{-| Indicates that its content is preformatted and that this format must be +preserved. +-} +pre : List (Attribute msg) -> List (Html msg) -> Html msg +pre = + node "pre" + + +{-| Represents a content that is quoted from another source. -} +blockquote : List (Attribute msg) -> List (Html msg) -> Html msg +blockquote = + node "blockquote" + + +{-| Defines an ordered list of items. -} +ol : List (Attribute msg) -> List (Html msg) -> Html msg +ol = + node "ol" + + +{-| Defines an unordered list of items. -} +ul : List (Attribute msg) -> List (Html msg) -> Html msg +ul = + node "ul" + + +{-| Defines a item of an enumeration list. -} +li : List (Attribute msg) -> List (Html msg) -> Html msg +li = + node "li" + + +{-| Defines a definition list, that is, a list of terms and their associated +definitions. +-} +dl : List (Attribute msg) -> List (Html msg) -> Html msg +dl = + node "dl" + + +{-| Represents a term defined by the next `dd`. -} +dt : List (Attribute msg) -> List (Html msg) -> Html msg +dt = + node "dt" + + +{-| Represents the definition of the terms immediately listed before it. -} +dd : List (Attribute msg) -> List (Html msg) -> Html msg +dd = + node "dd" + + +{-| Represents a figure illustrated as part of the document. -} +figure : List (Attribute msg) -> List (Html msg) -> Html msg +figure = + node "figure" + + +{-| Represents the legend of a figure. -} +figcaption : List (Attribute msg) -> List (Html msg) -> Html msg +figcaption = + node "figcaption" + + +{-| Represents a generic container with no special meaning. -} +div : List (Attribute msg) -> List (Html msg) -> Html msg +div = + node "div" + + +-- TEXT LEVEL SEMANTIC + +{-| Represents a hyperlink, linking to another resource. -} +a : List (Attribute msg) -> List (Html msg) -> Html msg +a = + node "a" + + +{-| Represents emphasized text, like a stress accent. -} +em : List (Attribute msg) -> List (Html msg) -> Html msg +em = + node "em" + + +{-| Represents especially important text. -} +strong : List (Attribute msg) -> List (Html msg) -> Html msg +strong = + node "strong" + + +{-| Represents a side comment, that is, text like a disclaimer or a +copyright, which is not essential to the comprehension of the document. +-} +small : List (Attribute msg) -> List (Html msg) -> Html msg +small = + node "small" + + +{-| Represents content that is no longer accurate or relevant. -} +s : List (Attribute msg) -> List (Html msg) -> Html msg +s = + node "s" + + +{-| Represents the title of a work. -} +cite : List (Attribute msg) -> List (Html msg) -> Html msg +cite = + node "cite" + + +{-| Represents an inline quotation. -} +q : List (Attribute msg) -> List (Html msg) -> Html msg +q = + node "q" + + +{-| Represents a term whose definition is contained in its nearest ancestor +content. +-} +dfn : List (Attribute msg) -> List (Html msg) -> Html msg +dfn = + node "dfn" + + +{-| Represents an abbreviation or an acronym; the expansion of the +abbreviation can be represented in the title attribute. +-} +abbr : List (Attribute msg) -> List (Html msg) -> Html msg +abbr = + node "abbr" + + +{-| Represents a date and time value; the machine-readable equivalent can be +represented in the datetime attribute. +-} +time : List (Attribute msg) -> List (Html msg) -> Html msg +time = + node "time" + + +{-| Represents computer code. -} +code : List (Attribute msg) -> List (Html msg) -> Html msg +code = + node "code" + + +{-| Represents a variable. Specific cases where it should be used include an +actual mathematical expression or programming context, an identifier +representing a constant, a symbol identifying a physical quantity, a function +parameter, or a mere placeholder in prose. +-} +var : List (Attribute msg) -> List (Html msg) -> Html msg +var = + node "var" + + +{-| Represents the output of a program or a computer. -} +samp : List (Attribute msg) -> List (Html msg) -> Html msg +samp = + node "samp" + + +{-| Represents user input, often from the keyboard, but not necessarily; it +may represent other input, like transcribed voice commands. +-} +kbd : List (Attribute msg) -> List (Html msg) -> Html msg +kbd = + node "kbd" + + +{-| Represent a subscript. -} +sub : List (Attribute msg) -> List (Html msg) -> Html msg +sub = + node "sub" + + +{-| Represent a superscript. -} +sup : List (Attribute msg) -> List (Html msg) -> Html msg +sup = + node "sup" + + +{-| Represents some text in an alternate voice or mood, or at least of +different quality, such as a taxonomic designation, a technical term, an +idiomatic phrase, a thought, or a ship name. +-} +i : List (Attribute msg) -> List (Html msg) -> Html msg +i = + node "i" + + +{-| Represents a text which to which attention is drawn for utilitarian +purposes. It doesn't convey extra importance and doesn't imply an alternate +voice. +-} +b : List (Attribute msg) -> List (Html msg) -> Html msg +b = + node "b" + + +{-| Represents a non-textual annoatation for which the conventional +presentation is underlining, such labeling the text as being misspelt or +labeling a proper name in Chinese text. +-} +u : List (Attribute msg) -> List (Html msg) -> Html msg +u = + node "u" + + +{-| Represents text highlighted for reference purposes, that is for its +relevance in another context. +-} +mark : List (Attribute msg) -> List (Html msg) -> Html msg +mark = + node "mark" + + +{-| Represents content to be marked with ruby annotations, short runs of text +presented alongside the text. This is often used in conjunction with East Asian +language where the annotations act as a guide for pronunciation, like the +Japanese furigana. +-} +ruby : List (Attribute msg) -> List (Html msg) -> Html msg +ruby = + node "ruby" + + +{-| Represents the text of a ruby annotation. -} +rt : List (Attribute msg) -> List (Html msg) -> Html msg +rt = + node "rt" + + +{-| Represents parenthesis around a ruby annotation, used to display the +annotation in an alternate way by browsers not supporting the standard display +for annotations. +-} +rp : List (Attribute msg) -> List (Html msg) -> Html msg +rp = + node "rp" + + +{-| Represents text that must be isolated from its surrounding for +bidirectional text formatting. It allows embedding a span of text with a +different, or unknown, directionality. +-} +bdi : List (Attribute msg) -> List (Html msg) -> Html msg +bdi = + node "bdi" + + +{-| Represents the directionality of its children, in order to explicitly +override the Unicode bidirectional algorithm. +-} +bdo : List (Attribute msg) -> List (Html msg) -> Html msg +bdo = + node "bdo" + + +{-| Represents text with no specific meaning. This has to be used when no other +text-semantic element conveys an adequate meaning, which, in this case, is +often brought by global attributes like `class`, `lang`, or `dir`. +-} +span : List (Attribute msg) -> List (Html msg) -> Html msg +span = + node "span" + + +{-| Represents a line break. -} +br : List (Attribute msg) -> List (Html msg) -> Html msg +br = + node "br" + + +{-| Represents a line break opportunity, that is a suggested point for +wrapping text in order to improve readability of text split on several lines. +-} +wbr : List (Attribute msg) -> List (Html msg) -> Html msg +wbr = + node "wbr" + + +-- EDITS + +{-| Defines an addition to the document. -} +ins : List (Attribute msg) -> List (Html msg) -> Html msg +ins = + node "ins" + + +{-| Defines a removal from the document. -} +del : List (Attribute msg) -> List (Html msg) -> Html msg +del = + node "del" + + +-- EMBEDDED CONTENT + +{-| Represents an image. -} +img : List (Attribute msg) -> List (Html msg) -> Html msg +img = + node "img" + + +{-| Embedded an HTML document. -} +iframe : List (Attribute msg) -> List (Html msg) -> Html msg +iframe = + node "iframe" + + +{-| Represents a integration point for an external, often non-HTML, +application or interactive content. +-} +embed : List (Attribute msg) -> List (Html msg) -> Html msg +embed = + node "embed" + + +{-| Represents an external resource, which is treated as an image, an HTML +sub-document, or an external resource to be processed by a plug-in. +-} +object : List (Attribute msg) -> List (Html msg) -> Html msg +object = + node "object" + + +{-| Defines parameters for use by plug-ins invoked by `object` elements. -} +param : List (Attribute msg) -> List (Html msg) -> Html msg +param = + node "param" + + +{-| Represents a video, the associated audio and captions, and controls. -} +video : List (Attribute msg) -> List (Html msg) -> Html msg +video = + node "video" + + +{-| Represents a sound or audio stream. -} +audio : List (Attribute msg) -> List (Html msg) -> Html msg +audio = + node "audio" + + +{-| Allows authors to specify alternative media resources for media elements +like `video` or `audio`. +-} +source : List (Attribute msg) -> List (Html msg) -> Html msg +source = + node "source" + + +{-| Allows authors to specify timed text track for media elements like `video` +or `audio`. +-} +track : List (Attribute msg) -> List (Html msg) -> Html msg +track = + node "track" + + +{-| Represents a bitmap area for graphics rendering. -} +canvas : List (Attribute msg) -> List (Html msg) -> Html msg +canvas = + node "canvas" + + +{-| Defines a mathematical formula. -} +math : List (Attribute msg) -> List (Html msg) -> Html msg +math = + node "math" + + +-- TABULAR DATA + +{-| Represents data with more than one dimension. -} +table : List (Attribute msg) -> List (Html msg) -> Html msg +table = + node "table" + + +{-| Represents the title of a table. -} +caption : List (Attribute msg) -> List (Html msg) -> Html msg +caption = + node "caption" + + +{-| Represents a set of one or more columns of a table. -} +colgroup : List (Attribute msg) -> List (Html msg) -> Html msg +colgroup = + node "colgroup" + + +{-| Represents a column of a table. -} +col : List (Attribute msg) -> List (Html msg) -> Html msg +col = + node "col" + + +{-| Represents the block of rows that describes the concrete data of a table. +-} +tbody : List (Attribute msg) -> List (Html msg) -> Html msg +tbody = + node "tbody" + + +{-| Represents the block of rows that describes the column labels of a table. +-} +thead : List (Attribute msg) -> List (Html msg) -> Html msg +thead = + node "thead" + + +{-| Represents the block of rows that describes the column summaries of a table. +-} +tfoot : List (Attribute msg) -> List (Html msg) -> Html msg +tfoot = + node "tfoot" + + +{-| Represents a row of cells in a table. -} +tr : List (Attribute msg) -> List (Html msg) -> Html msg +tr = + node "tr" + + +{-| Represents a data cell in a table. -} +td : List (Attribute msg) -> List (Html msg) -> Html msg +td = + node "td" + + +{-| Represents a header cell in a table. -} +th : List (Attribute msg) -> List (Html msg) -> Html msg +th = + node "th" + + +-- FORMS + +{-| Represents a form, consisting of controls, that can be submitted to a +server for processing. +-} +form : List (Attribute msg) -> List (Html msg) -> Html msg +form = + node "form" + + +{-| Represents a set of controls. -} +fieldset : List (Attribute msg) -> List (Html msg) -> Html msg +fieldset = + node "fieldset" + + +{-| Represents the caption for a `fieldset`. -} +legend : List (Attribute msg) -> List (Html msg) -> Html msg +legend = + node "legend" + + +{-| Represents the caption of a form control. -} +label : List (Attribute msg) -> List (Html msg) -> Html msg +label = + node "label" + + +{-| Represents a typed data field allowing the user to edit the data. -} +input : List (Attribute msg) -> List (Html msg) -> Html msg +input = + node "input" + + +{-| Represents a button. -} +button : List (Attribute msg) -> List (Html msg) -> Html msg +button = + node "button" + + +{-| Represents a control allowing selection among a set of options. -} +select : List (Attribute msg) -> List (Html msg) -> Html msg +select = + node "select" + + +{-| Represents a set of predefined options for other controls. -} +datalist : List (Attribute msg) -> List (Html msg) -> Html msg +datalist = + node "datalist" + + +{-| Represents a set of options, logically grouped. -} +optgroup : List (Attribute msg) -> List (Html msg) -> Html msg +optgroup = + node "optgroup" + + +{-| Represents an option in a `select` element or a suggestion of a `datalist` +element. +-} +option : List (Attribute msg) -> List (Html msg) -> Html msg +option = + node "option" + + +{-| Represents a multiline text edit control. -} +textarea : List (Attribute msg) -> List (Html msg) -> Html msg +textarea = + node "textarea" + + +{-| Represents a key-pair generator control. -} +keygen : List (Attribute msg) -> List (Html msg) -> Html msg +keygen = + node "keygen" + + +{-| Represents the result of a calculation. -} +output : List (Attribute msg) -> List (Html msg) -> Html msg +output = + node "output" + + +{-| Represents the completion progress of a task. -} +progress : List (Attribute msg) -> List (Html msg) -> Html msg +progress = + node "progress" + + +{-| Represents a scalar measurement (or a fractional value), within a known +range. +-} +meter : List (Attribute msg) -> List (Html msg) -> Html msg +meter = + node "meter" + + +-- INTERACTIVE ELEMENTS + +{-| Represents a widget from which the user can obtain additional information +or controls. +-} +details : List (Attribute msg) -> List (Html msg) -> Html msg +details = + node "details" + + +{-| Represents a summary, caption, or legend for a given `details`. -} +summary : List (Attribute msg) -> List (Html msg) -> Html msg +summary = + node "summary" + + +{-| Represents a command that the user can invoke. -} +menuitem : List (Attribute msg) -> List (Html msg) -> Html msg +menuitem = + node "menuitem" + + +{-| Represents a list of commands. -} +menu : List (Attribute msg) -> List (Html msg) -> Html msg +menu = + node "menu" + diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm new file mode 100644 index 0000000..4cdba44 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Attributes.elm @@ -0,0 +1,1009 @@ +module Html.Attributes exposing + ( style, property, attribute, map + , class, classList, id, title, hidden + , type_, value, defaultValue, checked, placeholder, selected + , accept, acceptCharset, action, autocomplete, autofocus + , disabled, enctype, formaction, list, maxlength, minlength, method, multiple + , name, novalidate, pattern, readonly, required, size, for, form + , max, min, step + , cols, rows, wrap + , href, target, download, downloadAs, hreflang, media, ping, rel + , ismap, usemap, shape, coords + , src, height, width, alt + , autoplay, controls, loop, preload, poster, default, kind, srclang + , sandbox, seamless, srcdoc + , reversed, start + , align, colspan, rowspan, headers, scope + , async, charset, content, defer, httpEquiv, language, scoped + , accesskey, contenteditable, contextmenu, dir, draggable, dropzone + , itemprop, lang, spellcheck, tabindex + , challenge, keytype + , cite, datetime, pubdate, manifest + ) + +{-| Helper functions for HTML attributes. They are organized roughly by +category. Each attribute is labeled with the HTML tags it can be used with, so +just search the page for `video` if you want video stuff. + +If you cannot find what you are looking for, go to the [Custom +Attributes](#custom-attributes) section to learn how to create new helpers. + +# Primitives +@docs style, property, attribute, map + +# Super Common Attributes +@docs class, classList, id, title, hidden + +# Inputs +@docs type_, value, defaultValue, checked, placeholder, selected + +## Input Helpers +@docs accept, acceptCharset, action, autocomplete, autofocus, + disabled, enctype, formaction, list, maxlength, minlength, method, multiple, + name, novalidate, pattern, readonly, required, size, for, form + +## Input Ranges +@docs max, min, step + +## Input Text Areas +@docs cols, rows, wrap + + +# Links and Areas +@docs href, target, download, downloadAs, hreflang, media, ping, rel + +## Maps +@docs ismap, usemap, shape, coords + + +# Embedded Content +@docs src, height, width, alt + +## Audio and Video +@docs autoplay, controls, loop, preload, poster, default, kind, srclang + +## iframes +@docs sandbox, seamless, srcdoc + +# Ordered Lists +@docs reversed, start + +# Tables +@docs align, colspan, rowspan, headers, scope + +# Header Stuff +@docs async, charset, content, defer, httpEquiv, language, scoped + +# Less Common Global Attributes +Attributes that can be attached to any HTML tag but are less commonly used. +@docs accesskey, contenteditable, contextmenu, dir, draggable, dropzone, + itemprop, lang, spellcheck, tabindex + +# Key Generation +@docs challenge, keytype + +# Miscellaneous +@docs cite, datetime, pubdate, manifest + +-} + +import Html exposing (Attribute) +import Json.Encode as Json +import VirtualDom + + +-- This library does not include low, high, or optimum because the idea of a +-- `meter` is just too crazy. + + + +-- PRIMITIVES + + +{-| Specify a list of styles. + + myStyle : Attribute msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Html msg + greeting = + div [ myStyle ] [ text "Hello!" ] + +There is no `Html.Styles` module because best practices for working with HTML +suggest that this should primarily be specified in CSS files. So the general +recommendation is to use this function lightly. +-} +style : List (String, String) -> Attribute msg +style = + VirtualDom.style + + +{-| This function makes it easier to build a space-separated class attribute. +Each class can easily be added and removed depending on the boolean value it +is paired with. For example, maybe we want a way to view notices: + + viewNotice : Notice -> Html msg + viewNotice notice = + div + [ classList + [ ("notice", True) + , ("notice-important", notice.isImportant) + , ("notice-seen", notice.isSeen) + ] + ] + [ text notice.content ] +-} +classList : List (String, Bool) -> Attribute msg +classList list = + list + |> List.filter Tuple.second + |> List.map Tuple.first + |> String.join " " + |> class + + + +-- CUSTOM ATTRIBUTES + + +{-| Create *properties*, like saying `domNode.className = 'greeting'` in +JavaScript. + + import Json.Encode as Encode + + class : String -> Attribute msg + class name = + property "className" (Encode.string name) + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +property : String -> Json.Value -> Attribute msg +property = + VirtualDom.property + + +stringProperty : String -> String -> Attribute msg +stringProperty name string = + property name (Json.string string) + + +boolProperty : String -> Bool -> Attribute msg +boolProperty name bool = + property name (Json.bool bool) + + +{-| Create *attributes*, like saying `domNode.setAttribute('class', 'greeting')` +in JavaScript. + + class : String -> Attribute msg + class name = + attribute "class" name + +Read more about the difference between properties and attributes [here][]. + +[here]: https://github.com/elm-lang/html/blob/master/properties-vs-attributes.md +-} +attribute : String -> String -> Attribute msg +attribute = + VirtualDom.attribute + + +{-| Transform the messages produced by an `Attribute`. +-} +map : (a -> msg) -> Attribute a -> Attribute msg +map = + VirtualDom.mapProperty + + + +-- GLOBAL ATTRIBUTES + + +{-| Often used with CSS to style elements with common properties. -} +class : String -> Attribute msg +class name = + stringProperty "className" name + + +{-| Indicates the relevance of an element. -} +hidden : Bool -> Attribute msg +hidden bool = + boolProperty "hidden" bool + + +{-| Often used with CSS to style a specific element. The value of this +attribute must be unique. +-} +id : String -> Attribute msg +id name = + stringProperty "id" name + + +{-| Text to be displayed in a tooltip when hovering over the element. -} +title : String -> Attribute msg +title name = + stringProperty "title" name + + + +-- LESS COMMON GLOBAL ATTRIBUTES + + +{-| Defines a keyboard shortcut to activate or add focus to the element. -} +accesskey : Char -> Attribute msg +accesskey char = + stringProperty "accessKey" (String.fromChar char) + + +{-| Indicates whether the element's content is editable. -} +contenteditable : Bool -> Attribute msg +contenteditable bool = + boolProperty "contentEditable" bool + + +{-| Defines the ID of a `menu` element which will serve as the element's +context menu. +-} +contextmenu : String -> Attribute msg +contextmenu value = + attribute "contextmenu" value + + +{-| Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl +(Right-To-Left). +-} +dir : String -> Attribute msg +dir value = + stringProperty "dir" value + + +{-| Defines whether the element can be dragged. -} +draggable : String -> Attribute msg +draggable value = + attribute "draggable" value + + +{-| Indicates that the element accept the dropping of content on it. -} +dropzone : String -> Attribute msg +dropzone value = + stringProperty "dropzone" value + + +{-|-} +itemprop : String -> Attribute msg +itemprop value = + attribute "itemprop" value + + +{-| Defines the language used in the element. -} +lang : String -> Attribute msg +lang value = + stringProperty "lang" value + + +{-| Indicates whether spell checking is allowed for the element. -} +spellcheck : Bool -> Attribute msg +spellcheck bool = + boolProperty "spellcheck" bool + + +{-| Overrides the browser's default tab order and follows the one specified +instead. +-} +tabindex : Int -> Attribute msg +tabindex n = + attribute "tabIndex" (toString n) + + + +-- HEADER STUFF + + +{-| Indicates that the `script` should be executed asynchronously. -} +async : Bool -> Attribute msg +async bool = + boolProperty "async" bool + + +{-| Declares the character encoding of the page or script. Common values include: + + * UTF-8 - Character encoding for Unicode + * ISO-8859-1 - Character encoding for the Latin alphabet + +For `meta` and `script`. +-} +charset : String -> Attribute msg +charset value = + attribute "charset" value + + +{-| A value associated with http-equiv or name depending on the context. For +`meta`. +-} +content : String -> Attribute msg +content value = + stringProperty "content" value + + +{-| Indicates that a `script` should be executed after the page has been +parsed. +-} +defer : Bool -> Attribute msg +defer bool = + boolProperty "defer" bool + + +{-| This attribute is an indicator that is paired with the `content` attribute, +indicating what that content means. `httpEquiv` can take on three different +values: content-type, default-style, or refresh. For `meta`. +-} +httpEquiv : String -> Attribute msg +httpEquiv value = + stringProperty "httpEquiv" value + + +{-| Defines the script language used in a `script`. -} +language : String -> Attribute msg +language value = + stringProperty "language" value + + +{-| Indicates that a `style` should only apply to its parent and all of the +parents children. +-} +scoped : Bool -> Attribute msg +scoped bool = + boolProperty "scoped" bool + + + +-- EMBEDDED CONTENT + + +{-| The URL of the embeddable content. For `audio`, `embed`, `iframe`, `img`, +`input`, `script`, `source`, `track`, and `video`. +-} +src : String -> Attribute msg +src value = + stringProperty "src" value + + +{-| Declare the height of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +height : Int -> Attribute msg +height value = + attribute "height" (toString value) + + +{-| Declare the width of a `canvas`, `embed`, `iframe`, `img`, `input`, +`object`, or `video`. +-} +width : Int -> Attribute msg +width value = + attribute "width" (toString value) + + +{-| Alternative text in case an image can't be displayed. Works with `img`, +`area`, and `input`. +-} +alt : String -> Attribute msg +alt value = + stringProperty "alt" value + + + +-- AUDIO and VIDEO + + +{-| The `audio` or `video` should play as soon as possible. -} +autoplay : Bool -> Attribute msg +autoplay bool = + boolProperty "autoplay" bool + + +{-| Indicates whether the browser should show playback controls for the `audio` +or `video`. +-} +controls : Bool -> Attribute msg +controls bool = + boolProperty "controls" bool + + +{-| Indicates whether the `audio` or `video` should start playing from the +start when it's finished. +-} +loop : Bool -> Attribute msg +loop bool = + boolProperty "loop" bool + + +{-| Control how much of an `audio` or `video` resource should be preloaded. -} +preload : String -> Attribute msg +preload value = + stringProperty "preload" value + + +{-| A URL indicating a poster frame to show until the user plays or seeks the +`video`. +-} +poster : String -> Attribute msg +poster value = + stringProperty "poster" value + + +{-| Indicates that the `track` should be enabled unless the user's preferences +indicate something different. +-} +default : Bool -> Attribute msg +default bool = + boolProperty "default" bool + + +{-| Specifies the kind of text `track`. -} +kind : String -> Attribute msg +kind value = + stringProperty "kind" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| Specifies a user-readable title of the text `track`. -} +label : String -> Attribute msg +label value = + stringProperty "label" value +--} + +{-| A two letter language code indicating the language of the `track` text data. +-} +srclang : String -> Attribute msg +srclang value = + stringProperty "srclang" value + + + +-- IFRAMES + + +{-| A space separated list of security restrictions you'd like to lift for an +`iframe`. +-} +sandbox : String -> Attribute msg +sandbox value = + stringProperty "sandbox" value + + +{-| Make an `iframe` look like part of the containing document. -} +seamless : Bool -> Attribute msg +seamless bool = + boolProperty "seamless" bool + + +{-| An HTML document that will be displayed as the body of an `iframe`. It will +override the content of the `src` attribute if it has been specified. +-} +srcdoc : String -> Attribute msg +srcdoc value = + stringProperty "srcdoc" value + + + +-- INPUT + + +{-| Defines the type of a `button`, `input`, `embed`, `object`, `script`, +`source`, `style`, or `menu`. +-} +type_ : String -> Attribute msg +type_ value = + stringProperty "type" value + + +{-| Defines a default value which will be displayed in a `button`, `option`, +`input`, `li`, `meter`, `progress`, or `param`. +-} +value : String -> Attribute msg +value value = + stringProperty "value" value + + +{-| Defines an initial value which will be displayed in an `input` when that +`input` is added to the DOM. Unlike `value`, altering `defaultValue` after the +`input` element has been added to the DOM has no effect. +-} +defaultValue : String -> Attribute msg +defaultValue value = + stringProperty "defaultValue" value + + +{-| Indicates whether an `input` of type checkbox is checked. -} +checked : Bool -> Attribute msg +checked bool = + boolProperty "checked" bool + + +{-| Provides a hint to the user of what can be entered into an `input` or +`textarea`. +-} +placeholder : String -> Attribute msg +placeholder value = + stringProperty "placeholder" value + + +{-| Defines which `option` will be selected on page load. -} +selected : Bool -> Attribute msg +selected bool = + boolProperty "selected" bool + + + +-- INPUT HELPERS + + +{-| List of types the server accepts, typically a file type. +For `form` and `input`. +-} +accept : String -> Attribute msg +accept value = + stringProperty "accept" value + + +{-| List of supported charsets in a `form`. +-} +acceptCharset : String -> Attribute msg +acceptCharset value = + stringProperty "acceptCharset" value + + +{-| The URI of a program that processes the information submitted via a `form`. +-} +action : String -> Attribute msg +action value = + stringProperty "action" value + + +{-| Indicates whether a `form` or an `input` can have their values automatically +completed by the browser. +-} +autocomplete : Bool -> Attribute msg +autocomplete bool = + stringProperty "autocomplete" (if bool then "on" else "off") + + +{-| The element should be automatically focused after the page loaded. +For `button`, `input`, `keygen`, `select`, and `textarea`. +-} +autofocus : Bool -> Attribute msg +autofocus bool = + boolProperty "autofocus" bool + + +{-| Indicates whether the user can interact with a `button`, `fieldset`, +`input`, `keygen`, `optgroup`, `option`, `select` or `textarea`. +-} +disabled : Bool -> Attribute msg +disabled bool = + boolProperty "disabled" bool + + +{-| How `form` data should be encoded when submitted with the POST method. +Options include: application/x-www-form-urlencoded, multipart/form-data, and +text/plain. +-} +enctype : String -> Attribute msg +enctype value = + stringProperty "enctype" value + + +{-| Indicates the action of an `input` or `button`. This overrides the action +defined in the surrounding `form`. +-} +formaction : String -> Attribute msg +formaction value = + attribute "formAction" value + + +{-| Associates an `input` with a `datalist` tag. The datalist gives some +pre-defined options to suggest to the user as they interact with an input. +The value of the list attribute must match the id of a `datalist` node. +For `input`. +-} +list : String -> Attribute msg +list value = + attribute "list" value + + +{-| Defines the minimum number of characters allowed in an `input` or +`textarea`. +-} +minlength : Int -> Attribute msg +minlength n = + attribute "minLength" (toString n) + + +{-| Defines the maximum number of characters allowed in an `input` or +`textarea`. +-} +maxlength : Int -> Attribute msg +maxlength n = + attribute "maxlength" (toString n) + + +{-| Defines which HTTP method to use when submitting a `form`. Can be GET +(default) or POST. +-} +method : String -> Attribute msg +method value = + stringProperty "method" value + + +{-| Indicates whether multiple values can be entered in an `input` of type +email or file. Can also indicate that you can `select` many options. +-} +multiple : Bool -> Attribute msg +multiple bool = + boolProperty "multiple" bool + + +{-| Name of the element. For example used by the server to identify the fields +in form submits. For `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, +`object`, `output`, `select`, `textarea`, `map`, `meta`, and `param`. +-} +name : String -> Attribute msg +name value = + stringProperty "name" value + + +{-| This attribute indicates that a `form` shouldn't be validated when +submitted. +-} +novalidate : Bool -> Attribute msg +novalidate bool = + boolProperty "noValidate" bool + + +{-| Defines a regular expression which an `input`'s value will be validated +against. +-} +pattern : String -> Attribute msg +pattern value = + stringProperty "pattern" value + + +{-| Indicates whether an `input` or `textarea` can be edited. -} +readonly : Bool -> Attribute msg +readonly bool = + boolProperty "readOnly" bool + + +{-| Indicates whether this element is required to fill out or not. +For `input`, `select`, and `textarea`. +-} +required : Bool -> Attribute msg +required bool = + boolProperty "required" bool + + +{-| For `input` specifies the width of an input in characters. + +For `select` specifies the number of visible options in a drop-down list. +-} +size : Int -> Attribute msg +size n = + attribute "size" (toString n) + + +{-| The element ID described by this `label` or the element IDs that are used +for an `output`. +-} +for : String -> Attribute msg +for value = + stringProperty "htmlFor" value + + +{-| Indicates the element ID of the `form` that owns this particular `button`, +`fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, +`progress`, `select`, or `textarea`. +-} +form : String -> Attribute msg +form value = + attribute "form" value + + + +-- RANGES + + +{-| Indicates the maximum value allowed. When using an input of type number or +date, the max value must be a number or date. For `input`, `meter`, and `progress`. +-} +max : String -> Attribute msg +max value = + stringProperty "max" value + + +{-| Indicates the minimum value allowed. When using an input of type number or +date, the min value must be a number or date. For `input` and `meter`. +-} +min : String -> Attribute msg +min value = + stringProperty "min" value + + +{-| Add a step size to an `input`. Use `step "any"` to allow any floating-point +number to be used in the input. +-} +step : String -> Attribute msg +step n = + stringProperty "step" n + + +-------------------------- + + +{-| Defines the number of columns in a `textarea`. -} +cols : Int -> Attribute msg +cols n = + attribute "cols" (toString n) + + +{-| Defines the number of rows in a `textarea`. -} +rows : Int -> Attribute msg +rows n = + attribute "rows" (toString n) + + +{-| Indicates whether the text should be wrapped in a `textarea`. Possible +values are "hard" and "soft". +-} +wrap : String -> Attribute msg +wrap value = + stringProperty "wrap" value + + + +-- MAPS + + +{-| When an `img` is a descendent of an `a` tag, the `ismap` attribute +indicates that the click location should be added to the parent `a`'s href as +a query string. +-} +ismap : Bool -> Attribute msg +ismap value = + boolProperty "isMap" value + + +{-| Specify the hash name reference of a `map` that should be used for an `img` +or `object`. A hash name reference is a hash symbol followed by the element's name or id. +E.g. `"#planet-map"`. +-} +usemap : String -> Attribute msg +usemap value = + stringProperty "useMap" value + + +{-| Declare the shape of the clickable area in an `a` or `area`. Valid values +include: default, rect, circle, poly. This attribute can be paired with +`coords` to create more particular shapes. +-} +shape : String -> Attribute msg +shape value = + stringProperty "shape" value + + +{-| A set of values specifying the coordinates of the hot-spot region in an +`area`. Needs to be paired with a `shape` attribute to be meaningful. +-} +coords : String -> Attribute msg +coords value = + stringProperty "coords" value + + + +-- KEY GEN + + +{-| A challenge string that is submitted along with the public key in a `keygen`. +-} +challenge : String -> Attribute msg +challenge value = + attribute "challenge" value + + +{-| Specifies the type of key generated by a `keygen`. Possible values are: +rsa, dsa, and ec. +-} +keytype : String -> Attribute msg +keytype value = + stringProperty "keytype" value + + + +-- REAL STUFF + + +{-| Specifies the horizontal alignment of a `caption`, `col`, `colgroup`, +`hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, or +`tr`. +-} +align : String -> Attribute msg +align value = + stringProperty "align" value + + +{-| Contains a URI which points to the source of the quote or change in a +`blockquote`, `del`, `ins`, or `q`. +-} +cite : String -> Attribute msg +cite value = + stringProperty "cite" value + + + + +-- LINKS AND AREAS + + +{-| The URL of a linked resource, such as `a`, `area`, `base`, or `link`. -} +href : String -> Attribute msg +href value = + stringProperty "href" value + + +{-| Specify where the results of clicking an `a`, `area`, `base`, or `form` +should appear. Possible special values include: + + * _blank — a new window or tab + * _self — the same frame (this is default) + * _parent — the parent frame + * _top — the full body of the window + +You can also give the name of any `frame` you have created. +-} +target : String -> Attribute msg +target value = + stringProperty "target" value + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly. +-} +download : Bool -> Attribute msg +download bool = + boolProperty "download" bool + + +{-| Indicates that clicking an `a` and `area` will download the resource +directly, and that the downloaded resource with have the given filename. +-} +downloadAs : String -> Attribute msg +downloadAs value = + stringProperty "download" value + + +{-| Two-letter language code of the linked resource of an `a`, `area`, or `link`. +-} +hreflang : String -> Attribute msg +hreflang value = + stringProperty "hreflang" value + + +{-| Specifies a hint of the target media of a `a`, `area`, `link`, `source`, +or `style`. +-} +media : String -> Attribute msg +media value = + attribute "media" value + + +{-| Specify a URL to send a short POST request to when the user clicks on an +`a` or `area`. Useful for monitoring and tracking. +-} +ping : String -> Attribute msg +ping value = + stringProperty "ping" value + + +{-| Specifies the relationship of the target object to the link object. +For `a`, `area`, `link`. +-} +rel : String -> Attribute msg +rel value = + attribute "rel" value + + + +-- CRAZY STUFF + + +{-| Indicates the date and time associated with the element. +For `del`, `ins`, `time`. +-} +datetime : String -> Attribute msg +datetime value = + attribute "datetime" value + + +{-| Indicates whether this date and time is the date of the nearest `article` +ancestor element. For `time`. +-} +pubdate : String -> Attribute msg +pubdate value = + attribute "pubdate" value + + + +-- ORDERED LISTS + + +{-| Indicates whether an ordered list `ol` should be displayed in a descending +order instead of a ascending. +-} +reversed : Bool -> Attribute msg +reversed bool = + boolProperty "reversed" bool + + +{-| Defines the first number of an ordered list if you want it to be something +besides 1. +-} +start : Int -> Attribute msg +start n = + stringProperty "start" (toString n) + + + +-- TABLES + + +{-| The colspan attribute defines the number of columns a cell should span. +For `td` and `th`. +-} +colspan : Int -> Attribute msg +colspan n = + attribute "colspan" (toString n) + + +{-| A space separated list of element IDs indicating which `th` elements are +headers for this cell. For `td` and `th`. +-} +headers : String -> Attribute msg +headers value = + stringProperty "headers" value + + +{-| Defines the number of rows a table cell should span over. +For `td` and `th`. +-} +rowspan : Int -> Attribute msg +rowspan n = + attribute "rowspan" (toString n) + + +{-| Specifies the scope of a header cell `th`. Possible values are: col, row, +colgroup, rowgroup. +-} +scope : String -> Attribute msg +scope value = + stringProperty "scope" value + + +{-| Specifies the URL of the cache manifest for an `html` tag. -} +manifest : String -> Attribute msg +manifest value = + attribute "manifest" value + + +{-- TODO: maybe reintroduce once there's a better way to disambiguate imports +{-| The number of columns a `col` or `colgroup` should span. -} +span : Int -> Attribute msg +span n = + stringProperty "span" (toString n) +--} diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm new file mode 100644 index 0000000..ff5c1fe --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Events.elm @@ -0,0 +1,269 @@ +module Html.Events exposing + ( onClick, onDoubleClick + , onMouseDown, onMouseUp + , onMouseEnter, onMouseLeave + , onMouseOver, onMouseOut + , onInput, onCheck, onSubmit + , onBlur, onFocus + , on, onWithOptions, Options, defaultOptions + , targetValue, targetChecked, keyCode + ) + +{-| +It is often helpful to create an [Union Type][] so you can have many different kinds +of events as seen in the [TodoMVC][] example. + +[Union Type]: http://elm-lang.org/learn/Union-Types.elm +[TodoMVC]: https://github.com/evancz/elm-todomvc/blob/master/Todo.elm + +# Mouse Helpers +@docs onClick, onDoubleClick, + onMouseDown, onMouseUp, + onMouseEnter, onMouseLeave, + onMouseOver, onMouseOut + +# Form Helpers +@docs onInput, onCheck, onSubmit + +# Focus Helpers +@docs onBlur, onFocus + +# Custom Event Handlers +@docs on, onWithOptions, Options, defaultOptions + +# Custom Decoders +@docs targetValue, targetChecked, keyCode +-} + +import Html exposing (Attribute) +import Json.Decode as Json +import VirtualDom + + + +-- MOUSE EVENTS + + +{-|-} +onClick : msg -> Attribute msg +onClick msg = + on "click" (Json.succeed msg) + + +{-|-} +onDoubleClick : msg -> Attribute msg +onDoubleClick msg = + on "dblclick" (Json.succeed msg) + + +{-|-} +onMouseDown : msg -> Attribute msg +onMouseDown msg = + on "mousedown" (Json.succeed msg) + + +{-|-} +onMouseUp : msg -> Attribute msg +onMouseUp msg = + on "mouseup" (Json.succeed msg) + + +{-|-} +onMouseEnter : msg -> Attribute msg +onMouseEnter msg = + on "mouseenter" (Json.succeed msg) + + +{-|-} +onMouseLeave : msg -> Attribute msg +onMouseLeave msg = + on "mouseleave" (Json.succeed msg) + + +{-|-} +onMouseOver : msg -> Attribute msg +onMouseOver msg = + on "mouseover" (Json.succeed msg) + + +{-|-} +onMouseOut : msg -> Attribute msg +onMouseOut msg = + on "mouseout" (Json.succeed msg) + + + +-- FORM EVENTS + + +{-| Capture [input](https://developer.mozilla.org/en-US/docs/Web/Events/input) +events for things like text fields or text areas. + +It grabs the **string** value at `event.target.value`, so it will not work if +you need some other type of information. For example, if you want to track +inputs on a range slider, make a custom handler with [`on`](#on). + +For more details on how `onInput` works, check out [targetValue](#targetValue). +-} +onInput : (String -> msg) -> Attribute msg +onInput tagger = + on "input" (Json.map tagger targetValue) + + +{-| Capture [change](https://developer.mozilla.org/en-US/docs/Web/Events/change) +events on checkboxes. It will grab the boolean value from `event.target.checked` +on any input event. + +Check out [targetChecked](#targetChecked) for more details on how this works. +-} +onCheck : (Bool -> msg) -> Attribute msg +onCheck tagger = + on "change" (Json.map tagger targetChecked) + + +{-| Capture a [submit](https://developer.mozilla.org/en-US/docs/Web/Events/submit) +event with [`preventDefault`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) +in order to prevent the form from changing the page’s location. If you need +different behavior, use `onWithOptions` to create a customized version of +`onSubmit`. +-} +onSubmit : msg -> Attribute msg +onSubmit msg = + onWithOptions "submit" onSubmitOptions (Json.succeed msg) + + +onSubmitOptions : Options +onSubmitOptions = + { defaultOptions | preventDefault = True } + + +-- FOCUS EVENTS + + +{-|-} +onBlur : msg -> Attribute msg +onBlur msg = + on "blur" (Json.succeed msg) + + +{-|-} +onFocus : msg -> Attribute msg +onFocus msg = + on "focus" (Json.succeed msg) + + + +-- CUSTOM EVENTS + + +{-| Create a custom event listener. Normally this will not be necessary, but +you have the power! Here is how `onClick` is defined for example: + + import Json.Decode as Json + + onClick : msg -> Attribute msg + onClick message = + on "click" (Json.succeed message) + +The first argument is the event name in the same format as with JavaScript's +[`addEventListener`][aEL] function. + +The second argument is a JSON decoder. Read more about these [here][decoder]. +When an event occurs, the decoder tries to turn the event object into an Elm +value. If successful, the value is routed to your `update` function. In the +case of `onClick` we always just succeed with the given `message`. + +If this is confusing, work through the [Elm Architecture Tutorial][tutorial]. +It really does help! + +[aEL]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener +[decoder]: http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode +[tutorial]: https://github.com/evancz/elm-architecture-tutorial/ +-} +on : String -> Json.Decoder msg -> Attribute msg +on = + VirtualDom.on + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Attribute msg +onWithOptions = + VirtualDom.onWithOptions + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + VirtualDom.defaultOptions + + + +-- COMMON DECODERS + + +{-| A `Json.Decoder` for grabbing `event.target.value`. We use this to define +`onInput` as follows: + + import Json.Decode as Json + + onInput : (String -> msg) -> Attribute msg + onInput tagger = + on "input" (Json.map tagger targetValue) + +You probably will never need this, but hopefully it gives some insights into +how to make custom event handlers. +-} +targetValue : Json.Decoder String +targetValue = + Json.at ["target", "value"] Json.string + + +{-| A `Json.Decoder` for grabbing `event.target.checked`. We use this to define +`onCheck` as follows: + + import Json.Decode as Json + + onCheck : (Bool -> msg) -> Attribute msg + onCheck tagger = + on "input" (Json.map tagger targetChecked) +-} +targetChecked : Json.Decoder Bool +targetChecked = + Json.at ["target", "checked"] Json.bool + + +{-| A `Json.Decoder` for grabbing `event.keyCode`. This helps you define +keyboard listeners like this: + + import Json.Decode as Json + + onKeyUp : (Int -> msg) -> Attribute msg + onKeyUp tagger = + on "keyup" (Json.map tagger keyCode) + +**Note:** It looks like the spec is moving away from `event.keyCode` and +towards `event.key`. Once this is supported in more browsers, we may add +helpers here for `onKeyUp`, `onKeyDown`, `onKeyPress`, etc. +-} +keyCode : Json.Decoder Int +keyCode = + Json.field "keyCode" Json.int diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm new file mode 100644 index 0000000..debd710 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Keyed.elm @@ -0,0 +1,48 @@ +module Html.Keyed exposing + ( node + , ol + , ul + ) +{-| A keyed node helps optimize cases where children are getting added, moved, +removed, etc. Common examples include: + + - The user can delete items from a list. + - The user can create new items in a list. + - You can sort a list based on name or date or whatever. + +When you use a keyed node, every child is paired with a string identifier. This +makes it possible for the underlying diffing algorithm to reuse nodes more +efficiently. + +# Keyed Nodes +@docs node + +# Commonly Keyed Nodes +@docs ol, ul +-} + + +import Html exposing (Attribute, Html) +import VirtualDom + + +{-| Works just like `Html.node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +node : String -> List (Attribute msg) -> List ( String, Html msg ) -> Html msg +node = + VirtualDom.keyedNode + + +{-|-} +ol : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ol = + node "ol" + + +{-|-} +ul : List (Attribute msg) -> List ( String, Html msg ) -> Html msg +ul = + node "ul" diff --git a/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm new file mode 100644 index 0000000..f027ffc --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/html/2.0.0/src/Html/Lazy.elm @@ -0,0 +1,48 @@ +module Html.Lazy exposing + ( lazy, lazy2, lazy3 + ) + +{-| Since all Elm functions are pure we have a guarantee that the same input +will always result in the same output. This module gives us tools to be lazy +about building `Html` that utilize this fact. + +Rather than immediately applying functions to their arguments, the `lazy` +functions just bundle the function and arguments up for later. When diffing +the old and new virtual DOM, it checks to see if all the arguments are equal. +If so, it skips calling the function! + +This is a really cheap test and often makes things a lot faster, but definitely +benchmark to be sure! + +@docs lazy, lazy2, lazy3 +-} + +import Html exposing (Html) +import VirtualDom + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Html msg) -> a -> Html msg +lazy = + VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Html msg) -> a -> b -> Html msg +lazy2 = + VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg +lazy3 = + VirtualDom.lazy3 diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore b/part10/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore new file mode 100644 index 0000000..e185314 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/.gitignore @@ -0,0 +1 @@ +elm-stuff \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE b/part10/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE new file mode 100644 index 0000000..737f64b --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/README.md b/part10/elm-stuff/packages/elm-lang/http/1.0.0/README.md new file mode 100644 index 0000000..a042adb --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/README.md @@ -0,0 +1,57 @@ +# HTTP in Elm + +Make HTTP requests in Elm. + +```elm +import Http +import Json.Decode as Decode + + +-- GET A STRING + +getWarAndPeace : Http.Request String +getWarAndPeace = + Http.getString "https://example.com/books/war-and-peace" + + +-- GET JSON + +getMetadata : Http.Request Metadata +getMetadata = + Http.get "https://example.com/books/war-and-peace/metadata" decodeMetadata + +type alias Metadata = + { author : String + , pages : Int + } + +decodeMetadata : Decode.Decoder Metadata +decodeMetadata = + Decode.map2 Metadata + (Decode.field "author" Decode.string) + (Decode.field "pages" Decode.int) + + +-- SEND REQUESTS + +type Msg + = LoadMetadata (Result Http.Error Metadata) + +send : Cmd Msg +send = + Http.send LoadMetadata getMetadata +``` + + +## Examples + + - GET requests - [demo and code](http://elm-lang.org/examples/http) + - Download progress - [demo](https://hirafuji.com.br/elm/http-progress-example/) and [code](https://gist.github.com/pablohirafuji/fa373d07c42016756d5bca28962008c4) + + +## Learn More + +To understand how HTTP works in Elm, check out: + + - [The HTTP example in the guide](https://guide.elm-lang.org/architecture/effects/http.html) to see a simple usage with some explanation. + - [The Elm Architecture](https://guide.elm-lang.org/architecture/) to understand how HTTP fits into Elm in a more complete way. This will explain concepts like `Cmd` and `Sub` that appear in this package. diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json b/part10/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json new file mode 100644 index 0000000..7c6b4ae --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "Make HTTP requests (download progress, rate-limit, debounce, throttle)", + "repository": "https://github.com/elm-lang/http.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Http", + "Http.Progress" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/rate-limit.md b/part10/elm-stuff/packages/elm-lang/http/1.0.0/rate-limit.md new file mode 100644 index 0000000..ebe049a --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/rate-limit.md @@ -0,0 +1,40 @@ +## Custom Rate-Limiting Strategies + +This package has `Http.RateLimit` which helps you rate-limit the HTTP requests you make. Instead of sending one request per keystroke, you filter it down because not all requests are important. + +The `Http.RateLimit` module comes with a `debounce` strategy that covers the common case, but you may want to define a custom strategy with other characteristics. Maybe you want to send the first request. Maybe you want to send when the previous request is done instead of using timers. Etc. + +If so, you can define a custom strategy with `Http.RateLimit.customStrategy`. For example, you would define `throttle` like this: + +```elm +import Http.RateLimit as Limit + +throttle : Time -> Limit.Strategy +throttle ms = + Limit.customStrategy <| \timeNow event state -> + case event of + Limit.New _ -> + -- wait after a new request + [ Limit.WakeUpIn ms ] + + Limit.Done _ -> + -- we do not care when requests finish + [] + + Limit.WakeUp -> + case state.next of + Nothing -> + -- do nothing if there is no pending request + [] + + Just req -> + -- send if enough time has passed since the previous request + case state.prev of + Nothing -> + [ Limit.Send req.id ] + + Just prev -> + if timeNow - prev.time >= ms then [ Limit.Send req.id ] else [] +``` + +It would be nice to have some useful strategies defined in a separate package so folks can experiment and find names and implementations that work well for specific scenarios. \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm new file mode 100644 index 0000000..d3ccf27 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http.elm @@ -0,0 +1,411 @@ +module Http exposing + ( Request, send, Error(..) + , getString, get + , post + , request + , Header, header + , Body, emptyBody, jsonBody, stringBody, multipartBody, Part, stringPart + , Expect, expectString, expectJson, expectStringResponse, Response + , encodeUri, decodeUri, toTask + ) + +{-| Create and send HTTP requests. + +# Send Requests +@docs Request, send, Error + +# GET +@docs getString, get + +# POST +@docs post + +# Custom Requests +@docs request + +## Headers +@docs Header, header + +## Request Bodies +@docs Body, emptyBody, jsonBody, stringBody, multipartBody, Part, stringPart + +## Responses +@docs Expect, expectString, expectJson, expectStringResponse, Response + +# Low-Level +@docs encodeUri, decodeUri, toTask + +-} + +import Dict exposing (Dict) +import Http.Internal +import Json.Decode as Decode +import Json.Encode as Encode +import Maybe exposing (Maybe(..)) +import Native.Http +import Platform.Cmd as Cmd exposing (Cmd) +import Result exposing (Result(..)) +import Task exposing (Task) +import Time exposing (Time) + + + +-- REQUESTS + + +{-| Describes an HTTP request. +-} +type alias Request a = + Http.Internal.Request a + + +{-| Send a `Request`. We could get the text of “War and Peace” like this: + + import Http + + type Msg = Click | NewBook (Result Http.Error String) + + update : Msg -> Model -> Model + update msg model = + case msg of + Click -> + ( model, getWarAndPeace ) + + NewBook (Ok book) -> + ... + + NewBook (Err _) -> + ... + + getWarAndPeace : Cmd Msg + getWarAndPeace = + Http.send NewBook <| + Http.getString "https://example.com/books/war-and-peace.md" +-} +send : (Result Error a -> msg) -> Request a -> Cmd msg +send resultToMessage request = + Task.attempt resultToMessage (toTask request) + + +{-| Convert a `Request` into a `Task`. This is only really useful if you want +to chain together a bunch of requests (or any other tasks) in a single command. +-} +toTask : Request a -> Task Error a +toTask (Http.Internal.Request request) = + Native.Http.toTask request Nothing + + +{-| A `Request` can fail in a couple ways: + + - `BadUrl` means you did not provide a valid URL. + - `Timeout` means it took too long to get a response. + - `NetworkError` means the user turned off their wifi, went in a cave, etc. + - `BadStatus` means you got a response back, but the [status code][sc] + indicates failure. + - `BadPayload` means you got a response back with a nice status code, but + the body of the response was something unexpected. The `String` in this + case is a debugging message that explains what went wrong with your JSON + decoder or whatever. + +[sc]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +-} +type Error + = BadUrl String + | Timeout + | NetworkError + | BadStatus (Response String) + | BadPayload String (Response String) + + + +-- GET + + +{-| Create a `GET` request and interpret the response body as a `String`. + + import Http + + getWarAndPeace : Http.Request String + getWarAndPeace = + Http.getString "https://example.com/books/war-and-peace" +-} +getString : String -> Request String +getString url = + request + { method = "GET" + , headers = [] + , url = url + , body = emptyBody + , expect = expectString + , timeout = Nothing + , withCredentials = False + } + + +{-| Create a `GET` request and try to decode the response body from JSON to +some Elm value. + + import Http + import Json.Decode exposing (list, string) + + getBooks : Http.Request (List String) + getBooks = + Http.get "https://example.com/books" (list string) + +You can learn more about how JSON decoders work [here][] in the guide. + +[here]: https://guide.elm-lang.org/interop/json.html +-} +get : String -> Decode.Decoder a -> Request a +get url decoder = + request + { method = "GET" + , headers = [] + , url = url + , body = emptyBody + , expect = expectJson decoder + , timeout = Nothing + , withCredentials = False + } + + + +-- POST + + +{-| Create a `POST` request and try to decode the response body from JSON to +an Elm value. For example, if we want to send a POST without any data in the +request body, it would be like this: + + import Http + import Json.Decode exposing (list, string) + + postBooks : Http.Request (List String) + postBooks = + Http.post "https://example.com/books" Http.emptyBody (list string) + +See [`jsonBody`](#jsonBody) to learn how to have a more interesting request +body. And check out [this section][here] of the guide to learn more about +JSON decoders. + +[here]: https://guide.elm-lang.org/interop/json.html + +-} +post : String -> Body -> Decode.Decoder a -> Request a +post url body decoder = + request + { method = "POST" + , headers = [] + , url = url + , body = body + , expect = expectJson decoder + , timeout = Nothing + , withCredentials = False + } + + + +-- CUSTOM REQUESTS + + +{-| Create a custom request. For example, a custom PUT request would look like +this: + + put : String -> Body -> Request () + put url body = + request + { method = "PUT" + , headers = [] + , url = url + , body = body + , expect = expectStringResponse (\_ -> Ok ()) + , timeout = Nothing + , withCredentials = False + } +-} +request + : { method : String + , headers : List Header + , url : String + , body : Body + , expect : Expect a + , timeout : Maybe Time + , withCredentials : Bool + } + -> Request a +request = + Http.Internal.Request + + + +-- HEADERS + + +{-| An HTTP header for configuring requests. See a bunch of common headers +[here][]. + +[here]: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields +-} +type alias Header = Http.Internal.Header + + +{-| Create a `Header`. + + header "If-Modified-Since" "Sat 29 Oct 1994 19:43:31 GMT" + header "Max-Forwards" "10" + header "X-Requested-With" "XMLHttpRequest" + +**Note:** In the future, we may split this out into an `Http.Headers` module +and provide helpers for cases that are common on the client-side. If this +sounds nice to you, open an issue [here][] describing the helper you want and +why you need it. + +[here]: https://github.com/elm-lang/http/issues +-} +header : String -> String -> Header +header = + Http.Internal.Header + + + +-- BODY + + +{-| Represents the body of a `Request`. +-} +type alias Body = Http.Internal.Body + + +{-| Create an empty body for your `Request`. This is useful for GET requests +and POST requests where you are not sending any data. +-} +emptyBody : Body +emptyBody = + Http.Internal.EmptyBody + + +{-| Put some JSON value in the body of your `Request`. This will automatically +add the `Content-Type: application/json` header. +-} +jsonBody : Encode.Value -> Body +jsonBody value = + Http.Internal.StringBody "application/json" (Encode.encode 0 value) + + +{-| Put some string in the body of your `Request`. Defining `jsonBody` looks +like this: + + import Json.Encode as Encode + + jsonBody : Encode.Value -> Body + jsonBody value = + stringBody "application/json" (Encode.encode 0 value) + +Notice that the first argument is a [MIME type][mime] so we know to add +`Content-Type: application/json` to our request headers. Make sure your +MIME type matches your data. Some servers are strict about this! + +[mime]: https://en.wikipedia.org/wiki/Media_type +-} +stringBody : String -> String -> Body +stringBody = + Http.Internal.StringBody + + +{-| Create multi-part bodies for your `Request`, automatically adding the +`Content-Type: multipart/form-data` header. +-} +multipartBody : List Part -> Body +multipartBody = + Native.Http.multipart + + +{-| Contents of a multi-part body. Right now it only supports strings, but we +will support blobs and files when we get an API for them in Elm. +-} +type Part + = StringPart String String + + +{-| A named chunk of string data. + + body = + multipartBody + [ stringPart "user" "tom" + , stringPart "payload" "42" + ] +-} +stringPart : String -> String -> Part +stringPart = + StringPart + + + +-- RESPONSES + + +{-| Logic for interpreting a response body. +-} +type alias Expect a = + Http.Internal.Expect a + + +{-| Expect the response body to be a `String`. +-} +expectString : Expect String +expectString = + expectStringResponse (\response -> Ok response.body) + + +{-| Expect the response body to be JSON. You provide a `Decoder` to turn that +JSON into an Elm value. If the body cannot be parsed as JSON or if the JSON +does not match the decoder, the request will resolve to a `BadPayload` error. +-} +expectJson : Decode.Decoder a -> Expect a +expectJson decoder = + expectStringResponse (\response -> Decode.decodeString decoder response.body) + + +{-| Maybe you want the whole `Response`: status code, headers, body, etc. This +lets you get all of that information. From there you can use functions like +`Json.Decode.decodeString` to interpret it as JSON or whatever else you want. +-} +expectStringResponse : (Response String -> Result String a) -> Expect a +expectStringResponse = + Native.Http.expectStringResponse + + +{-| The response from a `Request`. +-} +type alias Response body = + { url : String + , status : { code : Int, message : String } + , headers : Dict String String + , body : body + } + + + +-- LOW-LEVEL + + +{-| Use this to escape query parameters. Converts characters like `/` to `%2F` +so that it does not clash with normal URL + +It work just like `encodeURIComponent` in JavaScript. +-} +encodeUri : String -> String +encodeUri = + Native.Http.encodeUri + + +{-| Use this to unescape query parameters. It converts things like `%2F` to +`/`. It can fail in some cases. For example, there is no way to unescape `%` +because it could never appear alone in a properly escaped string. + +It works just like `decodeURIComponent` in JavaScript. +-} +decodeUri : String -> Maybe String +decodeUri = + Native.Http.decodeUri + diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm new file mode 100644 index 0000000..b547302 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Internal.elm @@ -0,0 +1,45 @@ +module Http.Internal exposing + ( Request(..) + , RawRequest + , Expect + , Body(..) + , Header(..) + , map + ) + + +import Native.Http +import Time exposing (Time) + + + +type Request a = Request (RawRequest a) + + +type alias RawRequest a = + { method : String + , headers : List Header + , url : String + , body : Body + , expect : Expect a + , timeout : Maybe Time + , withCredentials : Bool + } + + +type Expect a = Expect + + +type Body + = EmptyBody + | StringBody String String + | FormDataBody + + + +type Header = Header String String + + +map : (a -> b) -> RawRequest a -> RawRequest b +map func request = + { request | expect = Native.Http.mapExpect func request.expect } diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm new file mode 100644 index 0000000..c0b2a78 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Http/Progress.elm @@ -0,0 +1,200 @@ +effect module Http.Progress where { subscription = MySub } exposing + ( Progress(..) + , track + ) + +{-| Track the progress of an HTTP request. This can be useful if you are +requesting a large amount of data and want to show the user a progress bar +or something. + +Here is an example usage: [demo][] and [code][]. + +[demo]: https://hirafuji.com.br/elm/http-progress-example/ +[code]: https://gist.github.com/pablohirafuji/fa373d07c42016756d5bca28962008c4 + +**Note:** If you stop tracking progress, you cancel the request. + +# Progress +@docs Progress, track + +-} + + +import Dict +import Http +import Http.Internal exposing ( Request(Request) ) +import Task exposing (Task) +import Platform exposing (Router) +import Process + + + +-- PROGRESS + + +{-| The progress of an HTTP request. + +You start with `None`. As data starts to come in, you will see `Some`. The +`bytesExpected` field will match the `Content-Length` header, indicating how +long the response body is in bytes (8-bits). The `bytes` field indicates how +many bytes have been loaded so far, so if you want progress as a percentage, +you would say: + + Some { bytes, bytesExpected } -> + toFloat bytes / toFloat bytesExpected + +You will end up with `Fail` or `Done` depending on the success of the request. +-} +type Progress data + = None + | Some { bytes : Int, bytesExpected : Int} + | Fail Http.Error + | Done data + + + +-- TRACK + + +{-| Create a subscription that tracks the progress of an HTTP request. + +See it in action in this example: [demo][] and [code][]. + +[demo]: https://hirafuji.com.br/elm/http-progress-example/ +[code]: https://gist.github.com/pablohirafuji/fa373d07c42016756d5bca28962008c4 +-} +track : String -> (Progress data -> msg) -> Http.Request data -> Sub msg +track id toMessage (Request request) = + subscription <| Track id <| + { request = Http.Internal.map (Done >> toMessage) request + , toProgress = Some >> toMessage + , toError = Fail >> toMessage + } + + +type alias TrackedRequest msg = + { request : Http.Internal.RawRequest msg + , toProgress : { bytes : Int, bytesExpected : Int } -> msg + , toError : Http.Error -> msg + } + + +map : (a -> b) -> TrackedRequest a -> TrackedRequest b +map func { request, toProgress, toError } = + { request = Http.Internal.map func request + , toProgress = toProgress >> func + , toError = toError >> func + } + + + +-- SUBSCRIPTIONS + + +type MySub msg = + Track String (TrackedRequest msg) + + +subMap : (a -> b) -> MySub a -> MySub b +subMap func (Track id trackedRequest) = + Track id (map func trackedRequest) + + + +-- EFFECT MANAGER + + +type alias State = + Dict.Dict String Process.Id + + +init : Task Never State +init = + Task.succeed Dict.empty + + + +-- APP MESSAGES + + +onEffects : Platform.Router msg Never -> List (MySub msg) -> State -> Task Never State +onEffects router subs state = + let + subDict = + collectSubs subs + + leftStep id process (dead, ongoing, new) = + ( Process.kill process :: dead + , ongoing + , new + ) + + bothStep id process _ (dead, ongoing, new) = + ( dead + , Dict.insert id process ongoing + , new + ) + + rightStep id trackedRequest (dead, ongoing, new) = + ( dead + , ongoing + , (id, trackedRequest) :: new + ) + + (dead, ongoing, new) = + Dict.merge leftStep bothStep rightStep state subDict ([], Dict.empty, []) + in + Task.sequence dead + |> Task.andThen (\_ -> spawnRequests router new ongoing) + + +spawnRequests : Router msg Never -> List (String, TrackedRequest msg) -> State -> Task Never State +spawnRequests router trackedRequests state = + case trackedRequests of + [] -> + Task.succeed state + + (id, trackedRequest) :: others -> + Process.spawn (toTask router trackedRequest) + |> Task.andThen (\process -> spawnRequests router others (Dict.insert id process state)) + + +toTask : Router msg Never -> TrackedRequest msg -> Task Never () +toTask router { request, toProgress, toError } = + Native.Http.toTask request (Just (Platform.sendToApp router << toProgress)) + |> Task.andThen (Platform.sendToApp router) + |> Task.onError (Platform.sendToApp router << toError) + + + +-- COLLECT SUBS AS DICT + + +type alias SubDict msg = + Dict.Dict String (TrackedRequest msg) + + +collectSubs : List (MySub msg) -> SubDict msg +collectSubs subs = + List.foldl addSub Dict.empty subs + + +addSub : MySub msg -> SubDict msg -> SubDict msg +addSub (Track id trackedRequest) subDict = + let + request = + trackedRequest.request + + uid = + id ++ request.method ++ request.url + in + Dict.insert uid trackedRequest subDict + + + +-- SELF MESSAGES + + +onSelfMsg : Platform.Router msg Never -> Never -> State -> Task Never State +onSelfMsg router _ state = + Task.succeed state diff --git a/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js new file mode 100644 index 0000000..9f14772 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/http/1.0.0/src/Native/Http.js @@ -0,0 +1,238 @@ +var _elm_lang$http$Native_Http = function() { + + +// ENCODING AND DECODING + +function encodeUri(string) +{ + return encodeURIComponent(string); +} + +function decodeUri(string) +{ + try + { + return _elm_lang$core$Maybe$Just(decodeURIComponent(string)); + } + catch(e) + { + return _elm_lang$core$Maybe$Nothing; + } +} + + +// SEND REQUEST + +function toTask(request, maybeProgress) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var xhr = new XMLHttpRequest(); + + configureProgress(xhr, maybeProgress); + + xhr.addEventListener('error', function() { + callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'NetworkError' })); + }); + xhr.addEventListener('timeout', function() { + callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'Timeout' })); + }); + xhr.addEventListener('load', function() { + callback(handleResponse(xhr, request.expect.responseToResult)); + }); + + try + { + xhr.open(request.method, request.url, true); + } + catch (e) + { + return callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'BadUrl', _0: request.url })); + } + + configureRequest(xhr, request); + send(xhr, request.body); + + return function() { xhr.abort(); }; + }); +} + +function configureProgress(xhr, maybeProgress) +{ + if (maybeProgress.ctor === 'Nothing') + { + return; + } + + xhr.addEventListener('progress', function(event) { + if (!event.lengthComputable) + { + return; + } + _elm_lang$core$Native_Scheduler.rawSpawn(maybeProgress._0({ + bytes: event.loaded, + bytesExpected: event.total + })); + }); +} + +function configureRequest(xhr, request) +{ + function setHeader(pair) + { + xhr.setRequestHeader(pair._0, pair._1); + } + + A2(_elm_lang$core$List$map, setHeader, request.headers); + xhr.responseType = request.expect.responseType; + xhr.withCredentials = request.withCredentials; + + if (request.timeout.ctor === 'Just') + { + xhr.timeout = request.timeout._0; + } +} + +function send(xhr, body) +{ + switch (body.ctor) + { + case 'EmptyBody': + xhr.send(); + return; + + case 'StringBody': + xhr.setRequestHeader('Content-Type', body._0); + xhr.send(body._1); + return; + + case 'FormDataBody': + xhr.send(body._0); + return; + } +} + + +// RESPONSES + +function handleResponse(xhr, responseToResult) +{ + var response = toResponse(xhr); + + if (xhr.status < 200 || 300 <= xhr.status) + { + response.body = xhr.responseText; + return _elm_lang$core$Native_Scheduler.fail({ + ctor: 'BadStatus', + _0: response + }); + } + + var result = responseToResult(response); + + if (result.ctor === 'Ok') + { + return _elm_lang$core$Native_Scheduler.succeed(result._0); + } + else + { + response.body = xhr.responseText; + return _elm_lang$core$Native_Scheduler.fail({ + ctor: 'BadPayload', + _0: result._0, + _1: response + }); + } +} + +function toResponse(xhr) +{ + return { + status: { code: xhr.status, message: xhr.statusText }, + headers: parseHeaders(xhr.getAllResponseHeaders()), + url: xhr.responseURL, + body: xhr.response + }; +} + +function parseHeaders(rawHeaders) +{ + var headers = _elm_lang$core$Dict$empty; + + if (!rawHeaders) + { + return headers; + } + + var headerPairs = rawHeaders.split('\u000d\u000a'); + for (var i = headerPairs.length; i--; ) + { + var headerPair = headerPairs[i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) + { + var key = headerPair.substring(0, index); + var value = headerPair.substring(index + 2); + + headers = A3(_elm_lang$core$Dict$update, key, function(oldValue) { + if (oldValue.ctor === 'Just') + { + return _elm_lang$core$Maybe$Just(value + ', ' + oldValue._0); + } + return _elm_lang$core$Maybe$Just(value); + }, headers); + } + } + + return headers; +} + + +// EXPECTORS + +function expectStringResponse(responseToResult) +{ + return { + responseType: 'text', + responseToResult: responseToResult + }; +} + +function mapExpect(func, expect) +{ + return { + responseType: expect.responseType, + responseToResult: function(response) { + var convertedResponse = expect.responseToResult(response); + return A2(_elm_lang$core$Result$map, func, convertedResponse); + } + }; +} + + +// BODY + +function multipart(parts) +{ + var formData = new FormData(); + + while (parts.ctor !== '[]') + { + var part = parts._0; + formData.append(part._0, part._1); + parts = parts._1; + } + + return { ctor: 'FormDataBody', _0: formData }; +} + +return { + toTask: F2(toTask), + expectStringResponse: expectStringResponse, + mapExpect: F2(mapExpect), + multipart: multipart, + encodeUri: encodeUri, + decodeUri: decodeUri +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore new file mode 100644 index 0000000..f6a4e83 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.gitignore @@ -0,0 +1,3 @@ +node_modules +elm-stuff +tests/build diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.travis.yml b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.travis.yml new file mode 100644 index 0000000..d16a59a --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/.travis.yml @@ -0,0 +1,8 @@ +sudo: false +language: none +install: + - npm install --global elm@0.16.0 + - npm install + +script: + - ./tests/run-tests.sh \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE new file mode 100644 index 0000000..0edfd04 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016-present, Evan Czaplicki + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Evan Czaplicki nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/README.md b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/README.md new file mode 100644 index 0000000..0ff727c --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/README.md @@ -0,0 +1,5 @@ +# Virtual DOM for Elm + +A virtual DOM implementation that backs Elm's core libraries for [HTML](http://package.elm-lang.org/packages/elm-lang/html/latest/) and [SVG](http://package.elm-lang.org/packages/elm-lang/svg/latest/). You should almost certainly use those higher-level libraries directly. + +It is pretty fast! You can read about that [here](http://elm-lang.org/blog/blazing-fast-html-round-two). diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json new file mode 100644 index 0000000..353986f --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.4", + "summary": "Core virtual DOM implementation, basis for HTML and SVG libraries", + "repository": "https://github.com/elm-lang/virtual-dom.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "VirtualDom" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js new file mode 100644 index 0000000..729f171 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/Debug.js @@ -0,0 +1,280 @@ +var _elm_lang$virtual_dom$Native_Debug = function() { + + +// IMPORT / EXPORT + +function unsafeCoerce(value) +{ + return value; +} + +var upload = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) +{ + var element = document.createElement('input'); + element.setAttribute('type', 'file'); + element.setAttribute('accept', 'text/json'); + element.style.display = 'none'; + element.addEventListener('change', function(event) + { + var fileReader = new FileReader(); + fileReader.onload = function(e) + { + callback(_elm_lang$core$Native_Scheduler.succeed(e.target.result)); + }; + fileReader.readAsText(event.target.files[0]); + document.body.removeChild(element); + }); + document.body.appendChild(element); + element.click(); +}); + +function download(historyLength, json) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var fileName = 'history-' + historyLength + '.txt'; + var jsonString = JSON.stringify(json); + var mime = 'text/plain;charset=utf-8'; + var done = _elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0); + + // for IE10+ + if (navigator.msSaveBlob) + { + navigator.msSaveBlob(new Blob([jsonString], {type: mime}), fileName); + return callback(done); + } + + // for HTML5 + var element = document.createElement('a'); + element.setAttribute('href', 'data:' + mime + ',' + encodeURIComponent(jsonString)); + element.setAttribute('download', fileName); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + callback(done); + }); +} + + +// POPOUT + +function messageToString(value) +{ + switch (typeof value) + { + case 'boolean': + return value ? 'True' : 'False'; + case 'number': + return value + ''; + case 'string': + return '"' + addSlashes(value, false) + '"'; + } + if (value instanceof String) + { + return '\'' + addSlashes(value, true) + '\''; + } + if (typeof value !== 'object' || value === null || !('ctor' in value)) + { + return '…'; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Tupl' || ctorStarter === '_Task') + { + return '…' + } + if (['_Array', '', '_Process', '::', '[]', 'Set_elm_builtin', 'RBNode_elm_builtin', 'RBEmpty_elm_builtin'].indexOf(value.ctor) >= 0) + { + return '…'; + } + + var keys = Object.keys(value); + switch (keys.length) + { + case 1: + return value.ctor; + case 2: + return value.ctor + ' ' + messageToString(value._0); + default: + return value.ctor + ' … ' + messageToString(value[keys[keys.length - 1]]); + } +} + + +function primitive(str) +{ + return { ctor: 'Primitive', _0: str }; +} + + +function init(value) +{ + var type = typeof value; + + if (type === 'boolean') + { + return { + ctor: 'Constructor', + _0: _elm_lang$core$Maybe$Just(value ? 'True' : 'False'), + _1: true, + _2: _elm_lang$core$Native_List.Nil + }; + } + + if (type === 'number') + { + return primitive(value + ''); + } + + if (type === 'string') + { + return { ctor: 'S', _0: '"' + addSlashes(value, false) + '"' }; + } + + if (value instanceof String) + { + return { ctor: 'S', _0: "'" + addSlashes(value, true) + "'" }; + } + + if (value instanceof Date) + { + return primitive('<' + value.toString() + '>'); + } + + if (value === null) + { + return primitive('XXX'); + } + + if (type === 'object' && 'ctor' in value) + { + var ctor = value.ctor; + + if (ctor === '::' || ctor === '[]') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ListSeq'}, + _1: true, + _2: A2(_elm_lang$core$List$map, init, value) + }; + } + + if (ctor === 'Set_elm_builtin') + { + return { + ctor: 'Sequence', + _0: {ctor: 'SetSeq'}, + _1: true, + _2: A3(_elm_lang$core$Set$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === 'RBNode_elm_builtin' || ctor == 'RBEmpty_elm_builtin') + { + return { + ctor: 'Dictionary', + _0: true, + _1: A3(_elm_lang$core$Dict$foldr, initKeyValueCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + if (ctor === '_Array') + { + return { + ctor: 'Sequence', + _0: {ctor: 'ArraySeq'}, + _1: true, + _2: A3(_elm_lang$core$Array$foldr, initCons, _elm_lang$core$Native_List.Nil, value) + }; + } + + var ctorStarter = value.ctor.substring(0, 5); + if (ctorStarter === '_Task') + { + return primitive(''); + } + + if (ctor === '') + { + return primitive(ctor); + } + + if (ctor === '_Process') + { + return primitive(''); + } + + var list = _elm_lang$core$Native_List.Nil; + for (var i in value) + { + if (i === 'ctor') continue; + list = _elm_lang$core$Native_List.Cons(init(value[i]), list); + } + return { + ctor: 'Constructor', + _0: ctorStarter === '_Tupl' ? _elm_lang$core$Maybe$Nothing : _elm_lang$core$Maybe$Just(ctor), + _1: true, + _2: _elm_lang$core$List$reverse(list) + }; + } + + if (type === 'object') + { + var dict = _elm_lang$core$Dict$empty; + for (var i in value) + { + dict = A3(_elm_lang$core$Dict$insert, i, init(value[i]), dict); + } + return { ctor: 'Record', _0: true, _1: dict }; + } + + return primitive('XXX'); +} + +var initCons = F2(initConsHelp); + +function initConsHelp(value, list) +{ + return _elm_lang$core$Native_List.Cons(init(value), list); +} + +var initKeyValueCons = F3(initKeyValueConsHelp); + +function initKeyValueConsHelp(key, value, list) +{ + return _elm_lang$core$Native_List.Cons( + _elm_lang$core$Native_Utils.Tuple2(init(key), init(value)), + list + ); +} + +function addSlashes(str, isChar) +{ + var s = str.replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + + +return { + upload: upload, + download: F2(download), + unsafeCoerce: unsafeCoerce, + messageToString: messageToString, + init: init +} + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js new file mode 100644 index 0000000..98d4750 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/Native/VirtualDom.js @@ -0,0 +1,1881 @@ +var _elm_lang$virtual_dom$VirtualDom_Debug$wrap; +var _elm_lang$virtual_dom$VirtualDom_Debug$wrapWithFlags; + +var _elm_lang$virtual_dom$Native_VirtualDom = function() { + +var STYLE_KEY = 'STYLE'; +var EVENT_KEY = 'EVENT'; +var ATTR_KEY = 'ATTR'; +var ATTR_NS_KEY = 'ATTR_NS'; + +var localDoc = typeof document !== 'undefined' ? document : {}; + + +//////////// VIRTUAL DOM NODES //////////// + + +function text(string) +{ + return { + type: 'text', + text: string + }; +} + + +function node(tag) +{ + return F2(function(factList, kidList) { + return nodeHelp(tag, factList, kidList); + }); +} + + +function nodeHelp(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function keyedNode(tag, factList, kidList) +{ + var organized = organizeFacts(factList); + var namespace = organized.namespace; + var facts = organized.facts; + + var children = []; + var descendantsCount = 0; + while (kidList.ctor !== '[]') + { + var kid = kidList._0; + descendantsCount += (kid._1.descendantsCount || 0); + children.push(kid); + kidList = kidList._1; + } + descendantsCount += children.length; + + return { + type: 'keyed-node', + tag: tag, + facts: facts, + children: children, + namespace: namespace, + descendantsCount: descendantsCount + }; +} + + +function custom(factList, model, impl) +{ + var facts = organizeFacts(factList).facts; + + return { + type: 'custom', + facts: facts, + model: model, + impl: impl + }; +} + + +function map(tagger, node) +{ + return { + type: 'tagger', + tagger: tagger, + node: node, + descendantsCount: 1 + (node.descendantsCount || 0) + }; +} + + +function thunk(func, args, thunk) +{ + return { + type: 'thunk', + func: func, + args: args, + thunk: thunk, + node: undefined + }; +} + +function lazy(fn, a) +{ + return thunk(fn, [a], function() { + return fn(a); + }); +} + +function lazy2(fn, a, b) +{ + return thunk(fn, [a,b], function() { + return A2(fn, a, b); + }); +} + +function lazy3(fn, a, b, c) +{ + return thunk(fn, [a,b,c], function() { + return A3(fn, a, b, c); + }); +} + + + +// FACTS + + +function organizeFacts(factList) +{ + var namespace, facts = {}; + + while (factList.ctor !== '[]') + { + var entry = factList._0; + var key = entry.key; + + if (key === ATTR_KEY || key === ATTR_NS_KEY || key === EVENT_KEY) + { + var subFacts = facts[key] || {}; + subFacts[entry.realKey] = entry.value; + facts[key] = subFacts; + } + else if (key === STYLE_KEY) + { + var styles = facts[key] || {}; + var styleList = entry.value; + while (styleList.ctor !== '[]') + { + var style = styleList._0; + styles[style._0] = style._1; + styleList = styleList._1; + } + facts[key] = styles; + } + else if (key === 'namespace') + { + namespace = entry.value; + } + else if (key === 'className') + { + var classes = facts[key]; + facts[key] = typeof classes === 'undefined' + ? entry.value + : classes + ' ' + entry.value; + } + else + { + facts[key] = entry.value; + } + factList = factList._1; + } + + return { + facts: facts, + namespace: namespace + }; +} + + + +//////////// PROPERTIES AND ATTRIBUTES //////////// + + +function style(value) +{ + return { + key: STYLE_KEY, + value: value + }; +} + + +function property(key, value) +{ + return { + key: key, + value: value + }; +} + + +function attribute(key, value) +{ + return { + key: ATTR_KEY, + realKey: key, + value: value + }; +} + + +function attributeNS(namespace, key, value) +{ + return { + key: ATTR_NS_KEY, + realKey: key, + value: { + value: value, + namespace: namespace + } + }; +} + + +function on(name, options, decoder) +{ + return { + key: EVENT_KEY, + realKey: name, + value: { + options: options, + decoder: decoder + } + }; +} + + +function equalEvents(a, b) +{ + if (a.options !== b.options) + { + if (a.options.stopPropagation !== b.options.stopPropagation || a.options.preventDefault !== b.options.preventDefault) + { + return false; + } + } + return _elm_lang$core$Native_Json.equality(a.decoder, b.decoder); +} + + +function mapProperty(func, property) +{ + if (property.key !== EVENT_KEY) + { + return property; + } + return on( + property.realKey, + property.value.options, + A2(_elm_lang$core$Json_Decode$map, func, property.value.decoder) + ); +} + + +//////////// RENDER //////////// + + +function render(vNode, eventNode) +{ + switch (vNode.type) + { + case 'thunk': + if (!vNode.node) + { + vNode.node = vNode.thunk(); + } + return render(vNode.node, eventNode); + + case 'tagger': + var subNode = vNode.node; + var tagger = vNode.tagger; + + while (subNode.type === 'tagger') + { + typeof tagger !== 'object' + ? tagger = [tagger, subNode.tagger] + : tagger.push(subNode.tagger); + + subNode = subNode.node; + } + + var subEventRoot = { tagger: tagger, parent: eventNode }; + var domNode = render(subNode, subEventRoot); + domNode.elm_event_node_ref = subEventRoot; + return domNode; + + case 'text': + return localDoc.createTextNode(vNode.text); + + case 'node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i], eventNode)); + } + + return domNode; + + case 'keyed-node': + var domNode = vNode.namespace + ? localDoc.createElementNS(vNode.namespace, vNode.tag) + : localDoc.createElement(vNode.tag); + + applyFacts(domNode, eventNode, vNode.facts); + + var children = vNode.children; + + for (var i = 0; i < children.length; i++) + { + domNode.appendChild(render(children[i]._1, eventNode)); + } + + return domNode; + + case 'custom': + var domNode = vNode.impl.render(vNode.model); + applyFacts(domNode, eventNode, vNode.facts); + return domNode; + } +} + + + +//////////// APPLY FACTS //////////// + + +function applyFacts(domNode, eventNode, facts) +{ + for (var key in facts) + { + var value = facts[key]; + + switch (key) + { + case STYLE_KEY: + applyStyles(domNode, value); + break; + + case EVENT_KEY: + applyEvents(domNode, eventNode, value); + break; + + case ATTR_KEY: + applyAttrs(domNode, value); + break; + + case ATTR_NS_KEY: + applyAttrsNS(domNode, value); + break; + + case 'value': + if (domNode[key] !== value) + { + domNode[key] = value; + } + break; + + default: + domNode[key] = value; + break; + } + } +} + +function applyStyles(domNode, styles) +{ + var domNodeStyle = domNode.style; + + for (var key in styles) + { + domNodeStyle[key] = styles[key]; + } +} + +function applyEvents(domNode, eventNode, events) +{ + var allHandlers = domNode.elm_handlers || {}; + + for (var key in events) + { + var handler = allHandlers[key]; + var value = events[key]; + + if (typeof value === 'undefined') + { + domNode.removeEventListener(key, handler); + allHandlers[key] = undefined; + } + else if (typeof handler === 'undefined') + { + var handler = makeEventHandler(eventNode, value); + domNode.addEventListener(key, handler); + allHandlers[key] = handler; + } + else + { + handler.info = value; + } + } + + domNode.elm_handlers = allHandlers; +} + +function makeEventHandler(eventNode, info) +{ + function eventHandler(event) + { + var info = eventHandler.info; + + var value = A2(_elm_lang$core$Native_Json.run, info.decoder, event); + + if (value.ctor === 'Ok') + { + var options = info.options; + if (options.stopPropagation) + { + event.stopPropagation(); + } + if (options.preventDefault) + { + event.preventDefault(); + } + + var message = value._0; + + var currentEventNode = eventNode; + while (currentEventNode) + { + var tagger = currentEventNode.tagger; + if (typeof tagger === 'function') + { + message = tagger(message); + } + else + { + for (var i = tagger.length; i--; ) + { + message = tagger[i](message); + } + } + currentEventNode = currentEventNode.parent; + } + } + }; + + eventHandler.info = info; + + return eventHandler; +} + +function applyAttrs(domNode, attrs) +{ + for (var key in attrs) + { + var value = attrs[key]; + if (typeof value === 'undefined') + { + domNode.removeAttribute(key); + } + else + { + domNode.setAttribute(key, value); + } + } +} + +function applyAttrsNS(domNode, nsAttrs) +{ + for (var key in nsAttrs) + { + var pair = nsAttrs[key]; + var namespace = pair.namespace; + var value = pair.value; + + if (typeof value === 'undefined') + { + domNode.removeAttributeNS(namespace, key); + } + else + { + domNode.setAttributeNS(namespace, key, value); + } + } +} + + + +//////////// DIFF //////////// + + +function diff(a, b) +{ + var patches = []; + diffHelp(a, b, patches, 0); + return patches; +} + + +function makePatch(type, index, data) +{ + return { + index: index, + type: type, + data: data, + domNode: undefined, + eventNode: undefined + }; +} + + +function diffHelp(a, b, patches, index) +{ + if (a === b) + { + return; + } + + var aType = a.type; + var bType = b.type; + + // Bail if you run into different types of nodes. Implies that the + // structure has changed significantly and it's not worth a diff. + if (aType !== bType) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // Now we know that both nodes are the same type. + switch (bType) + { + case 'thunk': + var aArgs = a.args; + var bArgs = b.args; + var i = aArgs.length; + var same = a.func === b.func && i === bArgs.length; + while (same && i--) + { + same = aArgs[i] === bArgs[i]; + } + if (same) + { + b.node = a.node; + return; + } + b.node = b.thunk(); + var subPatches = []; + diffHelp(a.node, b.node, subPatches, 0); + if (subPatches.length > 0) + { + patches.push(makePatch('p-thunk', index, subPatches)); + } + return; + + case 'tagger': + // gather nested taggers + var aTaggers = a.tagger; + var bTaggers = b.tagger; + var nesting = false; + + var aSubNode = a.node; + while (aSubNode.type === 'tagger') + { + nesting = true; + + typeof aTaggers !== 'object' + ? aTaggers = [aTaggers, aSubNode.tagger] + : aTaggers.push(aSubNode.tagger); + + aSubNode = aSubNode.node; + } + + var bSubNode = b.node; + while (bSubNode.type === 'tagger') + { + nesting = true; + + typeof bTaggers !== 'object' + ? bTaggers = [bTaggers, bSubNode.tagger] + : bTaggers.push(bSubNode.tagger); + + bSubNode = bSubNode.node; + } + + // Just bail if different numbers of taggers. This implies the + // structure of the virtual DOM has changed. + if (nesting && aTaggers.length !== bTaggers.length) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + // check if taggers are "the same" + if (nesting ? !pairwiseRefEqual(aTaggers, bTaggers) : aTaggers !== bTaggers) + { + patches.push(makePatch('p-tagger', index, bTaggers)); + } + + // diff everything below the taggers + diffHelp(aSubNode, bSubNode, patches, index + 1); + return; + + case 'text': + if (a.text !== b.text) + { + patches.push(makePatch('p-text', index, b.text)); + return; + } + + return; + + case 'node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffChildren(a, b, patches, index); + return; + + case 'keyed-node': + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (a.tag !== b.tag || a.namespace !== b.namespace) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + diffKeyedChildren(a, b, patches, index); + return; + + case 'custom': + if (a.impl !== b.impl) + { + patches.push(makePatch('p-redraw', index, b)); + return; + } + + var factsDiff = diffFacts(a.facts, b.facts); + if (typeof factsDiff !== 'undefined') + { + patches.push(makePatch('p-facts', index, factsDiff)); + } + + var patch = b.impl.diff(a,b); + if (patch) + { + patches.push(makePatch('p-custom', index, patch)); + return; + } + + return; + } +} + + +// assumes the incoming arrays are the same length +function pairwiseRefEqual(as, bs) +{ + for (var i = 0; i < as.length; i++) + { + if (as[i] !== bs[i]) + { + return false; + } + } + + return true; +} + + +// TODO Instead of creating a new diff object, it's possible to just test if +// there *is* a diff. During the actual patch, do the diff again and make the +// modifications directly. This way, there's no new allocations. Worth it? +function diffFacts(a, b, category) +{ + var diff; + + // look for changes and removals + for (var aKey in a) + { + if (aKey === STYLE_KEY || aKey === EVENT_KEY || aKey === ATTR_KEY || aKey === ATTR_NS_KEY) + { + var subDiff = diffFacts(a[aKey], b[aKey] || {}, aKey); + if (subDiff) + { + diff = diff || {}; + diff[aKey] = subDiff; + } + continue; + } + + // remove if not in the new facts + if (!(aKey in b)) + { + diff = diff || {}; + diff[aKey] = + (typeof category === 'undefined') + ? (typeof a[aKey] === 'string' ? '' : null) + : + (category === STYLE_KEY) + ? '' + : + (category === EVENT_KEY || category === ATTR_KEY) + ? undefined + : + { namespace: a[aKey].namespace, value: undefined }; + + continue; + } + + var aValue = a[aKey]; + var bValue = b[aKey]; + + // reference equal, so don't worry about it + if (aValue === bValue && aKey !== 'value' + || category === EVENT_KEY && equalEvents(aValue, bValue)) + { + continue; + } + + diff = diff || {}; + diff[aKey] = bValue; + } + + // add new stuff + for (var bKey in b) + { + if (!(bKey in a)) + { + diff = diff || {}; + diff[bKey] = b[bKey]; + } + } + + return diff; +} + + +function diffChildren(aParent, bParent, patches, rootIndex) +{ + var aChildren = aParent.children; + var bChildren = bParent.children; + + var aLen = aChildren.length; + var bLen = bChildren.length; + + // FIGURE OUT IF THERE ARE INSERTS OR REMOVALS + + if (aLen > bLen) + { + patches.push(makePatch('p-remove-last', rootIndex, aLen - bLen)); + } + else if (aLen < bLen) + { + patches.push(makePatch('p-append', rootIndex, bChildren.slice(aLen))); + } + + // PAIRWISE DIFF EVERYTHING ELSE + + var index = rootIndex; + var minLen = aLen < bLen ? aLen : bLen; + for (var i = 0; i < minLen; i++) + { + index++; + var aChild = aChildren[i]; + diffHelp(aChild, bChildren[i], patches, index); + index += aChild.descendantsCount || 0; + } +} + + + +//////////// KEYED DIFF //////////// + + +function diffKeyedChildren(aParent, bParent, patches, rootIndex) +{ + var localPatches = []; + + var changes = {}; // Dict String Entry + var inserts = []; // Array { index : Int, entry : Entry } + // type Entry = { tag : String, vnode : VNode, index : Int, data : _ } + + var aChildren = aParent.children; + var bChildren = bParent.children; + var aLen = aChildren.length; + var bLen = bChildren.length; + var aIndex = 0; + var bIndex = 0; + + var index = rootIndex; + + while (aIndex < aLen && bIndex < bLen) + { + var a = aChildren[aIndex]; + var b = bChildren[bIndex]; + + var aKey = a._0; + var bKey = b._0; + var aNode = a._1; + var bNode = b._1; + + // check if keys match + + if (aKey === bKey) + { + index++; + diffHelp(aNode, bNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex++; + bIndex++; + continue; + } + + // look ahead 1 to detect insertions and removals. + + var aLookAhead = aIndex + 1 < aLen; + var bLookAhead = bIndex + 1 < bLen; + + if (aLookAhead) + { + var aNext = aChildren[aIndex + 1]; + var aNextKey = aNext._0; + var aNextNode = aNext._1; + var oldMatch = bKey === aNextKey; + } + + if (bLookAhead) + { + var bNext = bChildren[bIndex + 1]; + var bNextKey = bNext._0; + var bNextNode = bNext._1; + var newMatch = aKey === bNextKey; + } + + + // swap a and b + if (aLookAhead && bLookAhead && newMatch && oldMatch) + { + index++; + diffHelp(aNode, bNextNode, localPatches, index); + insertNode(changes, localPatches, aKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + removeNode(changes, localPatches, aKey, aNextNode, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + // insert b + if (bLookAhead && newMatch) + { + index++; + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + diffHelp(aNode, bNextNode, localPatches, index); + index += aNode.descendantsCount || 0; + + aIndex += 1; + bIndex += 2; + continue; + } + + // remove a + if (aLookAhead && oldMatch) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 1; + continue; + } + + // remove a, insert b + if (aLookAhead && bLookAhead && aNextKey === bNextKey) + { + index++; + removeNode(changes, localPatches, aKey, aNode, index); + insertNode(changes, localPatches, bKey, bNode, bIndex, inserts); + index += aNode.descendantsCount || 0; + + index++; + diffHelp(aNextNode, bNextNode, localPatches, index); + index += aNextNode.descendantsCount || 0; + + aIndex += 2; + bIndex += 2; + continue; + } + + break; + } + + // eat up any remaining nodes with removeNode and insertNode + + while (aIndex < aLen) + { + index++; + var a = aChildren[aIndex]; + var aNode = a._1; + removeNode(changes, localPatches, a._0, aNode, index); + index += aNode.descendantsCount || 0; + aIndex++; + } + + var endInserts; + while (bIndex < bLen) + { + endInserts = endInserts || []; + var b = bChildren[bIndex]; + insertNode(changes, localPatches, b._0, b._1, undefined, endInserts); + bIndex++; + } + + if (localPatches.length > 0 || inserts.length > 0 || typeof endInserts !== 'undefined') + { + patches.push(makePatch('p-reorder', rootIndex, { + patches: localPatches, + inserts: inserts, + endInserts: endInserts + })); + } +} + + + +//////////// CHANGES FROM KEYED DIFF //////////// + + +var POSTFIX = '_elmW6BL'; + + +function insertNode(changes, localPatches, key, vnode, bIndex, inserts) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + entry = { + tag: 'insert', + vnode: vnode, + index: bIndex, + data: undefined + }; + + inserts.push({ index: bIndex, entry: entry }); + changes[key] = entry; + + return; + } + + // this key was removed earlier, a match! + if (entry.tag === 'remove') + { + inserts.push({ index: bIndex, entry: entry }); + + entry.tag = 'move'; + var subPatches = []; + diffHelp(entry.vnode, vnode, subPatches, entry.index); + entry.index = bIndex; + entry.data.data = { + patches: subPatches, + entry: entry + }; + + return; + } + + // this key has already been inserted or moved, a duplicate! + insertNode(changes, localPatches, key + POSTFIX, vnode, bIndex, inserts); +} + + +function removeNode(changes, localPatches, key, vnode, index) +{ + var entry = changes[key]; + + // never seen this key before + if (typeof entry === 'undefined') + { + var patch = makePatch('p-remove', index, undefined); + localPatches.push(patch); + + changes[key] = { + tag: 'remove', + vnode: vnode, + index: index, + data: patch + }; + + return; + } + + // this key was inserted earlier, a match! + if (entry.tag === 'insert') + { + entry.tag = 'move'; + var subPatches = []; + diffHelp(vnode, entry.vnode, subPatches, index); + + var patch = makePatch('p-remove', index, { + patches: subPatches, + entry: entry + }); + localPatches.push(patch); + + return; + } + + // this key has already been removed or moved, a duplicate! + removeNode(changes, localPatches, key + POSTFIX, vnode, index); +} + + + +//////////// ADD DOM NODES //////////// +// +// Each DOM node has an "index" assigned in order of traversal. It is important +// to minimize our crawl over the actual DOM, so these indexes (along with the +// descendantsCount of virtual nodes) let us skip touching entire subtrees of +// the DOM if we know there are no patches there. + + +function addDomNodes(domNode, vNode, patches, eventNode) +{ + addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.descendantsCount, eventNode); +} + + +// assumes `patches` is non-empty and indexes increase monotonically. +function addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode) +{ + var patch = patches[i]; + var index = patch.index; + + while (index === low) + { + var patchType = patch.type; + + if (patchType === 'p-thunk') + { + addDomNodes(domNode, vNode.node, patch.data, eventNode); + } + else if (patchType === 'p-reorder') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var subPatches = patch.data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + else if (patchType === 'p-remove') + { + patch.domNode = domNode; + patch.eventNode = eventNode; + + var data = patch.data; + if (typeof data !== 'undefined') + { + data.entry.data = domNode; + var subPatches = data.patches; + if (subPatches.length > 0) + { + addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + } + else + { + patch.domNode = domNode; + patch.eventNode = eventNode; + } + + i++; + + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + + switch (vNode.type) + { + case 'tagger': + var subNode = vNode.node; + + while (subNode.type === "tagger") + { + subNode = subNode.node; + } + + return addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref); + + case 'node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'keyed-node': + var vChildren = vNode.children; + var childNodes = domNode.childNodes; + for (var j = 0; j < vChildren.length; j++) + { + low++; + var vChild = vChildren[j]._1; + var nextLow = low + (vChild.descendantsCount || 0); + if (low <= index && index <= nextLow) + { + i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.index) > high) + { + return i; + } + } + low = nextLow; + } + return i; + + case 'text': + case 'thunk': + throw new Error('should never traverse `text` or `thunk` nodes like this'); + } +} + + + +//////////// APPLY PATCHES //////////// + + +function applyPatches(rootDomNode, oldVirtualNode, patches, eventNode) +{ + if (patches.length === 0) + { + return rootDomNode; + } + + addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode); + return applyPatchesHelp(rootDomNode, patches); +} + +function applyPatchesHelp(rootDomNode, patches) +{ + for (var i = 0; i < patches.length; i++) + { + var patch = patches[i]; + var localDomNode = patch.domNode + var newNode = applyPatch(localDomNode, patch); + if (localDomNode === rootDomNode) + { + rootDomNode = newNode; + } + } + return rootDomNode; +} + +function applyPatch(domNode, patch) +{ + switch (patch.type) + { + case 'p-redraw': + return applyPatchRedraw(domNode, patch.data, patch.eventNode); + + case 'p-facts': + applyFacts(domNode, patch.eventNode, patch.data); + return domNode; + + case 'p-text': + domNode.replaceData(0, domNode.length, patch.data); + return domNode; + + case 'p-thunk': + return applyPatchesHelp(domNode, patch.data); + + case 'p-tagger': + if (typeof domNode.elm_event_node_ref !== 'undefined') + { + domNode.elm_event_node_ref.tagger = patch.data; + } + else + { + domNode.elm_event_node_ref = { tagger: patch.data, parent: patch.eventNode }; + } + return domNode; + + case 'p-remove-last': + var i = patch.data; + while (i--) + { + domNode.removeChild(domNode.lastChild); + } + return domNode; + + case 'p-append': + var newNodes = patch.data; + for (var i = 0; i < newNodes.length; i++) + { + domNode.appendChild(render(newNodes[i], patch.eventNode)); + } + return domNode; + + case 'p-remove': + var data = patch.data; + if (typeof data === 'undefined') + { + domNode.parentNode.removeChild(domNode); + return domNode; + } + var entry = data.entry; + if (typeof entry.index !== 'undefined') + { + domNode.parentNode.removeChild(domNode); + } + entry.data = applyPatchesHelp(domNode, data.patches); + return domNode; + + case 'p-reorder': + return applyPatchReorder(domNode, patch); + + case 'p-custom': + var impl = patch.data; + return impl.applyPatch(domNode, impl.data); + + default: + throw new Error('Ran into an unknown patch!'); + } +} + + +function applyPatchRedraw(domNode, vNode, eventNode) +{ + var parentNode = domNode.parentNode; + var newNode = render(vNode, eventNode); + + if (typeof newNode.elm_event_node_ref === 'undefined') + { + newNode.elm_event_node_ref = domNode.elm_event_node_ref; + } + + if (parentNode && newNode !== domNode) + { + parentNode.replaceChild(newNode, domNode); + } + return newNode; +} + + +function applyPatchReorder(domNode, patch) +{ + var data = patch.data; + + // remove end inserts + var frag = applyPatchReorderEndInsertsHelp(data.endInserts, patch); + + // removals + domNode = applyPatchesHelp(domNode, data.patches); + + // inserts + var inserts = data.inserts; + for (var i = 0; i < inserts.length; i++) + { + var insert = inserts[i]; + var entry = insert.entry; + var node = entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode); + domNode.insertBefore(node, domNode.childNodes[insert.index]); + } + + // add end inserts + if (typeof frag !== 'undefined') + { + domNode.appendChild(frag); + } + + return domNode; +} + + +function applyPatchReorderEndInsertsHelp(endInserts, patch) +{ + if (typeof endInserts === 'undefined') + { + return; + } + + var frag = localDoc.createDocumentFragment(); + for (var i = 0; i < endInserts.length; i++) + { + var insert = endInserts[i]; + var entry = insert.entry; + frag.appendChild(entry.tag === 'move' + ? entry.data + : render(entry.vnode, patch.eventNode) + ); + } + return frag; +} + + +// PROGRAMS + +var program = makeProgram(checkNoFlags); +var programWithFlags = makeProgram(checkYesFlags); + +function makeProgram(flagChecker) +{ + return F2(function(debugWrap, impl) + { + return function(flagDecoder) + { + return function(object, moduleName, debugMetadata) + { + var checker = flagChecker(flagDecoder, moduleName); + if (typeof debugMetadata === 'undefined') + { + normalSetup(impl, object, moduleName, checker); + } + else + { + debugSetup(A2(debugWrap, debugMetadata, impl), object, moduleName, checker); + } + }; + }; + }); +} + +function staticProgram(vNode) +{ + var nothing = _elm_lang$core$Native_Utils.Tuple2( + _elm_lang$core$Native_Utils.Tuple0, + _elm_lang$core$Platform_Cmd$none + ); + return A2(program, _elm_lang$virtual_dom$VirtualDom_Debug$wrap, { + init: nothing, + view: function() { return vNode; }, + update: F2(function() { return nothing; }), + subscriptions: function() { return _elm_lang$core$Platform_Sub$none; } + })(); +} + + +// FLAG CHECKERS + +function checkNoFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flags === 'undefined') + { + return init; + } + + var errorMessage = + 'The `' + moduleName + '` module does not need flags.\n' + + 'Initialize it with no arguments and you should be all set!'; + + crash(errorMessage, domNode); + }; +} + +function checkYesFlags(flagDecoder, moduleName) +{ + return function(init, flags, domNode) + { + if (typeof flagDecoder === 'undefined') + { + var errorMessage = + 'Are you trying to sneak a Never value into Elm? Trickster!\n' + + 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n' + + 'Use `program` instead if you do not want flags.' + + crash(errorMessage, domNode); + } + + var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags); + if (result.ctor === 'Ok') + { + return init(result._0); + } + + var errorMessage = + 'Trying to initialize the `' + moduleName + '` module with an unexpected flag.\n' + + 'I tried to convert it to an Elm value, but ran into this problem:\n\n' + + result._0; + + crash(errorMessage, domNode); + }; +} + +function crash(errorMessage, domNode) +{ + if (domNode) + { + domNode.innerHTML = + '
' + + '

Oops! Something went wrong when starting your Elm program.

' + + '
' + errorMessage + '
' + + '
'; + } + + throw new Error(errorMessage); +} + + +// NORMAL SETUP + +function normalSetup(impl, object, moduleName, flagChecker) +{ + object['embed'] = function embed(node, flags) + { + while (node.lastChild) + { + node.removeChild(node.lastChild); + } + + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update, + impl.subscriptions, + normalRenderer(node, impl.view) + ); + }; + + object['fullscreen'] = function fullscreen(flags) + { + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update, + impl.subscriptions, + normalRenderer(document.body, impl.view) + ); + }; +} + +function normalRenderer(parentNode, view) +{ + return function(tagger, initialModel) + { + var eventNode = { tagger: tagger, parent: undefined }; + var initialVirtualNode = view(initialModel); + var domNode = render(initialVirtualNode, eventNode); + parentNode.appendChild(domNode); + return makeStepper(domNode, view, initialVirtualNode, eventNode); + }; +} + + +// STEPPER + +var rAF = + typeof requestAnimationFrame !== 'undefined' + ? requestAnimationFrame + : function(callback) { setTimeout(callback, 1000 / 60); }; + +function makeStepper(domNode, view, initialVirtualNode, eventNode) +{ + var state = 'NO_REQUEST'; + var currNode = initialVirtualNode; + var nextModel; + + function updateIfNeeded() + { + switch (state) + { + case 'NO_REQUEST': + throw new Error( + 'Unexpected draw callback.\n' + + 'Please report this to .' + ); + + case 'PENDING_REQUEST': + rAF(updateIfNeeded); + state = 'EXTRA_REQUEST'; + + var nextNode = view(nextModel); + var patches = diff(currNode, nextNode); + domNode = applyPatches(domNode, currNode, patches, eventNode); + currNode = nextNode; + + return; + + case 'EXTRA_REQUEST': + state = 'NO_REQUEST'; + return; + } + } + + return function stepper(model) + { + if (state === 'NO_REQUEST') + { + rAF(updateIfNeeded); + } + state = 'PENDING_REQUEST'; + nextModel = model; + }; +} + + +// DEBUG SETUP + +function debugSetup(impl, object, moduleName, flagChecker) +{ + object['fullscreen'] = function fullscreen(flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, document.body), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, document.body, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; + + object['embed'] = function fullscreen(node, flags) + { + var popoutRef = { doc: undefined }; + return _elm_lang$core$Native_Platform.initialize( + flagChecker(impl.init, flags, node), + impl.update(scrollTask(popoutRef)), + impl.subscriptions, + debugRenderer(moduleName, node, popoutRef, impl.view, impl.viewIn, impl.viewOut) + ); + }; +} + +function scrollTask(popoutRef) +{ + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) + { + var doc = popoutRef.doc; + if (doc) + { + var msgs = doc.getElementsByClassName('debugger-sidebar-messages')[0]; + if (msgs) + { + msgs.scrollTop = msgs.scrollHeight; + } + } + callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0)); + }); +} + + +function debugRenderer(moduleName, parentNode, popoutRef, view, viewIn, viewOut) +{ + return function(tagger, initialModel) + { + var appEventNode = { tagger: tagger, parent: undefined }; + var eventNode = { tagger: tagger, parent: undefined }; + + // make normal stepper + var appVirtualNode = view(initialModel); + var appNode = render(appVirtualNode, appEventNode); + parentNode.appendChild(appNode); + var appStepper = makeStepper(appNode, view, appVirtualNode, appEventNode); + + // make overlay stepper + var overVirtualNode = viewIn(initialModel)._1; + var overNode = render(overVirtualNode, eventNode); + parentNode.appendChild(overNode); + var wrappedViewIn = wrapViewIn(appEventNode, overNode, viewIn); + var overStepper = makeStepper(overNode, wrappedViewIn, overVirtualNode, eventNode); + + // make debugger stepper + var debugStepper = makeDebugStepper(initialModel, viewOut, eventNode, parentNode, moduleName, popoutRef); + + return function stepper(model) + { + appStepper(model); + overStepper(model); + debugStepper(model); + } + }; +} + +function makeDebugStepper(initialModel, view, eventNode, parentNode, moduleName, popoutRef) +{ + var curr; + var domNode; + + return function stepper(model) + { + if (!model.isDebuggerOpen) + { + return; + } + + if (!popoutRef.doc) + { + curr = view(model); + domNode = openDebugWindow(moduleName, popoutRef, curr, eventNode); + return; + } + + // switch to document of popout + localDoc = popoutRef.doc; + + var next = view(model); + var patches = diff(curr, next); + domNode = applyPatches(domNode, curr, patches, eventNode); + curr = next; + + // switch back to normal document + localDoc = document; + }; +} + +function openDebugWindow(moduleName, popoutRef, virtualNode, eventNode) +{ + var w = 900; + var h = 360; + var x = screen.width - w; + var y = screen.height - h; + var debugWindow = window.open('', '', 'width=' + w + ',height=' + h + ',left=' + x + ',top=' + y); + + // switch to window document + localDoc = debugWindow.document; + + popoutRef.doc = localDoc; + localDoc.title = 'Debugger - ' + moduleName; + localDoc.body.style.margin = '0'; + localDoc.body.style.padding = '0'; + var domNode = render(virtualNode, eventNode); + localDoc.body.appendChild(domNode); + + localDoc.addEventListener('keydown', function(event) { + if (event.metaKey && event.which === 82) + { + window.location.reload(); + } + if (event.which === 38) + { + eventNode.tagger({ ctor: 'Up' }); + event.preventDefault(); + } + if (event.which === 40) + { + eventNode.tagger({ ctor: 'Down' }); + event.preventDefault(); + } + }); + + function close() + { + popoutRef.doc = undefined; + debugWindow.close(); + } + window.addEventListener('unload', close); + debugWindow.addEventListener('unload', function() { + popoutRef.doc = undefined; + window.removeEventListener('unload', close); + eventNode.tagger({ ctor: 'Close' }); + }); + + // switch back to the normal document + localDoc = document; + + return domNode; +} + + +// BLOCK EVENTS + +function wrapViewIn(appEventNode, overlayNode, viewIn) +{ + var ignorer = makeIgnorer(overlayNode); + var blocking = 'Normal'; + var overflow; + + var normalTagger = appEventNode.tagger; + var blockTagger = function() {}; + + return function(model) + { + var tuple = viewIn(model); + var newBlocking = tuple._0.ctor; + appEventNode.tagger = newBlocking === 'Normal' ? normalTagger : blockTagger; + if (blocking !== newBlocking) + { + traverse('removeEventListener', ignorer, blocking); + traverse('addEventListener', ignorer, newBlocking); + + if (blocking === 'Normal') + { + overflow = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + } + + if (newBlocking === 'Normal') + { + document.body.style.overflow = overflow; + } + + blocking = newBlocking; + } + return tuple._1; + } +} + +function traverse(verbEventListener, ignorer, blocking) +{ + switch(blocking) + { + case 'Normal': + return; + + case 'Pause': + return traverseHelp(verbEventListener, ignorer, mostEvents); + + case 'Message': + return traverseHelp(verbEventListener, ignorer, allEvents); + } +} + +function traverseHelp(verbEventListener, handler, eventNames) +{ + for (var i = 0; i < eventNames.length; i++) + { + document.body[verbEventListener](eventNames[i], handler, true); + } +} + +function makeIgnorer(overlayNode) +{ + return function(event) + { + if (event.type === 'keydown' && event.metaKey && event.which === 82) + { + return; + } + + var isScroll = event.type === 'scroll' || event.type === 'wheel'; + + var node = event.target; + while (node !== null) + { + if (node.className === 'elm-overlay-message-details' && isScroll) + { + return; + } + + if (node === overlayNode && !isScroll) + { + return; + } + node = node.parentNode; + } + + event.stopPropagation(); + event.preventDefault(); + } +} + +var mostEvents = [ + 'click', 'dblclick', 'mousemove', + 'mouseup', 'mousedown', 'mouseenter', 'mouseleave', + 'touchstart', 'touchend', 'touchcancel', 'touchmove', + 'pointerdown', 'pointerup', 'pointerover', 'pointerout', + 'pointerenter', 'pointerleave', 'pointermove', 'pointercancel', + 'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave', 'drop', + 'keyup', 'keydown', 'keypress', + 'input', 'change', + 'focus', 'blur' +]; + +var allEvents = mostEvents.concat('wheel', 'scroll'); + + +return { + node: node, + text: text, + custom: custom, + map: F2(map), + + on: F3(on), + style: style, + property: F2(property), + attribute: F2(attribute), + attributeNS: F3(attributeNS), + mapProperty: F2(mapProperty), + + lazy: F2(lazy), + lazy2: F3(lazy2), + lazy3: F4(lazy3), + keyedNode: F3(keyedNode), + + program: program, + programWithFlags: programWithFlags, + staticProgram: staticProgram +}; + +}(); diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm new file mode 100644 index 0000000..ac28926 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom.elm @@ -0,0 +1,331 @@ +module VirtualDom exposing + ( Node + , text, node + , Property, property, attribute, attributeNS, mapProperty + , style + , on, onWithOptions, Options, defaultOptions + , map + , lazy, lazy2, lazy3 + , keyedNode + , program, programWithFlags + ) + +{-| API to the core diffing algorithm. Can serve as a foundation for libraries +that expose more helper functions for HTML or SVG. + +# Create +@docs Node, text, node + +# Declare Properties and Attributes +@docs Property, property, attribute, attributeNS, mapProperty + +# Styles +@docs style + +# Events +@docs on, onWithOptions, Options, defaultOptions + +# Routing Messages +@docs map + +# Optimizations +@docs lazy, lazy2, lazy3, keyedNode + +# Programs +@docs program, programWithFlags + +-} + +import Json.Decode as Json +import Native.VirtualDom +import VirtualDom.Debug as Debug + + +{-| An immutable chunk of data representing a DOM node. This can be HTML or SVG. +-} +type Node msg = Node + + +{-| Create a DOM node with a tag name, a list of HTML properties that can +include styles and event listeners, a list of CSS properties like `color`, and +a list of child nodes. + + import Json.Encode as Json + + hello : Node msg + hello = + node "div" [] [ text "Hello!" ] + + greeting : Node msg + greeting = + node "div" + [ property "id" (Json.string "greeting") ] + [ text "Hello!" ] +-} +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +{-| Just put plain text in the DOM. It will escape the string so that it appears +exactly as you specify. + + text "Hello World!" +-} +text : String -> Node msg +text = + Native.VirtualDom.text + + +{-| This function is useful when nesting components with [the Elm +Architecture](https://github.com/evancz/elm-architecture-tutorial/). It lets +you transform the messages produced by a subtree. + +Say you have a node named `button` that produces `()` values when it is +clicked. To get your model updating properly, you will probably want to tag +this `()` value like this: + + type Msg = Click | ... + + update msg model = + case msg of + Click -> + ... + + view model = + map (\_ -> Click) button + +So now all the events produced by `button` will be transformed to be of type +`Msg` so they can be handled by your update function! +-} +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + + +-- PROPERTIES + + +{-| When using HTML and JS, there are two ways to specify parts of a DOM node. + + 1. Attributes — You can set things in HTML itself. So the `class` + in `
` is called an *attribute*. + + 2. Properties — You can also set things in JS. So the `className` + in `div.className = 'greeting'` is called a *property*. + +So the `class` attribute corresponds to the `className` property. At first +glance, perhaps this distinction is defensible, but it gets much crazier. +*There is not always a one-to-one mapping between attributes and properties!* +Yes, that is a true fact. Sometimes an attribute exists, but there is no +corresponding property. Sometimes changing an attribute does not change the +underlying property. For example, as of this writing, the `webkit-playsinline` +attribute can be used in HTML, but there is no corresponding property! +-} +type Property msg = Property + + +{-| Create arbitrary *properties*. + + import JavaScript.Encode as Json + + greeting : Html + greeting = + node "div" [ property "className" (Json.string "greeting") ] [ + text "Hello!" + ] + +Notice that you must give the *property* name, so we use `className` as it +would be in JavaScript, not `class` as it would appear in HTML. +-} +property : String -> Json.Value -> Property msg +property = + Native.VirtualDom.property + + +{-| Create arbitrary HTML *attributes*. Maps onto JavaScript’s `setAttribute` +function under the hood. + + greeting : Html + greeting = + node "div" [ attribute "class" "greeting" ] [ + text "Hello!" + ] + +Notice that you must give the *attribute* name, so we use `class` as it would +be in HTML, not `className` as it would appear in JS. +-} +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +{-| Would you believe that there is another way to do this?! This corresponds +to JavaScript's `setAttributeNS` function under the hood. It is doing pretty +much the same thing as `attribute` but you are able to have "namespaced" +attributes. This is used in some SVG stuff at least. +-} +attributeNS : String -> String -> String -> Property msg +attributeNS = + Native.VirtualDom.attributeNS + + +{-| Transform the messages produced by a `Property`. +-} +mapProperty : (a -> b) -> Property a -> Property b +mapProperty = + Native.VirtualDom.mapProperty + + +{-| Specify a list of styles. + + myStyle : Property msg + myStyle = + style + [ ("backgroundColor", "red") + , ("height", "90px") + , ("width", "100%") + ] + + greeting : Node msg + greeting = + node "div" [ myStyle ] [ text "Hello!" ] + +-} +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + + +-- EVENTS + + +{-| Create a custom event listener. + + import Json.Decode as Json + + onClick : msg -> Property msg + onClick msg = + on "click" (Json.succeed msg) + +You first specify the name of the event in the same format as with JavaScript’s +`addEventListener`. Next you give a JSON decoder, which lets you pull +information out of the event object. If the decoder succeeds, it will produce +a message and route it to your `update` function. +-} +on : String -> Json.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +{-| Same as `on` but you can set a few options. +-} +onWithOptions : String -> Options -> Json.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +{-| Options for an event listener. If `stopPropagation` is true, it means the +event stops traveling through the DOM so it will not trigger any other event +listeners. If `preventDefault` is true, any built-in browser behavior related +to the event is prevented. For example, this is used with touch events when you +want to treat them as gestures of your own, not as scrolls. +-} +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +{-| Everything is `False` by default. + + defaultOptions = + { stopPropagation = False + , preventDefault = False + } +-} +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + + +-- OPTIMIZATION + + +{-| A performance optimization that delays the building of virtual DOM nodes. + +Calling `(view model)` will definitely build some virtual DOM, perhaps a lot of +it. Calling `(lazy view model)` delays the call until later. During diffing, we +can check to see if `model` is referentially equal to the previous value used, +and if so, we just stop. No need to build up the tree structure and diff it, +we know if the input to `view` is the same, the output must be the same! +-} +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +{-| Same as `lazy` but checks on two arguments. +-} +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +{-| Same as `lazy` but checks on three arguments. +-} +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +{-| Works just like `node`, but you add a unique identifier to each child +node. You want this when you have a list of nodes that is changing: adding +nodes, removing nodes, etc. In these cases, the unique identifiers help make +the DOM modifications more efficient. +-} +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + + + +-- PROGRAMS + + +{-| Check out the docs for [`Html.App.program`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#program +-} +program + : { init : (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program Never model msg +program impl = + Native.VirtualDom.program Debug.wrap impl + + +{-| Check out the docs for [`Html.App.programWithFlags`][prog]. +It works exactly the same way. + +[prog]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-App#programWithFlags +-} +programWithFlags + : { init : flags -> (model, Cmd msg) + , update : msg -> model -> (model, Cmd msg) + , subscriptions : model -> Sub msg + , view : model -> Node msg + } + -> Program flags model msg +programWithFlags impl = + Native.VirtualDom.programWithFlags Debug.wrapWithFlags impl + diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm new file mode 100644 index 0000000..ba7afe5 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Debug.elm @@ -0,0 +1,567 @@ +module VirtualDom.Debug exposing (wrap, wrapWithFlags) + +import Json.Decode as Decode +import Json.Encode as Encode +import Task exposing (Task) +import Native.Debug +import Native.VirtualDom +import VirtualDom.Expando as Expando exposing (Expando) +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.History as History exposing (History) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Overlay as Overlay +import VirtualDom.Report as Report + + + +-- WRAP PROGRAMS + + +wrap metadata { init, update, subscriptions, view } = + { init = wrapInit metadata init + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + +wrapWithFlags metadata { init, update, subscriptions, view } = + { init = \flags -> wrapInit metadata (init flags) + , view = wrapView view + , update = wrapUpdate update + , viewIn = viewIn + , viewOut = viewOut + , subscriptions = wrapSubs subscriptions + } + + + +-- MODEL + + +type alias Model model msg = + { history : History model msg + , state : State model + , expando : Expando + , metadata : Result Metadata.Error Metadata + , overlay : Overlay.State + , isDebuggerOpen : Bool + } + + +type State model + = Running model + | Paused Int model model + + +wrapInit : Encode.Value -> ( model, Cmd msg ) -> ( Model model msg, Cmd (Msg msg) ) +wrapInit metadata ( userModel, userCommands ) = + { history = History.empty userModel + , state = Running userModel + , expando = Expando.init userModel + , metadata = Metadata.decode metadata + , overlay = Overlay.none + , isDebuggerOpen = False + } + ! [ Cmd.map UserMsg userCommands ] + + + +-- UPDATE + + +type Msg msg + = NoOp + | UserMsg msg + | ExpandoMsg Expando.Msg + | Resume + | Jump Int + | Open + | Close + | Up + | Down + | Import + | Export + | Upload String + | OverlayMsg Overlay.Msg + + +type alias UserUpdate model msg = + msg -> model -> ( model, Cmd msg ) + + +wrapUpdate + : UserUpdate model msg + -> Task Never () + -> Msg msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +wrapUpdate userUpdate scrollTask msg model = + case msg of + NoOp -> + model ! [] + + UserMsg userMsg -> + updateUserMsg userUpdate scrollTask userMsg model + + ExpandoMsg eMsg -> + { model + | expando = Expando.update eMsg model.expando + } + ! [] + + Resume -> + case model.state of + Running _ -> + model ! [] + + Paused _ _ userModel -> + { model + | state = Running userModel + , expando = Expando.merge userModel model.expando + } + ! [ runIf model.isDebuggerOpen scrollTask ] + + Jump index -> + let + (indexModel, indexMsg) = + History.get userUpdate index model.history + in + { model + | state = Paused index indexModel (getLatestModel model.state) + , expando = Expando.merge indexModel model.expando + } + ! [] + + Open -> + { model | isDebuggerOpen = True } ! [] + + Close -> + { model | isDebuggerOpen = False } ! [] + + Up -> + let + index = + case model.state of + Paused index _ _ -> + index + + Running _ -> + History.size model.history + in + if index > 0 then + wrapUpdate userUpdate scrollTask (Jump (index - 1)) model + else + model ! [] + + Down -> + case model.state of + Running _ -> + model ! [] + + Paused index _ userModel -> + if index == History.size model.history - 1 then + wrapUpdate userUpdate scrollTask Resume model + else + wrapUpdate userUpdate scrollTask (Jump (index + 1)) model + + Import -> + withGoodMetadata model <| \_ -> + model ! [ upload ] + + Export -> + withGoodMetadata model <| \metadata -> + model ! [ download metadata model.history ] + + Upload jsonString -> + withGoodMetadata model <| \metadata -> + case Overlay.assessImport metadata jsonString of + Err newOverlay -> + { model | overlay = newOverlay } ! [] + + Ok rawHistory -> + loadNewHistory rawHistory userUpdate model + + OverlayMsg overlayMsg -> + case Overlay.close overlayMsg model.overlay of + Nothing -> + { model | overlay = Overlay.none } ! [] + + Just rawHistory -> + loadNewHistory rawHistory userUpdate model + + + +-- COMMANDS + + +upload : Cmd (Msg msg) +upload = + Task.perform Upload Native.Debug.upload + + +download : Metadata -> History model msg -> Cmd (Msg msg) +download metadata history = + let + historyLength = + History.size history + + json = + Encode.object + [ ("metadata", Metadata.encode metadata) + , ("history", History.encode history) + ] + in + Task.perform (\_ -> NoOp) (Native.Debug.download historyLength json) + + + +-- UPDATE OVERLAY + + +withGoodMetadata + : Model model msg + -> (Metadata -> (Model model msg, Cmd (Msg msg))) + -> (Model model msg, Cmd (Msg msg)) +withGoodMetadata model func = + case model.metadata of + Ok metadata -> + func metadata + + Err error -> + { model | overlay = Overlay.badMetadata error } ! [] + + +loadNewHistory + : Encode.Value + -> UserUpdate model msg + -> Model model msg + -> ( Model model msg, Cmd (Msg msg) ) +loadNewHistory rawHistory userUpdate model = + let + initialUserModel = + History.initialModel model.history + + pureUserUpdate msg userModel = + Tuple.first (userUpdate msg userModel) + + decoder = + History.decoder initialUserModel pureUserUpdate + in + case Decode.decodeValue decoder rawHistory of + Err _ -> + { model | overlay = Overlay.corruptImport } ! [] + + Ok (latestUserModel, newHistory) -> + { model + | history = newHistory + , state = Running latestUserModel + , expando = Expando.init latestUserModel + , overlay = Overlay.none + } + ! [] + + + +-- UPDATE - USER MESSAGES + + +updateUserMsg + : UserUpdate model msg + -> Task Never () + -> msg + -> Model model msg + -> (Model model msg, Cmd (Msg msg)) +updateUserMsg userUpdate scrollTask userMsg ({ history, state, expando } as model) = + let + userModel = + getLatestModel state + + newHistory = + History.add userMsg userModel history + + (newUserModel, userCmds) = + userUpdate userMsg userModel + + commands = + Cmd.map UserMsg userCmds + in + case state of + Running _ -> + { model + | history = newHistory + , state = Running newUserModel + , expando = Expando.merge newUserModel expando + } + ! [ commands, runIf model.isDebuggerOpen scrollTask ] + + Paused index indexModel _ -> + { model + | history = newHistory + , state = Paused index indexModel newUserModel + } + ! [ commands ] + + +runIf : Bool -> Task Never () -> Cmd (Msg msg) +runIf bool task = + if bool then + Task.perform (always NoOp) task + else + Cmd.none + + +getLatestModel : State model -> model +getLatestModel state = + case state of + Running model -> + model + + Paused _ _ model -> + model + + + +-- SUBSCRIPTIONS + + +wrapSubs : (model -> Sub msg) -> Model model msg -> Sub (Msg msg) +wrapSubs userSubscriptions {state} = + getLatestModel state + |> userSubscriptions + |> Sub.map UserMsg + + + +-- VIEW + + +wrapView : (model -> Node msg) -> Model model msg -> Node (Msg msg) +wrapView userView { state } = + let + currentModel = + case state of + Running model -> + model + + Paused _ oldModel _ -> + oldModel + in + VDom.map UserMsg (userView currentModel) + + + +-- SMALL DEBUG VIEW + + +viewIn : Model model msg -> ( Overlay.Block, Node (Msg msg) ) +viewIn { history, state, overlay, isDebuggerOpen } = + let + isPaused = + case state of + Running _ -> + False + + Paused _ _ _ -> + True + in + Overlay.view overlayConfig isPaused isDebuggerOpen (History.size history) overlay + + +overlayConfig : Overlay.Config (Msg msg) +overlayConfig = + { resume = Resume + , open = Open + , importHistory = Import + , exportHistory = Export + , wrap = OverlayMsg + } + + + +-- BIG DEBUG VIEW + + +viewOut : Model model msg -> Node (Msg msg) +viewOut { history, state, expando } = + VDom.div + [ VDom.id "debugger" ] + [ styles + , viewSidebar state history + , VDom.map ExpandoMsg <| + VDom.div [ VDom.id "values" ] [ Expando.view Nothing expando ] + ] + + +viewSidebar : State model -> History model msg -> Node (Msg msg) +viewSidebar state history = + let + maybeIndex = + case state of + Running _ -> + Nothing + + Paused index _ _ -> + Just index + in + VDom.div [ VDom.class "debugger-sidebar" ] + [ VDom.map Jump (History.view maybeIndex history) + , playButton maybeIndex + ] + + +playButton : Maybe Int -> Node (Msg msg) +playButton maybeIndex = + VDom.div [ VDom.class "debugger-sidebar-controls" ] + [ viewResumeButton maybeIndex + , VDom.div [ VDom.class "debugger-sidebar-controls-import-export" ] + [ button Import "Import" + , VDom.text " / " + , button Export "Export" + ] + ] + + +button msg label = + VDom.span + [ VDom.onClick msg + , VDom.style [("cursor","pointer")] + ] + [ VDom.text label ] + + +viewResumeButton maybeIndex = + case maybeIndex of + Nothing -> + VDom.text "" + + Just _ -> + resumeButton + + +resumeButton = + VDom.div + [ VDom.onClick Resume + , VDom.class "debugger-sidebar-controls-resume" + ] + [ VDom.text "Resume" + ] + + + +-- STYLE + + +styles : Node msg +styles = + VDom.node "style" [] [ VDom.text """ + +html { + overflow: hidden; + height: 100%; +} + +body { + height: 100%; + overflow: auto; +} + +#debugger { + width: 100% + height: 100%; + font-family: monospace; +} + +#values { + display: block; + float: left; + height: 100%; + width: calc(100% - 30ch); + margin: 0; + overflow: auto; + cursor: default; +} + +.debugger-sidebar { + display: block; + float: left; + width: 30ch; + height: 100%; + color: white; + background-color: rgb(61, 61, 61); +} + +.debugger-sidebar-controls { + width: 100%; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.debugger-sidebar-controls-import-export { + width: 100%; + height: 24px; + line-height: 24px; + font-size: 12px; +} + +.debugger-sidebar-controls-resume { + width: 100%; + height: 30px; + line-height: 30px; + cursor: pointer; +} + +.debugger-sidebar-controls-resume:hover { + background-color: rgb(41, 41, 41); +} + +.debugger-sidebar-messages { + width: 100%; + overflow-y: auto; + height: calc(100% - 24px); +} + +.debugger-sidebar-messages-paused { + width: 100%; + overflow-y: auto; + height: calc(100% - 54px); +} + +.messages-entry { + cursor: pointer; + width: 100%; +} + +.messages-entry:hover { + background-color: rgb(41, 41, 41); +} + +.messages-entry-selected, .messages-entry-selected:hover { + background-color: rgb(10, 10, 10); +} + +.messages-entry-content { + width: calc(100% - 7ch); + padding-top: 4px; + padding-bottom: 4px; + padding-left: 1ch; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + display: inline-block; +} + +.messages-entry-index { + color: #666; + width: 5ch; + padding-top: 4px; + padding-bottom: 4px; + padding-right: 1ch; + text-align: right; + display: block; + float: right; +} + +""" ] diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm new file mode 100644 index 0000000..88b5857 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Expando.elm @@ -0,0 +1,659 @@ +module VirtualDom.Expando exposing + ( Expando + , init + , merge + , Msg, update + , view + ) + + +import Dict exposing (Dict) +import Json.Decode as Json +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node, text, div, span, class, onClick) + + + +-- MODEL + + +type Expando + = S String + | Primitive String + | Sequence SeqType Bool (List Expando) + | Dictionary Bool (List (Expando, Expando)) + | Record Bool (Dict String Expando) + | Constructor (Maybe String) Bool (List Expando) + + +type SeqType = ListSeq | SetSeq | ArraySeq + + +seqTypeToString : Int -> SeqType -> String +seqTypeToString n seqType = + case seqType of + ListSeq -> + "List(" ++ toString n ++ ")" + + SetSeq -> + "Set(" ++ toString n ++ ")" + + ArraySeq -> + "Array(" ++ toString n ++ ")" + + + +-- INITIALIZE + + +init : a -> Expando +init value = + initHelp True (Native.Debug.init value) + + +initHelp : Bool -> Expando -> Expando +initHelp isOuter expando = + case expando of + S _ -> + expando + + Primitive _ -> + expando + + Sequence seqType isClosed items -> + if isOuter then + Sequence seqType False (List.map (initHelp False) items) + else if List.length items <= 8 then + Sequence seqType False items + else + expando + + Dictionary isClosed keyValuePairs -> + if isOuter then + Dictionary False (List.map (\(k,v) -> (k, initHelp False v)) keyValuePairs) + else if List.length keyValuePairs <= 8 then + Dictionary False keyValuePairs + else + expando + + Record isClosed entries -> + if isOuter then + Record False (Dict.map (\_ v -> initHelp False v) entries) + else if Dict.size entries <= 4 then + Record False entries + else + expando + + Constructor maybeName isClosed args -> + if isOuter then + Constructor maybeName False (List.map (initHelp False) args) + else if List.length args <= 4 then + Constructor maybeName False args + else + expando + + + +-- PRESERVE OLD EXPANDO STATE (open/closed) + + +merge : a -> Expando -> Expando +merge value expando = + mergeHelp expando (Native.Debug.init value) + + +mergeHelp : Expando -> Expando -> Expando +mergeHelp old new = + case ( old, new ) of + ( _, S _ ) -> + new + + ( _, Primitive _ ) -> + new + + ( Sequence _ isClosed oldValues, Sequence seqType _ newValues ) -> + Sequence seqType isClosed (mergeListHelp oldValues newValues) + + ( Dictionary isClosed _, Dictionary _ keyValuePairs ) -> + Dictionary isClosed keyValuePairs + + ( Record isClosed oldDict, Record _ newDict ) -> + Record isClosed <| Dict.map (mergeDictHelp oldDict) newDict + + ( Constructor _ isClosed oldValues, Constructor maybeName _ newValues ) -> + Constructor maybeName isClosed (mergeListHelp oldValues newValues) + + _ -> + new + + +mergeListHelp : List Expando -> List Expando -> List Expando +mergeListHelp olds news = + case (olds, news) of + ( [], _ ) -> + news + + ( _, [] ) -> + news + + ( x :: xs, y :: ys ) -> + mergeHelp x y :: mergeListHelp xs ys + + +mergeDictHelp : Dict String Expando -> String -> Expando -> Expando +mergeDictHelp oldDict key value = + case Dict.get key oldDict of + Nothing -> + value + + Just oldValue -> + mergeHelp oldValue value + + + +-- UPDATE + + +type Msg + = Toggle + | Index Redirect Int Msg + | Field String Msg + + +type Redirect = None | Key | Value + + +update : Msg -> Expando -> Expando +update msg value = + case value of + S _ -> + Debug.crash "No messages for primitives" + + Primitive _ -> + Debug.crash "No messages for primitives" + + Sequence seqType isClosed valueList -> + case msg of + Toggle -> + Sequence seqType (not isClosed) valueList + + Index None index subMsg -> + Sequence seqType isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field on sequences" + + Dictionary isClosed keyValuePairs -> + case msg of + Toggle -> + Dictionary (not isClosed) keyValuePairs + + Index redirect index subMsg -> + case redirect of + None -> + Debug.crash "must have redirect for dictionaries" + + Key -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (update subMsg k, v)) keyValuePairs + + Value -> + Dictionary isClosed <| + updateIndex index (\(k,v) -> (k, update subMsg v)) keyValuePairs + + Field _ _ -> + Debug.crash "no field for dictionaries" + + Record isClosed valueDict -> + case msg of + Toggle -> + Record (not isClosed) valueDict + + Index _ _ _ -> + Debug.crash "No index for records" + + Field field subMsg -> + Record isClosed (Dict.update field (updateField subMsg) valueDict) + + Constructor maybeName isClosed valueList -> + case msg of + Toggle -> + Constructor maybeName (not isClosed) valueList + + Index None index subMsg -> + Constructor maybeName isClosed <| + updateIndex index (update subMsg) valueList + + Index _ _ _ -> + Debug.crash "No redirected indexes on sequences" + + Field _ _ -> + Debug.crash "No field for constructors" + + +updateIndex : Int -> (a -> a) -> List a -> List a +updateIndex n func list = + case list of + [] -> + [] + + x :: xs -> + if n <= 0 then + func x :: xs + else + x :: updateIndex (n-1) func xs + + +updateField : Msg -> Maybe Expando -> Maybe Expando +updateField msg maybeExpando = + case maybeExpando of + Nothing -> + Debug.crash "key does not exist" + + Just expando -> + Just (update msg expando) + + + +-- VIEW + + +view : Maybe String -> Expando -> Node Msg +view maybeKey expando = + case expando of + S stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [red] [text stringRep]]) + + Primitive stringRep -> + div [ leftPad maybeKey ] (lineStarter maybeKey Nothing [span [blue] [text stringRep]]) + + Sequence seqType isClosed valueList -> + viewSequence maybeKey seqType isClosed valueList + + Dictionary isClosed keyValuePairs -> + viewDictionary maybeKey isClosed keyValuePairs + + Record isClosed valueDict -> + viewRecord maybeKey isClosed valueDict + + Constructor maybeName isClosed valueList -> + viewConstructor maybeKey maybeName isClosed valueList + + + +-- VIEW SEQUENCE + + +viewSequence : Maybe String -> SeqType -> Bool -> List Expando -> Node Msg +viewSequence maybeKey seqType isClosed valueList = + let + starter = + seqTypeToString (List.length valueList) seqType + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewSequenceOpen valueList + ] + + +viewSequenceOpen : List Expando -> Node Msg +viewSequenceOpen values = + div [] (List.indexedMap viewConstructorEntry values) + + + +-- VIEW DICTIONARY + + +viewDictionary : Maybe String -> Bool -> List (Expando, Expando) -> Node Msg +viewDictionary maybeKey isClosed keyValuePairs = + let + starter = + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) [text starter]) + , if isClosed then text "" else viewDictionaryOpen keyValuePairs + ] + + +viewDictionaryOpen : List (Expando, Expando) -> Node Msg +viewDictionaryOpen keyValuePairs = + div [] (List.indexedMap viewDictionaryEntry keyValuePairs) + + +viewDictionaryEntry : Int -> (Expando, Expando) -> Node Msg +viewDictionaryEntry index (key, value) = + case key of + S stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + Primitive stringRep -> + VDom.map (Index Value index) (view (Just stringRep) value) + + _ -> + div [] + [ VDom.map (Index Key index) (view (Just "key") key) + , VDom.map (Index Value index) (view (Just "value") value) + ] + + + +-- VIEW RECORD + + +viewRecord : Maybe String -> Bool -> Dict String Expando -> Node Msg +viewRecord maybeKey isClosed record = + let + (start, middle, end) = + if isClosed then + ( Tuple.second (viewTinyRecord record), text "", text "" ) + else + ( [ text "{" ], viewRecordOpen record, div [leftPad (Just ())] [text "}"] ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey (Just isClosed) start) + , middle + , end + ] + + +viewRecordOpen : Dict String Expando -> Node Msg +viewRecordOpen record = + div [] (List.map viewRecordEntry (Dict.toList record)) + + +viewRecordEntry : (String, Expando) -> Node Msg +viewRecordEntry (field, value) = + VDom.map (Field field) (view (Just field) value) + + + +-- VIEW CONSTRUCTOR + + +viewConstructor : Maybe String -> Maybe String -> Bool -> List Expando -> Node Msg +viewConstructor maybeKey maybeName isClosed valueList = + let + tinyArgs = + List.map (Tuple.second << viewExtraTiny) valueList + + description = + case (maybeName, tinyArgs) of + (Nothing, []) -> + [ text "()" ] + + (Nothing, x :: xs) -> + text "( " + :: span [] x + :: List.foldr (\args rest -> text ", " :: span [] args :: rest) [text " )"] xs + + (Just name, []) -> + [ text name ] + + (Just name, x :: xs) -> + text (name ++ " ") + :: span [] x + :: List.foldr (\args rest -> text " " :: span [] args :: rest) [] xs + + (maybeIsClosed, openHtml) = + case valueList of + [] -> + ( Nothing, div [] [] ) + + [entry] -> + case entry of + S _ -> + ( Nothing, div [] [] ) + + Primitive _ -> + ( Nothing, div [] [] ) + + Sequence _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewSequenceOpen subValueList) + ) + + Dictionary _ keyValuePairs -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewDictionaryOpen keyValuePairs) + ) + + Record _ record -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewRecordOpen record) + ) + + Constructor _ _ subValueList -> + ( Just isClosed + , if isClosed then div [] [] else VDom.map (Index None 0) (viewConstructorOpen subValueList) + ) + + _ -> + ( Just isClosed + , if isClosed then div [] [] else viewConstructorOpen valueList + ) + in + div [ leftPad maybeKey ] + [ div [ onClick Toggle ] (lineStarter maybeKey maybeIsClosed description) + , openHtml + ] + + +viewConstructorOpen : List Expando -> Node Msg +viewConstructorOpen valueList = + div [] (List.indexedMap viewConstructorEntry valueList) + + +viewConstructorEntry : Int -> Expando -> Node Msg +viewConstructorEntry index value = + VDom.map (Index None index) (view (Just (toString index)) value) + + + +-- VIEW TINY + + +viewTiny : Expando -> ( Int, List (Node msg) ) +viewTiny value = + case value of + S stringRep -> + let + str = + elideMiddle stringRep + in + ( String.length str + , [ span [red] [text str] ] + ) + + Primitive stringRep -> + ( String.length stringRep + , [ span [blue] [text stringRep] ] + ) + + Sequence seqType _ valueList -> + viewTinyHelp <| + seqTypeToString (List.length valueList) seqType + + Dictionary _ keyValuePairs -> + viewTinyHelp <| + "Dict(" ++ toString (List.length keyValuePairs) ++ ")" + + Record _ record -> + viewTinyRecord record + + Constructor maybeName _ [] -> + viewTinyHelp <| + Maybe.withDefault "Unit" maybeName + + Constructor maybeName _ valueList -> + viewTinyHelp <| + case maybeName of + Nothing -> + "Tuple(" ++ toString (List.length valueList) ++ ")" + + Just name -> + name ++ " …" + + +viewTinyHelp : String -> ( Int, List (Node msg) ) +viewTinyHelp str = + ( String.length str, [text str] ) + + +elideMiddle : String -> String +elideMiddle str = + if String.length str <= 18 then + str + + else + String.left 8 str ++ "..." ++ String.right 8 str + + + +-- VIEW TINY RECORDS + + +viewTinyRecord : Dict String Expando -> ( Int, List (Node msg) ) +viewTinyRecord record = + if Dict.isEmpty record then + ( 2, [text "{}"] ) + + else + viewTinyRecordHelp 0 "{ " (Dict.toList record) + + +viewTinyRecordHelp : Int -> String -> List (String, Expando) -> ( Int, List (Node msg) ) +viewTinyRecordHelp length starter entries = + case entries of + [] -> + ( length + 2, [ text " }" ] ) + + (field, value) :: rest -> + let + fieldLen = + String.length field + + (valueLen, valueNodes) = + viewExtraTiny value + + newLength = + length + fieldLen + valueLen + 5 + in + if newLength > 60 then + ( length + 4, [text ", … }"] ) + + else + let + ( finalLength, otherNodes ) = + viewTinyRecordHelp newLength ", " rest + in + ( finalLength + , text starter + :: span [purple] [text field] + :: text " = " + :: span [] valueNodes + :: otherNodes + ) + + +viewExtraTiny : Expando -> ( Int, List (Node msg) ) +viewExtraTiny value = + case value of + Record _ record -> + viewExtraTinyRecord 0 "{" (Dict.keys record) + + _ -> + viewTiny value + + +viewExtraTinyRecord : Int -> String -> List String -> ( Int, List (Node msg) ) +viewExtraTinyRecord length starter entries = + case entries of + [] -> + ( length + 1, [text "}"] ) + + field :: rest -> + let + nextLength = + length + String.length field + 1 + in + if nextLength > 18 then + ( length + 2, [text "…}"]) + + else + let + (finalLength, otherNodes) = + viewExtraTinyRecord nextLength "," rest + in + ( finalLength + , text starter :: span [purple] [text field] :: otherNodes + ) + + + +-- VIEW HELPERS + + +lineStarter : Maybe String -> Maybe Bool -> List (Node msg) -> List (Node msg) +lineStarter maybeKey maybeIsClosed description = + let + arrow = + case maybeIsClosed of + Nothing -> + makeArrow "" + + Just True -> + makeArrow "▸" + + Just False -> + makeArrow "▾" + in + case maybeKey of + Nothing -> + arrow :: description + + Just key -> + arrow :: span [purple] [text key] :: text " = " :: description + + +makeArrow : String -> Node msg +makeArrow arrow = + span + [ VDom.style + [ ("color", "#777") + , ("padding-left", "2ch") + , ("width", "2ch") + , ("display", "inline-block") + ] + ] + [ text arrow ] + + +leftPad : Maybe a -> VDom.Property msg +leftPad maybeKey = + case maybeKey of + Nothing -> + VDom.style [] + + Just _ -> + VDom.style [("padding-left", "4ch")] + + +red : VDom.Property msg +red = + VDom.style [("color", "rgb(196, 26, 22)")] + + +blue : VDom.Property msg +blue = + VDom.style [("color", "rgb(28, 0, 207)")] + + +purple : VDom.Property msg +purple = + VDom.style [("color", "rgb(136, 19, 145)")] diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm new file mode 100644 index 0000000..104e23b --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Helpers.elm @@ -0,0 +1,137 @@ +module VirtualDom.Helpers exposing + ( Node + , text, node, div, span, a, h1 + , Property, property, attribute + , class, id, href + , style + , on, onWithOptions, Options, defaultOptions + , onClick + , map + , lazy, lazy2, lazy3 + , keyedNode + ) + + +import Json.Decode as Decode +import Json.Encode as Encode +import Native.VirtualDom + + +type Node msg = Node + + +node : String -> List (Property msg) -> List (Node msg) -> Node msg +node = + Native.VirtualDom.node + + +text : String -> Node msg +text = + Native.VirtualDom.text + + +div : List (Property msg) -> List (Node msg) -> Node msg +div = + node "div" + + +span : List (Property msg) -> List (Node msg) -> Node msg +span = + node "span" + + +a : List (Property msg) -> List (Node msg) -> Node msg +a = + node "a" + + +h1 : List (Property msg) -> List (Node msg) -> Node msg +h1 = + node "h1" + + +map : (a -> msg) -> Node a -> Node msg +map = + Native.VirtualDom.map + + +type Property msg = Property + + +property : String -> Decode.Value -> Property msg +property = + Native.VirtualDom.property + + +attribute : String -> String -> Property msg +attribute = + Native.VirtualDom.attribute + + +class : String -> Property msg +class name = + property "className" (Encode.string name) + + +href : String -> Property msg +href name = + property "href" (Encode.string name) + + +id : String -> Property msg +id = + attribute "id" + + +style : List (String, String) -> Property msg +style = + Native.VirtualDom.style + + +on : String -> Decode.Decoder msg -> Property msg +on eventName decoder = + onWithOptions eventName defaultOptions decoder + + +onClick : msg -> Property msg +onClick msg = + on "click" (Decode.succeed msg) + + +onWithOptions : String -> Options -> Decode.Decoder msg -> Property msg +onWithOptions = + Native.VirtualDom.on + + +type alias Options = + { stopPropagation : Bool + , preventDefault : Bool + } + + +defaultOptions : Options +defaultOptions = + { stopPropagation = False + , preventDefault = False + } + + +lazy : (a -> Node msg) -> a -> Node msg +lazy = + Native.VirtualDom.lazy + + +lazy2 : (a -> b -> Node msg) -> a -> b -> Node msg +lazy2 = + Native.VirtualDom.lazy2 + + +lazy3 : (a -> b -> c -> Node msg) -> a -> b -> c -> Node msg +lazy3 = + Native.VirtualDom.lazy3 + + +keyedNode : String -> List (Property msg) -> List ( String, Node msg ) -> Node msg +keyedNode = + Native.VirtualDom.keyedNode + diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm new file mode 100644 index 0000000..bd9a28d --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/History.elm @@ -0,0 +1,290 @@ +module VirtualDom.History exposing + ( History + , empty + , size + , initialModel + , add + , get + , view + , decoder + , encode + ) + + +import Array exposing (Array) +import Json.Decode as Decode +import Json.Encode as Encode +import Native.Debug +import VirtualDom.Helpers as VDom exposing (Node) +import VirtualDom.Metadata as Metadata + + + +-- CONSTANTS + + +maxSnapshotSize : Int +maxSnapshotSize = + 64 + + + +-- HISTORY + + +type alias History model msg = + { snapshots : Array (Snapshot model msg) + , recent : RecentHistory model msg + , numMessages : Int + } + + +type alias RecentHistory model msg = + { model : model + , messages : List msg + , numMessages : Int + } + + +type alias Snapshot model msg = + { model : model + , messages : Array msg + } + + +empty : model -> History model msg +empty model = + History Array.empty (RecentHistory model [] 0) 0 + + +size : History model msg -> Int +size history = + history.numMessages + + +initialModel : History model msg -> model +initialModel { snapshots, recent } = + case Array.get 0 snapshots of + Just { model } -> + model + + Nothing -> + recent.model + + + +-- JSON + + +decoder : model -> (msg -> model -> model) -> Decode.Decoder (model, History model msg) +decoder initialModel update = + let + addMessage rawMsg (model, history) = + let + msg = + jsToElm rawMsg + in + (update msg model, add msg model history) + + updateModel rawMsgs = + List.foldl addMessage (initialModel, empty initialModel) rawMsgs + in + Decode.map updateModel (Decode.list Decode.value) + + +jsToElm : Encode.Value -> a +jsToElm = + Native.Debug.unsafeCoerce + + +encode : History model msg -> Encode.Value +encode { snapshots, recent } = + let + recentJson = + List.map elmToJs (List.reverse recent.messages) + in + Encode.list <| Array.foldr encodeHelp recentJson snapshots + + +encodeHelp : Snapshot model msg -> List Encode.Value -> List Encode.Value +encodeHelp snapshot allMessages = + Array.foldl (\elm msgs -> elmToJs elm :: msgs) allMessages snapshot.messages + + +elmToJs : a -> Encode.Value +elmToJs = + Native.Debug.unsafeCoerce + + + +-- ADD MESSAGES + + +add : msg -> model -> History model msg -> History model msg +add msg model { snapshots, recent, numMessages } = + case addRecent msg model recent of + (Just snapshot, newRecent) -> + History (Array.push snapshot snapshots) newRecent (numMessages + 1) + + (Nothing, newRecent) -> + History snapshots newRecent (numMessages + 1) + + +addRecent + : msg + -> model + -> RecentHistory model msg + -> ( Maybe (Snapshot model msg), RecentHistory model msg ) +addRecent msg newModel { model, messages, numMessages } = + if numMessages == maxSnapshotSize then + ( Just (Snapshot model (Array.fromList messages)) + , RecentHistory newModel [msg] 1 + ) + + else + ( Nothing + , RecentHistory model (msg :: messages) (numMessages + 1) + ) + + + +-- GET SUMMARY + + +get : (msg -> model -> (model, a)) -> Int -> History model msg -> ( model, msg ) +get update index { snapshots, recent, numMessages } = + let + snapshotMax = + numMessages - recent.numMessages + in + if index >= snapshotMax then + undone <| + List.foldr (getHelp update) (Stepping (index - snapshotMax) recent.model) recent.messages + + else + case Array.get (index // maxSnapshotSize) snapshots of + Nothing -> + Debug.crash "UI should only let you ask for real indexes!" + + Just { model, messages } -> + undone <| + Array.foldr (getHelp update) (Stepping (rem index maxSnapshotSize) model) messages + + +type GetResult model msg + = Stepping Int model + | Done msg model + + +getHelp : (msg -> model -> (model, a)) -> msg -> GetResult model msg -> GetResult model msg +getHelp update msg getResult = + case getResult of + Done _ _ -> + getResult + + Stepping n model -> + if n == 0 then + Done msg (Tuple.first (update msg model)) + + else + Stepping (n - 1) (Tuple.first (update msg model)) + + +undone : GetResult model msg -> ( model, msg ) +undone getResult = + case getResult of + Done msg model -> + ( model, msg ) + + Stepping _ _ -> + Debug.crash "Bug in History.get" + + + +-- VIEW + + +view : Maybe Int -> History model msg -> Node Int +view maybeIndex { snapshots, recent, numMessages } = + let + (index, className) = + case maybeIndex of + Nothing -> + ( -1, "debugger-sidebar-messages" ) + Just i -> + ( i, "debugger-sidebar-messages-paused" ) + + oldStuff = + VDom.lazy2 viewSnapshots index snapshots + + newStuff = + Tuple.second <| List.foldl (consMsg index) (numMessages - 1, []) recent.messages + in + VDom.div [ VDom.class className ] (oldStuff :: newStuff) + + + +-- VIEW SNAPSHOTS + + +viewSnapshots : Int -> Array (Snapshot model msg) -> Node Int +viewSnapshots currentIndex snapshots = + let + highIndex = + maxSnapshotSize * Array.length snapshots + in + VDom.div [] <| Tuple.second <| + Array.foldr (consSnapshot currentIndex) (highIndex, []) snapshots + + +consSnapshot : Int -> Snapshot model msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consSnapshot currentIndex snapshot (index, rest) = + let + nextIndex = + index - maxSnapshotSize + + currentIndexHelp = + if nextIndex <= currentIndex && currentIndex < index then currentIndex else -1 + in + ( index - maxSnapshotSize + , VDom.lazy3 viewSnapshot currentIndexHelp index snapshot :: rest + ) + + +viewSnapshot : Int -> Int -> Snapshot model msg -> Node Int +viewSnapshot currentIndex index { messages } = + VDom.div [] <| Tuple.second <| + Array.foldl (consMsg currentIndex) (index - 1, []) messages + + + +-- VIEW MESSAGE + + +consMsg : Int -> msg -> ( Int, List (Node Int) ) -> ( Int, List (Node Int) ) +consMsg currentIndex msg (index, rest) = + ( index - 1 + , VDom.lazy3 viewMessage currentIndex index msg :: rest + ) + + +viewMessage : Int -> Int -> msg -> Node Int +viewMessage currentIndex index msg = + let + className = + if currentIndex == index then + "messages-entry messages-entry-selected" + + else + "messages-entry" + + messageName = + Native.Debug.messageToString msg + in + VDom.div + [ VDom.class className + , VDom.on "click" (Decode.succeed index) + ] + [ VDom.span [VDom.class "messages-entry-content", VDom.attribute "title" messageName ] [ VDom.text messageName ] + , VDom.span [VDom.class "messages-entry-index"] [ VDom.text (toString index) ] + ] diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm new file mode 100644 index 0000000..74e7316 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Metadata.elm @@ -0,0 +1,326 @@ +module VirtualDom.Metadata exposing + ( Metadata + , check + , decode, decoder, encode + , Error, ProblemType, Problem(..) + ) + + +import Array exposing (Array) +import Dict exposing (Dict) +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Report as Report exposing (Report) + + + +-- METADATA + + +type alias Metadata = + { versions : Versions + , types : Types + } + + + +-- VERSIONS + + +type alias Versions = + { elm : String + } + + + +-- TYPES + + +type alias Types = + { message : String + , aliases : Dict String Alias + , unions : Dict String Union + } + + +type alias Alias = + { args : List String + , tipe : String + } + + +type alias Union = + { args : List String + , tags : Dict String (List String) + } + + + +-- PORTABILITY + + +isPortable : Metadata -> Maybe Error +isPortable {types} = + let + badAliases = + Dict.foldl collectBadAliases [] types.aliases + in + case Dict.foldl collectBadUnions badAliases types.unions of + [] -> + Nothing + + problems -> + Just (Error types.message problems) + + +type alias Error = + { message : String + , problems : List ProblemType + } + + +type alias ProblemType = + { name : String + , problems : List Problem + } + + +type Problem + = Function + | Decoder + | Task + | Process + | Socket + | Request + | Program + | VirtualDom + + +collectBadAliases : String -> Alias -> List ProblemType -> List ProblemType +collectBadAliases name {tipe} list = + case findProblems tipe of + [] -> + list + + problems -> + ProblemType name problems :: list + + +collectBadUnions : String -> Union -> List ProblemType -> List ProblemType +collectBadUnions name {tags} list = + case List.concatMap findProblems (List.concat (Dict.values tags)) of + [] -> + list + + problems -> + ProblemType name problems :: list + + +findProblems : String -> List Problem +findProblems tipe = + List.filterMap (hasProblem tipe) problemTable + + +hasProblem : String -> (Problem, String) -> Maybe Problem +hasProblem tipe (problem, token) = + if String.contains token tipe then Just problem else Nothing + + +problemTable : List (Problem, String) +problemTable = + [ ( Function, "->" ) + , ( Decoder, "Json.Decode.Decoder" ) + , ( Task, "Task.Task" ) + , ( Process, "Process.Id" ) + , ( Socket, "WebSocket.LowLevel.WebSocket" ) + , ( Request, "Http.Request" ) + , ( Program, "Platform.Program" ) + , ( VirtualDom, "VirtualDom.Node" ) + , ( VirtualDom, "VirtualDom.Attribute" ) + ] + + + +-- CHECK + + +check : Metadata -> Metadata -> Report +check old new = + if old.versions.elm /= new.versions.elm then + Report.VersionChanged old.versions.elm new.versions.elm + + else + checkTypes old.types new.types + + +checkTypes : Types -> Types -> Report +checkTypes old new = + if old.message /= new.message then + Report.MessageChanged old.message new.message + + else + [] + |> Dict.merge ignore checkAlias ignore old.aliases new.aliases + |> Dict.merge ignore checkUnion ignore old.unions new.unions + |> Report.SomethingChanged + + +ignore : String -> value -> a -> a +ignore key value report = + report + + + +-- CHECK ALIASES + + +checkAlias : String -> Alias -> Alias -> List Report.Change -> List Report.Change +checkAlias name old new changes = + if old.tipe == new.tipe && old.args == new.args then + changes + + else + Report.AliasChange name :: changes + + + +-- CHECK UNIONS + + +checkUnion : String -> Union -> Union -> List Report.Change -> List Report.Change +checkUnion name old new changes = + let + tagChanges = + Dict.merge removeTag checkTag addTag old.tags new.tags <| + Report.emptyTagChanges (old.args == new.args) + in + if Report.hasTagChanges tagChanges then + changes + + else + Report.UnionChange name tagChanges :: changes + + +removeTag : String -> a -> Report.TagChanges -> Report.TagChanges +removeTag tag _ changes = + { changes | removed = tag :: changes.removed } + + +addTag : String -> a -> Report.TagChanges -> Report.TagChanges +addTag tag _ changes = + { changes | added = tag :: changes.added } + + +checkTag : String -> a -> a -> Report.TagChanges -> Report.TagChanges +checkTag tag old new changes = + if old == new then + changes + + else + { changes | changed = tag :: changes.changed } + + + +-- JSON DECODE + + +decode : Encode.Value -> Result Error Metadata +decode value = + case Decode.decodeValue decoder value of + Err _ -> + Debug.crash "Compiler is generating bad metadata. Report this at ." + + Ok metadata -> + case isPortable metadata of + Nothing -> + Ok metadata + + Just error -> + Err error + + +decoder : Decode.Decoder Metadata +decoder = + Decode.map2 Metadata + (Decode.field "versions" decodeVersions) + (Decode.field "types" decodeTypes) + + +decodeVersions : Decode.Decoder Versions +decodeVersions = + Decode.map Versions + (Decode.field "elm" Decode.string) + + +decodeTypes : Decode.Decoder Types +decodeTypes = + Decode.map3 Types + (Decode.field "message" Decode.string) + (Decode.field "aliases" (Decode.dict decodeAlias)) + (Decode.field "unions" (Decode.dict decodeUnion)) + + +decodeUnion : Decode.Decoder Union +decodeUnion = + Decode.map2 Union + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "tags" (Decode.dict (Decode.list Decode.string))) + + +decodeAlias : Decode.Decoder Alias +decodeAlias = + Decode.map2 Alias + (Decode.field "args" (Decode.list Decode.string)) + (Decode.field "type" (Decode.string)) + + + +-- JSON ENCODE + + +encode : Metadata -> Encode.Value +encode { versions, types } = + Encode.object + [ ("versions", encodeVersions versions) + , ("types", encodeTypes types) + ] + + +encodeVersions : Versions -> Encode.Value +encodeVersions { elm } = + Encode.object [("elm", Encode.string elm)] + + +encodeTypes : Types -> Encode.Value +encodeTypes { message, unions, aliases } = + Encode.object + [ ("message", Encode.string message) + , ("aliases", encodeDict encodeAlias aliases) + , ("unions", encodeDict encodeUnion unions) + ] + + +encodeAlias : Alias -> Encode.Value +encodeAlias { args, tipe } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("type", Encode.string tipe) + ] + + +encodeUnion : Union -> Encode.Value +encodeUnion { args, tags } = + Encode.object + [ ("args", Encode.list (List.map Encode.string args)) + , ("tags", encodeDict (Encode.list << List.map Encode.string) tags) + ] + + +encodeDict : (a -> Encode.Value) -> Dict String a -> Encode.Value +encodeDict f dict = + dict + |> Dict.map (\key value -> f value) + |> Dict.toList + |> Encode.object + + diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm new file mode 100644 index 0000000..9e6bd2e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Overlay.elm @@ -0,0 +1,541 @@ +module VirtualDom.Overlay exposing + ( State, none, corruptImport, badMetadata + , Msg, close, assessImport + , isBlocking + , Config + , Block + , view + , viewImportExport + ) + +import Json.Decode as Decode +import Json.Encode as Encode +import VirtualDom.Helpers exposing (..) +import VirtualDom.Metadata as Metadata exposing (Metadata) +import VirtualDom.Report as Report exposing (Report) + + + +type State + = None + | BadMetadata Metadata.Error + | BadImport Report + | RiskyImport Report Encode.Value + + +none : State +none = + None + + +corruptImport : State +corruptImport = + BadImport Report.CorruptHistory + + +badMetadata : Metadata.Error -> State +badMetadata = + BadMetadata + + +isBlocking : State -> Bool +isBlocking state = + case state of + None -> + False + + _ -> + True + + + +-- UPDATE + + +type Msg = Cancel | Proceed + + +close : Msg -> State -> Maybe Encode.Value +close msg state = + case state of + None -> + Nothing + + BadMetadata _ -> + Nothing + + BadImport _ -> + Nothing + + RiskyImport _ rawHistory -> + case msg of + Cancel -> + Nothing + + Proceed -> + Just rawHistory + + +assessImport : Metadata -> String -> Result State Encode.Value +assessImport metadata jsonString = + case Decode.decodeString uploadDecoder jsonString of + Err _ -> + Err corruptImport + + Ok (foreignMetadata, rawHistory) -> + let + report = + Metadata.check foreignMetadata metadata + in + case Report.evaluate report of + Report.Impossible -> + Err (BadImport report) + + Report.Risky -> + Err (RiskyImport report rawHistory) + + Report.Fine -> + Ok rawHistory + + +uploadDecoder : Decode.Decoder (Metadata, Encode.Value) +uploadDecoder = + Decode.map2 (,) + (Decode.field "metadata" Metadata.decoder) + (Decode.field "history" Decode.value) + + + +-- VIEW + + +type alias Config msg = + { resume : msg + , open : msg + , importHistory : msg + , exportHistory : msg + , wrap : Msg -> msg + } + + +type Block = Normal | Pause | Message + + +view : Config msg -> Bool -> Bool -> Int -> State -> ( Block, Node msg ) +view config isPaused isOpen numMsgs state = + let + (block, nodes) = + viewHelp config isPaused isOpen numMsgs state + in + ( block + , div [ class "elm-overlay" ] (styles :: nodes) + ) + + +viewHelp : Config msg -> Bool -> Bool -> Int -> State -> ( Block, List (Node msg) ) +viewHelp config isPaused isOpen numMsgs state = + case state of + None -> + let + miniControls = + if isOpen then [] else [ viewMiniControls config numMsgs ] + in + ( if isPaused then Pause else Normal + , if isPaused && not isOpen then + viewResume config :: miniControls + else + miniControls + ) + + BadMetadata badMetadata -> + viewMessage config + "Cannot use Import or Export" + (viewBadMetadata badMetadata) + (Accept "Ok") + + BadImport report -> + viewMessage config + "Cannot Import History" + (viewReport True report) + (Accept "Ok") + + RiskyImport report _ -> + viewMessage config + "Warning" + (viewReport False report) + (Choose "Cancel" "Import Anyway") + + +viewResume config = + div [ class "elm-overlay-resume", onClick config.resume ] + [ div [class "elm-overlay-resume-words"] [text "Click to Resume"] ] + + + +-- VIEW MESSAGE + + +viewMessage : Config msg -> String -> List (Node msg) -> Buttons -> ( Block, List (Node msg) ) +viewMessage config title details buttons = + ( Message + , [ div [ class "elm-overlay-message" ] + [ div [ class "elm-overlay-message-title" ] [ text title ] + , div [ class "elm-overlay-message-details" ] details + , map config.wrap (viewButtons buttons) + ] + ] + ) + + +viewReport : Bool -> Report -> List (Node msg) +viewReport isBad report = + case report of + Report.CorruptHistory -> + [ text "Looks like this history file is corrupt. I cannot understand it." + ] + + Report.VersionChanged old new -> + [ text <| + "This history was created with Elm " + ++ old ++ ", but you are using Elm " + ++ new ++ " right now." + ] + + Report.MessageChanged old new -> + [ text <| + "To import some other history, the overall message type must" + ++ " be the same. The old history has " + , viewCode old + , text " messages, but the new program works with " + , viewCode new + , text " messages." + ] + + Report.SomethingChanged changes -> + [ node "p" [] [ text (if isBad then explanationBad else explanationRisky) ] + , node "ul" [] (List.map viewChange changes) + ] + + +explanationBad : String +explanationBad = """ +The messages in this history do not match the messages handled by your +program. I noticed changes in the following types: +""" + +explanationRisky : String +explanationRisky = """ +This history seems old. It will work with this program, but some +messages have been added since the history was created: +""" + + +viewCode : String -> Node msg +viewCode name = + node "code" [] [ text name ] + + +viewChange : Report.Change -> Node msg +viewChange change = + node "li" [] <| + case change of + Report.AliasChange name -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + ] + + Report.UnionChange name { removed, changed, added, argsMatch } -> + [ span [ class "elm-overlay-message-details-type" ] [ viewCode name ] + , node "ul" [] + [ viewMention removed "Removed " + , viewMention changed "Changed " + , viewMention added "Added " + ] + , if argsMatch then + text "" + else + text "This may be due to the fact that the type variable names changed." + ] + + +viewMention : List String -> String -> Node msg +viewMention tags verbed = + case List.map viewCode (List.reverse tags) of + [] -> + text "" + + [tag] -> + node "li" [] + [ text verbed, tag, text "." ] + + [tag2, tag1] -> + node "li" [] + [ text verbed, tag1, text " and ", tag2, text "." ] + + lastTag :: otherTags -> + node "li" [] <| + text verbed + :: List.intersperse (text ", ") (List.reverse otherTags) + ++ [ text ", and ", lastTag, text "." ] + + +viewBadMetadata : Metadata.Error -> List (Node msg) +viewBadMetadata {message, problems} = + [ node "p" [] + [ text "The " + , viewCode message + , text " type of your program cannot be reliably serialized for history files." + ] + , node "p" [] [ text "Functions cannot be serialized, nor can values that contain functions. This is a problem in these places:" ] + , node "ul" [] (List.map viewProblemType problems) + , node "p" [] + [ text goodNews1 + , a [ href "https://guide.elm-lang.org/types/union_types.html" ] [ text "union types" ] + , text ", in your messages. From there, your " + , viewCode "update" + , text goodNews2 + ] + ] + + +goodNews1 = """ +The good news is that having values like this in your message type is not +so great in the long run. You are better off using simpler data, like +""" + + +goodNews2 = """ +function can pattern match on that data and call whatever functions, JSON +decoders, etc. you need. This makes the code much more explicit and easy to +follow for other readers (or you in a few months!) +""" + + +viewProblemType : Metadata.ProblemType -> Node msg +viewProblemType { name, problems } = + node "li" [] + [ viewCode name + , text (" can contain " ++ addCommas (List.map problemToString problems) ++ ".") + ] + + +problemToString : Metadata.Problem -> String +problemToString problem = + case problem of + Metadata.Function -> + "functions" + + Metadata.Decoder -> + "JSON decoders" + + Metadata.Task -> + "tasks" + + Metadata.Process -> + "processes" + + Metadata.Socket -> + "web sockets" + + Metadata.Request -> + "HTTP requests" + + Metadata.Program -> + "programs" + + Metadata.VirtualDom -> + "virtual DOM values" + + +addCommas : List String -> String +addCommas items = + case items of + [] -> + "" + + [item] -> + item + + [item1, item2] -> + item1 ++ " and " ++ item2 + + lastItem :: otherItems -> + String.join ", " (otherItems ++ [ " and " ++ lastItem ]) + + + +-- VIEW MESSAGE BUTTONS + + +type Buttons + = Accept String + | Choose String String + + +viewButtons : Buttons -> Node Msg +viewButtons buttons = + div [ class "elm-overlay-message-buttons" ] <| + case buttons of + Accept proceed -> + [ node "button" [ onClick Proceed ] [ text proceed ] + ] + + Choose cancel proceed -> + [ node "button" [ onClick Cancel ] [ text cancel ] + , node "button" [ onClick Proceed ] [ text proceed ] + ] + + + +-- VIEW MINI CONTROLS + + +viewMiniControls : Config msg -> Int -> Node msg +viewMiniControls config numMsgs = + div + [ class "elm-mini-controls" + ] + [ div + [ onClick config.open + , class "elm-mini-controls-button" + ] + [ text ("Explore History (" ++ toString numMsgs ++ ")") + ] + , viewImportExport + [class "elm-mini-controls-import-export"] + config.importHistory + config.exportHistory + ] + + +viewImportExport : List (Property msg) -> msg -> msg -> Node msg +viewImportExport props importMsg exportMsg = + div + props + [ button importMsg "Import" + , text " / " + , button exportMsg "Export" + ] + + +button : msg -> String -> Node msg +button msg label = + span [ onClick msg, style [("cursor","pointer")] ] [ text label ] + + + +-- STYLE + + +styles : Node msg +styles = + node "style" [] [ text """ + +.elm-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + color: white; + pointer-events: none; + font-family: 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif; +} + +.elm-overlay-resume { + width: 100%; + height: 100%; + cursor: pointer; + text-align: center; + pointer-events: auto; + background-color: rgba(200, 200, 200, 0.7); +} + +.elm-overlay-resume-words { + position: absolute; + top: calc(50% - 40px); + font-size: 80px; + line-height: 80px; + height: 80px; + width: 100%; +} + +.elm-mini-controls { + position: fixed; + bottom: 0; + right: 6px; + border-radius: 4px; + background-color: rgb(61, 61, 61); + font-family: monospace; + pointer-events: auto; +} + +.elm-mini-controls-button { + padding: 6px; + cursor: pointer; + text-align: center; + min-width: 24ch; +} + +.elm-mini-controls-import-export { + padding: 4px 0; + font-size: 0.8em; + text-align: center; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message { + position: absolute; + width: 600px; + height: 100%; + padding-left: calc(50% - 300px); + padding-right: calc(50% - 300px); + background-color: rgba(200, 200, 200, 0.7); + pointer-events: auto; +} + +.elm-overlay-message-title { + font-size: 36px; + height: 80px; + background-color: rgb(50, 50, 50); + padding-left: 22px; + vertical-align: middle; + line-height: 80px; +} + +.elm-overlay-message-details { + padding: 8px 20px; + overflow-y: auto; + max-height: calc(100% - 156px); + background-color: rgb(61, 61, 61); +} + +.elm-overlay-message-details-type { + font-size: 1.5em; +} + +.elm-overlay-message-details ul { + list-style-type: none; + padding-left: 20px; +} + +.elm-overlay-message-details ul ul { + list-style-type: disc; + padding-left: 2em; +} + +.elm-overlay-message-details li { + margin: 8px 0; +} + +.elm-overlay-message-buttons { + height: 60px; + line-height: 60px; + text-align: right; + background-color: rgb(50, 50, 50); +} + +.elm-overlay-message-buttons button { + margin-right: 20px; +} + +""" ] \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm new file mode 100644 index 0000000..89b4e07 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/src/VirtualDom/Report.elm @@ -0,0 +1,99 @@ +module VirtualDom.Report exposing + ( Report(..) + , Change(..) + , TagChanges + , emptyTagChanges + , hasTagChanges + , Status(..), evaluate + ) + + + +-- REPORTS + + +type Report + = CorruptHistory + | VersionChanged String String + | MessageChanged String String + | SomethingChanged (List Change) + + +type Change + = AliasChange String + | UnionChange String TagChanges + + +type alias TagChanges = + { removed : List String + , changed : List String + , added : List String + , argsMatch : Bool + } + + +emptyTagChanges : Bool -> TagChanges +emptyTagChanges argsMatch = + TagChanges [] [] [] argsMatch + + +hasTagChanges : TagChanges -> Bool +hasTagChanges tagChanges = + tagChanges == TagChanges [] [] [] True + + +type Status = Impossible | Risky | Fine + + +evaluate : Report -> Status +evaluate report = + case report of + CorruptHistory -> + Impossible + + VersionChanged _ _ -> + Impossible + + MessageChanged _ _ -> + Impossible + + SomethingChanged changes -> + worstCase Fine (List.map evaluateChange changes) + + +worstCase : Status -> List Status -> Status +worstCase status statusList = + case statusList of + [] -> + status + + Impossible :: _ -> + Impossible + + Risky :: rest -> + worstCase Risky rest + + Fine :: rest -> + worstCase status rest + + +evaluateChange : Change -> Status +evaluateChange change = + case change of + AliasChange _ -> + Impossible + + UnionChange _ { removed, changed, added, argsMatch } -> + if not argsMatch || some changed || some removed then + Impossible + + else if some added then + Risky + + else + Fine + + +some : List a -> Bool +some list = + not (List.isEmpty list) diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js new file mode 100644 index 0000000..6b1ebbb --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/Native/TestHelpers.js @@ -0,0 +1,35 @@ +Elm.Native.TestHelpers = {}; +Elm.Native.TestHelpers.make = function(localRuntime) +{ + localRuntime.Native = localRuntime.Native || {}; + localRuntime.Native.TestHelpers = localRuntime.Native.TestHelpers || {}; + if (localRuntime.Native.TestHelpers.values) + { + return localRuntime.Native.TestHelpers.values; + } + + var VirtualDom = Elm.Native.VirtualDom.make(localRuntime); + + function unsafeRecordCallCount(f) { + function wrapper(a) { + wrapper.__elm_test_call_count += 1; + return f(a); + } + wrapper.__elm_test_call_count = 0; + return wrapper; + } + + function unsafeQueryCallCount(f) { + if (f.__elm_test_call_count === undefined) { + return -1; + } + return f.__elm_test_call_count; + } + + Elm.Native.TestHelpers.values = { + unsafeRecordCallCount: unsafeRecordCallCount, + unsafeQueryCallCount: unsafeQueryCallCount, + updateAndReplace: F3(VirtualDom.updateAndReplace) + }; + return localRuntime.Native.TestHelpers.values = Elm.Native.TestHelpers.values; +}; \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm new file mode 100644 index 0000000..09e362a --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestCases/Lazy.elm @@ -0,0 +1,72 @@ +module TestCases.Lazy where + +import VirtualDom exposing (Node, lazy) +import ElmTest.Assertion exposing (assertEqual) +import ElmTest.Test exposing (Test, suite, test) + +import TestHelpers exposing (renderDom, updateDom, unsafeRecordCallCount, unsafeQueryCallCount) + +renderRecord : { x: String, y: String } -> Node +renderRecord r = + VirtualDom.text <| "The values: " ++ r.x ++ ", " ++ r.y + + +renderPrimitive : Int -> Node +renderPrimitive x = + VirtualDom.text <| "The value: " ++ (toString x) + + +testLazyIdenticalRecord = + test "isn't called again with identical record" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender record + v3 = updateDom v2 <| lazy wrappedRender record + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyIdenticalPrimitive = + test "isn't called again with identical primitive" <| + let wrappedRender = unsafeRecordCallCount renderPrimitive + v1 = renderDom <| lazy wrappedRender 5 + v2 = updateDom v1 <| lazy wrappedRender 5 + v3 = updateDom v2 <| lazy wrappedRender 5 + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testLazyRecordMutationOfIdenticalValue = + test "isn't called again with record mutation of identical value" <| + let record = { x = "a", y = "b" } + wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender record + v2 = updateDom v1 <| lazy wrappedRender { record | x = "a" } + v3 = updateDom v2 <| lazy wrappedRender { record | x = "a", y = "b" } + in + assertEqual 1 <| unsafeQueryCallCount wrappedRender + + +testNotLazyDifferentRecord = + test "is called again with an equivalent but different record" <| + let wrappedRender = unsafeRecordCallCount renderRecord + v1 = renderDom <| lazy wrappedRender { x = "a", y = "b" } + v2 = updateDom v1 <| lazy wrappedRender { x = "a", y = "b" } + v3 = updateDom v2 <| lazy wrappedRender { x = "a", y = "b" } + in + assertEqual 3 <| unsafeQueryCallCount wrappedRender + + +tests : Test +tests = + suite + "Lazy" + [ + testLazyIdenticalRecord, + testLazyIdenticalPrimitive, + -- Re-enable this test when core supports checking + -- record update values for identity before copying: + -- testLazyRecordMutationOfIdenticalValue, + testNotLazyDifferentRecord + ] diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm new file mode 100644 index 0000000..2fe24cf --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestHelpers.elm @@ -0,0 +1,34 @@ +module TestHelpers where + +import VirtualDom exposing (Node) + +import Native.TestHelpers +import Native.VirtualDom + +unsafeRecordCallCount : (a -> b) -> (a -> b) +unsafeRecordCallCount = + Native.TestHelpers.unsafeRecordCallCount + +unsafeQueryCallCount : (a -> b) -> Int +unsafeQueryCallCount = + Native.TestHelpers.unsafeQueryCallCount + +type OpaqueDom = OpaqueDom + +render : Node -> OpaqueDom +render = + Native.VirtualDom.render + +updateAndReplace : OpaqueDom -> Node -> Node -> OpaqueDom +updateAndReplace = + Native.TestHelpers.updateAndReplace + + +renderDom : Node -> (OpaqueDom, Node) +renderDom vdom = + (render vdom, vdom) + + +updateDom : (OpaqueDom, Node) -> Node -> (OpaqueDom, Node) +updateDom (oldDom, oldVDom) newVDom = + (updateAndReplace oldDom oldVDom newVDom, newVDom) diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm new file mode 100644 index 0000000..ea59abf --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/TestMain.elm @@ -0,0 +1,18 @@ + +import ElmTest.Runner.Console exposing (runDisplay) +import ElmTest.Test exposing (Test, suite) +import Console exposing (IO) +import Task exposing (Task) + +import TestCases.Lazy + +tests : Test +tests = + suite + "VirtualDom Library Tests" + [ + TestCases.Lazy.tests + ] + +port runner : Signal (Task x ()) +port runner = Console.run (runDisplay tests) diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json new file mode 100644 index 0000000..5041954 --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "Test for VirtualDom", + "license": "BSD3", + "repository": "https://github.com/evancz/virtual-dom.git", + "exposed-modules": [], + "source-directories": [ + ".", + "build/virtual-dom/" + ], + "native-modules": true, + "dependencies": { + "elm-lang/core": "2.0.0 <= v < 4.0.0", + "laszlopandy/elm-console": "1.0.0 <= v < 2.0.0", + "deadfoxygrandpa/elm-test": "1.0.3 <= v < 2.0.0" + }, + "elm-version": "0.16.0 <= v < 0.17.0" +} \ No newline at end of file diff --git a/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/run-tests.sh b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/run-tests.sh new file mode 100644 index 0000000..98e4f2e --- /dev/null +++ b/part10/elm-stuff/packages/elm-lang/virtual-dom/2.0.4/tests/run-tests.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +cd "$(dirname "$0")" + +mkdir -p build/virtual-dom/Native +cp ../src/VirtualDom.elm build/virtual-dom/ +$(npm bin)/browserify ../src/wrapper.js -o build/VirtualDom.browser.js + +set +e +diff -u ../src/Native/VirtualDom.js build/VirtualDom.browser.js +if [ $? != 0 ]; then + echo "ERROR:" + echo "src/Native/VirtualDom.js has local modifications or is out of date. Please run rebuild.sh" + exit 1 +fi +set -e + +$(npm bin)/browserify --no-browser-field ../src/wrapper.js -o build/virtual-dom/Native/VirtualDom.js + +elm-make --yes --output build/test.js TestMain.elm +echo "Elm.worker(Elm.Main);" >> build/test.js +node build/test.js \ No newline at end of file diff --git a/part10/tests/Auth.elm b/part10/tests/Auth.elm deleted file mode 100644 index c59f16a..0000000 --- a/part10/tests/Auth.elm +++ /dev/null @@ -1,7 +0,0 @@ -module Auth exposing (token) - - -token : String -token = - -- Tests don't need a real token. - "" diff --git a/part10/tests/HtmlRunner.elm b/part10/tests/HtmlRunner.elm deleted file mode 100644 index 288e39b..0000000 --- a/part10/tests/HtmlRunner.elm +++ /dev/null @@ -1,16 +0,0 @@ -module HtmlRunner exposing (..) - -import Tests -import Test.Runner.Html as Runner - - --- To run this: --- --- cd into part10/test --- elm-reactor --- navigate to HtmlRunner.elm - - -main : Program Never Model Msg -main = - Runner.run Tests.all diff --git a/part10/tests/Main.elm b/part10/tests/Main.elm deleted file mode 100644 index 80906ca..0000000 --- a/part10/tests/Main.elm +++ /dev/null @@ -1,18 +0,0 @@ -port module Main exposing (..) - -import Tests -import Test.Runner.Node as Runner -import Json.Decode exposing (Value) - - --- To run this: --- --- elm-test - - -main : Program Value -main = - Runner.run emit Tests.all - - -port emit : ( String, Value ) -> Cmd msg diff --git a/part10/tests/elm-package.json b/part10/tests/elm-package.json index 460cf01..2809053 100644 --- a/part10/tests/elm-package.json +++ b/part10/tests/elm-package.json @@ -1,21 +1,21 @@ { "version": "1.0.0", - "summary": "Like GitHub, but for Elm stuff.", + "summary": "Test Suites", "repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause", "source-directories": [ - ".", - ".." + "..", + "../..", + "." ], "exposed-modules": [], "dependencies": { - "NoRedInk/elm-decode-pipeline": "1.1.2 <= v < 2.0.0", - "elm-community/elm-test": "2.0.1 <= v < 3.0.0", - "elm-lang/core": "4.0.1 <= v < 5.0.0", - "elm-lang/html": "1.0.0 <= v < 2.0.0", - "evancz/elm-http": "3.0.1 <= v < 4.0.0", - "rtfeldman/html-test-runner": "1.0.0 <= v < 2.0.0", - "rtfeldman/node-test-runner": "2.0.0 <= v < 3.0.0" + "NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0", + "eeue56/elm-html-test": "5.1.1 <= v < 6.0.0", + "elm-community/elm-test": "4.0.0 <= v < 5.0.0", + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0", + "elm-lang/http": "1.0.0 <= v < 2.0.0" }, - "elm-version": "0.17.0 <= v < 0.18.0" + "elm-version": "0.18.0 <= v < 0.19.0" } diff --git a/part10/tests/elm-stuff/exact-dependencies.json b/part10/tests/elm-stuff/exact-dependencies.json new file mode 100644 index 0000000..9152172 --- /dev/null +++ b/part10/tests/elm-stuff/exact-dependencies.json @@ -0,0 +1,15 @@ +{ + "eeue56/elm-html-query": "3.0.0", + "elm-community/elm-test": "4.2.0", + "elm-lang/virtual-dom": "2.0.4", + "eeue56/elm-lazy": "1.0.0", + "mgold/elm-random-pcg": "5.0.2", + "eeue56/elm-lazy-list": "1.0.0", + "elm-lang/html": "2.0.0", + "elm-lang/http": "1.0.0", + "eeue56/elm-shrink": "1.0.0", + "eeue56/elm-html-in-elm": "5.2.0", + "eeue56/elm-html-test": "5.1.1", + "NoRedInk/elm-decode-pipeline": "3.0.0", + "elm-lang/core": "5.1.1" +} \ No newline at end of file diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore new file mode 100644 index 0000000..a594364 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/.gitignore @@ -0,0 +1,4 @@ +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE new file mode 100644 index 0000000..a8e355a --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016, NoRedInk +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of elm-decode-pipeline nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md new file mode 100644 index 0000000..7843d4d --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/README.md @@ -0,0 +1,108 @@ +# elm-decode-pipeline + +A library for building decoders using the pipeline [`(|>)`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Basics#|>) +operator and plain function calls. + +## Motivation + +It's common to decode into a record that has a `type alias`. Here's an example +of this from the [`object3`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Json-Decode#object3) +docs: + +```elm +type alias Job = { name : String, id : Int, completed : Bool } + +point : Decoder Job +point = + object3 Job + ("name" := string) + ("id" := int) + ("completed" := bool) +``` + +This works because a record type alias can be called as a normal function. In +that case it accepts one argument for each field (in whatever order the fields +are declared in the type alias) and then returns an appropriate record built +with those arguments. + +The `objectN` decoders are straightforward, but require manually changing N +whenever the field count changes. This library provides functions designed to +be used with the `|>` operator, with the goal of having decoders that are both +easy to read and easy to modify. + +## Examples + +Here is a decoder built with this library. + +```elm +import Json.Decode exposing (int, string, float, Decoder) +import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded) + + +type alias User = + { id : Int + , email : Maybe String + , name : String + , percentExcited : Float + } + + +userDecoder : Decoder User +userDecoder = + decode User + |> required "id" int + |> required "email" (nullable string) -- `null` decodes to `Nothing` + |> optional "name" string "(fallback if name is `null` or not present)" + |> hardcoded 1.0 +``` + +In this example: + +* `decode` is a synonym for [`succeed`](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Json-Decode#succeed) (it just reads better here) +* `required "id" int` is similar to `("id" := int)` +* `optional` is like `required`, but if the field is either `null` or not present, decoding does not fail; instead it succeeds with the provided fallback value. +* `hardcoded` does not look at the provided JSON, and instead always decodes to the same value. + +You could use this decoder as follows: + +```elm +Json.Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "name": "Sam Sample"} + """ +``` + +The result would be: + +```elm +{ id = 123 +, email = "sam@example.com" +, name = "Sam Sample" +, percentExcited = 1.0 +} +``` + +Alternatively, you could use it like so: + +```elm +Json.Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "percentExcited": "(hardcoded)"} + """ +``` + +In this case, the result would be: + +```elm +{ id = 123 +, email = "sam@example.com" +, name = "(fallback if name not present)" +, percentExcited = 1.0 +} +``` + +--- +[![NoRedInk](https://cloud.githubusercontent.com/assets/1094080/9069346/99522418-3a9d-11e5-8175-1c2bfd7a2ffe.png)][team] +[team]: http://noredink.com/about/team diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json new file mode 100644 index 0000000..06af200 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/elm-package.json @@ -0,0 +1,16 @@ +{ + "version": "3.0.0", + "summary": "A pipeline-friendly library for building JSON decoders.", + "repository": "https://github.com/NoRedInk/elm-decode-pipeline.git", + "license": "BSD-3-Clause", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Json.Decode.Pipeline" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm new file mode 100644 index 0000000..3b83e15 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/examples/Example.elm @@ -0,0 +1,19 @@ +module Example exposing (..) + +import Json.Decode exposing (int, string, float, Decoder) +import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded) + + +type alias User = + { id : Int + , name : String + , percentExcited : Float + } + + +userDecoder : Decoder User +userDecoder = + decode User + |> required "id" int + |> optional "name" string "(fallback if name not present)" + |> hardcoded 1.0 diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm new file mode 100644 index 0000000..15eab71 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/src/Json/Decode/Pipeline.elm @@ -0,0 +1,292 @@ +module Json.Decode.Pipeline exposing (required, requiredAt, optional, optionalAt, resolve, decode, hardcoded, custom) + +{-| # Json.Decode.Pipeline + +Use the `(|>)` operator to build JSON decoders. + +## Decoding fields + +@docs required, requiredAt, optional, optionalAt, hardcoded, custom + +## Beginning and ending pipelines + +@docs decode, resolve + +-} + +import Json.Decode as Decode exposing (Decoder) + + +{-| Decode a required field. + + import Json.Decode exposing (int, string, Decoder) + import Decode.Pipeline exposing (decode, required) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "name" string + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "name": "Sam"} + """ + -- Ok { id = 123, name = "Sam", email = "sam@example.com" } +-} +required : String -> Decoder a -> Decoder (a -> b) -> Decoder b +required key valDecoder decoder = + custom (Decode.field key valDecoder) decoder + + +{-| Decode a required nested field. +-} +requiredAt : List String -> Decoder a -> Decoder (a -> b) -> Decoder b +requiredAt path valDecoder decoder = + custom (Decode.at path valDecoder) decoder + + +{-| Decode a field that may be missing or have a null value. If the field is +missing, then it decodes as the `fallback` value. If the field is present, +then `valDecoder` is used to decode its value. If `valDecoder` fails on a +`null` value, then the `fallback` is used as if the field were missing +entirely. + + import Json.Decode exposing (int, string, null, oneOf, Decoder) + import Decode.Pipeline exposing (decode, required, optional) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> optional "name" string "blah" + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com" } + """ + -- Ok { id = 123, name = "blah", email = "sam@example.com" } + +Because `valDecoder` is given an opportunity to decode `null` values before +resorting to the `fallback`, you can distinguish between missing and `null` +values if you need to: + + userDecoder2 = + decode User + |> required "id" int + |> optional "name" (oneOf [ string, null "NULL" ]) "MISSING" + |> required "email" string + +-} +optional : String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b +optional key valDecoder fallback decoder = + custom (optionalDecoder (Decode.field key Decode.value) valDecoder fallback) decoder + + +{-| Decode an optional nested field. +-} +optionalAt : List String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b +optionalAt path valDecoder fallback decoder = + custom (optionalDecoder (Decode.at path Decode.value) valDecoder fallback) decoder + + +optionalDecoder : Decoder Decode.Value -> Decoder a -> a -> Decoder a +optionalDecoder pathDecoder valDecoder fallback = + let + nullOr decoder = + Decode.oneOf [ decoder, Decode.null fallback ] + + handleResult input = + case Decode.decodeValue pathDecoder input of + Ok rawValue -> + -- The field was present, so now let's try to decode that value. + -- (If it was present but fails to decode, this should and will fail!) + case Decode.decodeValue (nullOr valDecoder) rawValue of + Ok finalResult -> + Decode.succeed finalResult + + Err finalErr -> + Decode.fail finalErr + + Err _ -> + -- The field was not present, so use the fallback. + Decode.succeed fallback + in + Decode.value + |> Decode.andThen handleResult + + +{-| Rather than decoding anything, use a fixed value for the next step in the +pipeline. `harcoded` does not look at the JSON at all. + + import Json.Decode exposing (int, string, Decoder) + import Decode.Pipeline exposing (decode, required) + + + type alias User = + { id : Int + , email : String + , followers : Int + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "email" string + |> hardcoded 0 + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com"} + """ + -- Ok { id = 123, email = "sam@example.com", followers = 0 } +-} +hardcoded : a -> Decoder (a -> b) -> Decoder b +hardcoded = + Decode.succeed >> custom + + +{-| Run the given decoder and feed its result into the pipeline at this point. + +Consider this example. + + import Json.Decode exposing (int, string, at, Decoder) + import Decode.Pipeline exposing (decode, required, custom) + + + type alias User = + { id : Int + , name : String + , email : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> custom (at [ "profile", "name" ] string) + |> required "email" string + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + { + "id": 123, + "email": "sam@example.com", + "profile": {"name": "Sam"} + } + """ + -- Ok { id = 123, name = "Sam", email = "sam@example.com" } +-} +custom : Decoder a -> Decoder (a -> b) -> Decoder b +custom = + Decode.map2 (|>) + + +{-| Convert a `Decoder (Result x a)` into a `Decoder a`. Useful when you want +to perform some custom processing just before completing the decoding operation. + + import Json.Decode exposing (int, string, float, Decoder) + import Decode.Pipeline exposing + (decode, required, resolve) + + + type alias User = + { id : Int + , email : String + } + + + userDecoder : Decoder User + userDecoder = + let + -- toDecoder gets run *after* all the + -- (|> required ...) steps are done. + toDecoder : Int -> String -> Int -> Decoder User + toDecoder id email version = + if version > 2 then + succeed (User id email) + else + fail "This JSON is from a deprecated source. Please upgrade!" + in + decode toDecoder + |> required "id" int + |> required "email" string + |> required "version" int -- version is part of toDecoder, + |> resolve -- but it is not a part of User + + + result : Result String User + result = + Decode.decodeString + userDecoder + """ + {"id": 123, "email": "sam@example.com", "version": 1} + """ + -- Err "This JSON is from a deprecated source. Please upgrade!" +-} +resolve : Decoder (Decoder a) -> Decoder a +resolve = + Decode.andThen identity + + +{-| Begin a decoding pipeline. This is a synonym for [Json.Decode.succeed](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode#succeed), +intended to make things read more clearly. + + import Json.Decode exposing (int, string, float, Decoder) + import Json.Decode.Pipeline exposing (decode, required, optional) + + + type alias User = + { id : Int + , email : String + , name : String + } + + + userDecoder : Decoder User + userDecoder = + decode User + |> required "id" int + |> required "email" string + |> optional "name" string "" +-} +decode : a -> Decoder a +decode = + Decode.succeed diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore new file mode 100644 index 0000000..aee9810 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/.gitignore @@ -0,0 +1 @@ +/elm-stuff/ diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm new file mode 100644 index 0000000..532f8e6 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Main.elm @@ -0,0 +1,19 @@ +port module Main exposing (..) + +{-| +Run the tests with node-test-runner: + +https://github.com/rtfeldman/node-test-runner +-} + +import Tests +import Test.Runner.Node exposing (run) +import Json.Encode exposing (Value) + + +main : Program Never +main = + run emit Tests.all + + +port emit : ( String, Value ) -> Cmd msg diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm new file mode 100644 index 0000000..f4bcaa1 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/Tests.elm @@ -0,0 +1,114 @@ +module Tests exposing (..) + +import Test exposing (..) +import Expect exposing (Expectation) +import Json.Decode.Pipeline + exposing + ( decode + , required + , requiredAt + , optional + , optionalAt + , resolveResult + ) +import Json.Decode exposing (Decoder, string, null) + + +{-| Run some JSON through a Decoder and return the result. +-} +runWith : String -> Decoder a -> Result String a +runWith = + flip Json.Decode.decodeString + + +isError : Result err ok -> Bool +isError result = + case result of + Err _ -> + True + + Ok _ -> + False + + +expectErr : Result err ok -> Expectation +expectErr result = + isError result + |> Expect.true ("Expected an Err but got " ++ toString result) + + +all : Test +all = + describe + "Json.Decode.Pipeline" + [ test "should decode basic example" <| + \() -> + decode (,) + |> required "a" string + |> required "b" string + |> runWith """{"a":"foo","b":"bar"}""" + |> Expect.equal (Ok ( "foo", "bar" )) + , test "should decode requiredAt fields" <| + \() -> + decode (,) + |> requiredAt [ "a" ] string + |> requiredAt [ "b", "c" ] string + |> runWith """{"a":"foo","b":{"c":"bar"}}""" + |> Expect.equal (Ok ( "foo", "bar" )) + , test "should decode optionalAt fields" <| + \() -> + decode (,) + |> optionalAt [ "a", "b" ] string "--" + |> optionalAt [ "x", "y" ] string "--" + |> runWith """{"a":{},"x":{"y":"bar"}}""" + |> Expect.equal (Ok ( "--", "bar" )) + , test "optional succeeds if the field is not present" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"x":"five"}""" + |> Expect.equal (Ok ( "--", "five" )) + , test "optional succeeds with fallback if the field is present but null" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"a":null,"x":"five"}""" + |> Expect.equal (Ok ( "--", "five" )) + , test "optional succeeds with result of the given decoder if the field is null and the decoder decodes nulls" <| + \() -> + decode (,) + |> optional "a" (null "null") "--" + |> optional "x" string "--" + |> runWith """{"a":null,"x":"five"}""" + |> Expect.equal (Ok ( "null", "five" )) + , test "optional fails if the field is present but doesn't decode" <| + \() -> + decode (,) + |> optional "a" string "--" + |> optional "x" string "--" + |> runWith """{"x":5}""" + |> expectErr + , test "optionalAt fails if the field is present but doesn't decode" <| + \() -> + decode (,) + |> optionalAt [ "a", "b" ] string "--" + |> optionalAt [ "x", "y" ] string "--" + |> runWith """{"a":{},"x":{"y":5}}""" + |> expectErr + , test "resolveResult bubbles up decoded Err results" <| + \() -> + decode Err + |> required "error" string + |> resolveResult + |> runWith """{"error":"invalid"}""" + |> expectErr + , test "resolveResult bubbles up decoded Ok results" <| + \() -> + decode Ok + |> required "ok" string + |> resolveResult + |> runWith """{"ok":"valid"}""" + |> Expect.equal (Ok "valid") + ] diff --git a/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json new file mode 100644 index 0000000..4513220 --- /dev/null +++ b/part10/tests/elm-stuff/packages/NoRedInk/elm-decode-pipeline/3.0.0/tests/elm-package.json @@ -0,0 +1,17 @@ +{ + "version": "1.0.0", + "summary": "Sample Elm Test", + "repository": "https://github.com/user/project.git", + "license": "BSD-3-Clause", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-community/elm-test": "2.0.0 <= v < 3.0.0", + "rtfeldman/node-test-runner": "1.0.0 <= v < 2.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.gitignore b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.gitignore new file mode 100644 index 0000000..a594364 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.gitignore @@ -0,0 +1,4 @@ +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.travis.yml b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.travis.yml new file mode 100644 index 0000000..b74a0c2 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/.travis.yml @@ -0,0 +1,31 @@ +sudo: false + +cache: + directories: + - tests/elm-stuff/build-artifacts + +os: + - osx + - linux + +env: + matrix: + - ELM_VERSION=0.18 TARGET_NODE_VERSION=node + - ELM_VERSION=0.18 TARGET_NODE_VERSION=4.2 + +before_install: + - if [ ${TRAVIS_OS_NAME} == "osx" ]; + then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh; + fi + +install: + - nvm install $TARGET_NODE_VERSION + - nvm use $TARGET_NODE_VERSION + - node --version + - npm --version + - npm install -g elm@$ELM_VERSION + - npm install -g elm-test + + +script: + - elm-test diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/LICENSE b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/LICENSE new file mode 100644 index 0000000..c495756 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2016, Noah +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/README.md b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/README.md new file mode 100644 index 0000000..a75b421 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/README.md @@ -0,0 +1,9 @@ +# elm-html-in-elm + + +A pure Elm represention of Elm Html. This module has been taken from [elm-server-side-renderer](https://github.com/eeue56/elm-server-side-renderer) and is a pure representation of the Html structure used by VirtualDom. It is designed to allow you to inspect Html nodes + +This package is used to support testing with [elm-html-test](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest). + +This package is also used to support using Elm as to generate static files for +your site with [elm-static-html](https://github.com/eeue56/elm-static-html) diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/elm-package.json b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/elm-package.json new file mode 100644 index 0000000..fdbecbb --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/elm-package.json @@ -0,0 +1,22 @@ +{ + "version": "5.2.0", + "summary": "A pure Elm representation of Elm Html", + "repository": "https://github.com/eeue56/elm-html-in-elm.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "ElmHtml.Constants", + "ElmHtml.InternalTypes", + "ElmHtml.Markdown", + "ElmHtml.ToString", + "ElmHtml.ToElmString", + "ElmHtml.ToHtml" + ], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Constants.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Constants.elm new file mode 100644 index 0000000..23262f2 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Constants.elm @@ -0,0 +1,43 @@ +module ElmHtml.Constants exposing (..) + +{-| +Constants for representing internal keys for Elm's vdom implementation + +@docs styleKey, eventKey, attributeKey, attributeNamespaceKey, knownKeys + +-} + + +{-| Internal key for style +-} +styleKey : String +styleKey = + "STYLE" + + +{-| Internal key for style +-} +eventKey : String +eventKey = + "EVENT" + + +{-| Internal key for style +-} +attributeKey : String +attributeKey = + "ATTR" + + +{-| Internal key for style +-} +attributeNamespaceKey : String +attributeNamespaceKey = + "ATTR_NS" + + +{-| Keys that we are aware of and should pay attention to +-} +knownKeys : List String +knownKeys = + [ styleKey, eventKey, attributeKey, attributeNamespaceKey ] diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Helpers.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Helpers.elm new file mode 100644 index 0000000..b5114fc --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Helpers.elm @@ -0,0 +1,17 @@ +module ElmHtml.Helpers exposing (..) + +{-| +Internal helpers for ElmHtml + +@docs filterKnownKeys +-} + +import Dict exposing (Dict) +import ElmHtml.Constants exposing (..) + + +{-| Filter out keys that we don't know +-} +filterKnownKeys : Dict String a -> Dict String a +filterKnownKeys = + Dict.filter (\key _ -> not (List.member key knownKeys)) diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/InternalTypes.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/InternalTypes.elm new file mode 100644 index 0000000..e553433 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/InternalTypes.elm @@ -0,0 +1,581 @@ +module ElmHtml.InternalTypes + exposing + ( Attribute(..) + , AttributeRecord + , CustomNodeRecord + , ElementKind(..) + , ElmHtml(..) + , EventHandler + , EventRecord + , Facts + , MarkdownNodeRecord + , NamespacedAttributeRecord + , NodeRecord + , PropertyRecord + , Tagger + , TextTagRecord + , decodeAttribute + , decodeElmHtml + , emptyFacts + , toElementKind + ) + +{-| Internal types used to represent Elm Html in pure Elm + +@docs ElmHtml, TextTagRecord, NodeRecord, CustomNodeRecord, MarkdownNodeRecord + +@docs Facts, Tagger, EventHandler, ElementKind + +@docs Attribute, AttributeRecord, NamespacedAttributeRecord, PropertyRecord, EventRecord + +@docs decodeElmHtml, emptyFacts, toElementKind, decodeAttribute + +-} + +import Dict exposing (Dict) +import ElmHtml.Constants exposing (..) +import ElmHtml.Helpers exposing (..) +import ElmHtml.Markdown exposing (..) +import Html.Events +import Json.Decode exposing (field) +import Json.Encode + + +{-| Type tree for representing Elm's Html + + - TextTag is just a plain old bit of text. + - NodeEntry is an actual HTML node, e.g a div + - CustomNode are nodes defined to work with the renderer in some way, e.g webgl/markdown + - MarkdownNode is just a wrapper for CustomNode designed just for markdown + +-} +type ElmHtml msg + = TextTag TextTagRecord + | NodeEntry (NodeRecord msg) + | CustomNode (CustomNodeRecord msg) + | MarkdownNode (MarkdownNodeRecord msg) + | NoOp + + +{-| Text tags just contain text +-} +type alias TextTagRecord = + { text : String } + + +{-| A node contains the `tag` as a string, the children, the facts (e.g attributes) and descendantsCount +-} +type alias NodeRecord msg = + { tag : String + , children : List (ElmHtml msg) + , facts : + Facts msg + + --, namespace : String + , descendantsCount : Int + } + + +{-| A markdown node contains facts (e.g attributes) and the model used by markdown +-} +type alias MarkdownNodeRecord msg = + { facts : Facts msg + , model : MarkdownModel + } + + +{-| Custom nodes contain facts (e.g attributes) and a json value for the model +-} +type alias CustomNodeRecord msg = + { facts : Facts msg + , model : Json.Decode.Value + } + + +{-| Tagger holds the map function when Html.Map is used, the tagger +should then be applied to events comming from descendant nodes, it +is basically a javascript function. +-} +type alias Tagger = + Json.Decode.Value + + +{-| EventHandler holds the function that is called when an event is +triggered, it is basically a javascript object like this: + +{ decoder: [Function] } + +-} +type alias EventHandler = + Json.Decode.Value + + +{-| Facts contain various dictionaries and values for a node + + - styles are a mapping of rules + - events may be a json object containing event handlers + - attributes are pulled out into stringAttributes and boolAttributes - things with string values go into + stringAttributes, things with bool values go into boolAttributes + +-} +type alias Facts msg = + { styles : Dict String String + , events : Dict String (Json.Decode.Decoder msg) + , attributeNamespace : Maybe Json.Decode.Value + , stringAttributes : Dict String String + , boolAttributes : Dict String Bool + } + + +{-| Type for representing the five kinds of elements according to HTML 5 +[spec](https://html.spec.whatwg.org/multipage/syntax.html#elements-2). +Used to handle different rendering behavior depending on the type of element. +-} +type ElementKind + = VoidElements + | RawTextElements + | EscapableRawTextElements + | ForeignElements + | NormalElements + + +type HtmlContext msg + = HtmlContext (List Tagger) (List Tagger -> EventHandler -> Json.Decode.Decoder msg) + + +{-| Type for representing Elm's Attributes + + - Attribute is an HTML attribute, like `Html.Attributes.colspan`. These values + are applied using `element.setAttribute(key, value)` during a patch. + - NamespacedAttribute has an namespace, like `Svg.Attributes.xlinkHref` + - Property assigns a value to a node like `Html.Attributes.class`, and can + hold any encoded value. Unlike attributes, where `element.setAttribute()` is + used during the patch, properties are applied directly as + `element[key] = value`. + - Styles hold a list of key value pairs to be applied to the node's style set + - Event contains a decoder for a msg and the `Html.Event.Options` for the event + +-} +type Attribute + = Attribute AttributeRecord + | NamespacedAttribute NamespacedAttributeRecord + | Property PropertyRecord + | Styles (List ( String, String )) + | Event EventRecord + + +{-| Attribute contains a string key and a string value +-} +type alias AttributeRecord = + { key : String + , value : String + } + + +{-| NamespacedAttribute contains a string key, string namespace and string value +-} +type alias NamespacedAttributeRecord = + { key : String + , value : String + , namespace : String + } + + +{-| Property contains a string key and a value with an arbitrary type +-} +type alias PropertyRecord = + { key : String + , value : Json.Decode.Value + } + + +{-| Event contains a string key, a decoder for a msg and event options +-} +type alias EventRecord = + { key : String + , decoder : Json.Decode.Value + , options : Html.Events.Options + } + + +{-| decode a json object into ElmHtml, you have to pass a function that decodes +events from Html Nodes. If you don't want to decode event msgs, you can ignore it: + +decodeElmHtml (\_ _ -> ()) jsonHtml + +if you do want to decode them, you will probably need to write some native code +like elm-html-test does to extract the function inside those. + +-} +decodeElmHtml : (List Tagger -> EventHandler -> Json.Decode.Decoder msg) -> Json.Decode.Decoder (ElmHtml msg) +decodeElmHtml eventDecoder = + contextDecodeElmHtml (HtmlContext [] eventDecoder) + + +contextDecodeElmHtml : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg) +contextDecodeElmHtml context = + field "type" Json.Decode.string + |> Json.Decode.andThen + (\typeString -> + case typeString of + "text" -> + Json.Decode.map TextTag decodeTextTag + + "keyed-node" -> + Json.Decode.map NodeEntry (decodeKeyedNode context) + + "node" -> + Json.Decode.map NodeEntry (decodeNode context) + + "custom" -> + decodeCustomNode context + + "tagger" -> + decodeTagger context + + "thunk" -> + field "node" (contextDecodeElmHtml context) + + _ -> + Json.Decode.fail ("No such type as " ++ typeString) + ) + + +{-| decode text tag +-} +decodeTextTag : Json.Decode.Decoder TextTagRecord +decodeTextTag = + field "text" (Json.Decode.andThen (\text -> Json.Decode.succeed { text = text }) Json.Decode.string) + + +{-| encode text tag +-} +encodeTextTag : TextTagRecord -> Json.Encode.Value +encodeTextTag { text } = + Json.Encode.object [ ( "text", Json.Encode.string text ) ] + + +{-| decode a tagger +-} +decodeTagger : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg) +decodeTagger (HtmlContext taggers eventDecoder) = + Json.Decode.field "tagger" Json.Decode.value + |> Json.Decode.andThen + (\tagger -> + let + nodeDecoder = + contextDecodeElmHtml (HtmlContext (taggers ++ [ tagger ]) eventDecoder) + in + Json.Decode.oneOf + [ Json.Decode.at [ "node" ] nodeDecoder + , Json.Decode.at [ "text" ] nodeDecoder + , Json.Decode.at [ "custom" ] nodeDecoder + ] + ) + + +decodeKeyedNode : HtmlContext msg -> Json.Decode.Decoder (NodeRecord msg) +decodeKeyedNode context = + let + -- elm stores keyed nodes as tuples + -- we only want to decode the html, in the second property + decodeSecondNode = + Json.Decode.field "_1" (contextDecodeElmHtml context) + in + Json.Decode.map4 NodeRecord + (Json.Decode.field "tag" Json.Decode.string) + (Json.Decode.field "children" (Json.Decode.list decodeSecondNode)) + (Json.Decode.field "facts" (decodeFacts context)) + (Json.Decode.field "descendantsCount" Json.Decode.int) + + +{-| decode a node record +-} +decodeNode : HtmlContext msg -> Json.Decode.Decoder (NodeRecord msg) +decodeNode context = + Json.Decode.map4 NodeRecord + (field "tag" Json.Decode.string) + (field "children" (Json.Decode.list (contextDecodeElmHtml context))) + (field "facts" (decodeFacts context)) + (field "descendantsCount" Json.Decode.int) + + +{-| encode a node record: currently does not support facts or children +-} +encodeNodeRecord : NodeRecord msg -> Json.Encode.Value +encodeNodeRecord record = + Json.Encode.object + [ ( "tag", Json.Encode.string record.tag ) + + --, ( "children", Json.Encode.list encodeElmHtml) + --, ( "facts", encodeFacts) + , ( "descendantsCount", Json.Encode.int record.descendantsCount ) + ] + + +{-| decode custom node into either markdown or custom +-} +decodeCustomNode : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg) +decodeCustomNode context = + Json.Decode.oneOf + [ Json.Decode.map MarkdownNode (decodeMarkdownNodeRecord context) + , Json.Decode.map CustomNode (decodeCustomNodeRecord context) + ] + + +{-| decode custom node record +-} +decodeCustomNodeRecord : HtmlContext msg -> Json.Decode.Decoder (CustomNodeRecord msg) +decodeCustomNodeRecord context = + Json.Decode.map2 CustomNodeRecord + (field "facts" (decodeFacts context)) + (field "model" Json.Decode.value) + + +{-| decode markdown node record +-} +decodeMarkdownNodeRecord : HtmlContext msg -> Json.Decode.Decoder (MarkdownNodeRecord msg) +decodeMarkdownNodeRecord context = + Json.Decode.map2 MarkdownNodeRecord + (field "facts" (decodeFacts context)) + (field "model" decodeMarkdownModel) + + +{-| decode the styles +-} +decodeStyles : Json.Decode.Decoder (Dict String String) +decodeStyles = + Json.Decode.oneOf + [ field styleKey (Json.Decode.dict Json.Decode.string) + , Json.Decode.succeed Dict.empty + ] + + +{-| encode styles +-} +encodeStyles : Dict String String -> Json.Encode.Value +encodeStyles stylesDict = + let + encodedDict = + stylesDict + |> Dict.toList + |> List.map (\( k, v ) -> ( k, Json.Encode.string v )) + in + Json.Encode.object [ ( styleKey, Json.Encode.object encodedDict ) ] + + +{-| grab things from attributes via a decoder, then anything that isn't filtered on +the object +-} +decodeOthers : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a) +decodeOthers otherDecoder = + decodeAttributes otherDecoder + |> Json.Decode.andThen + (\attributes -> + decodeDictFilterMap otherDecoder + |> Json.Decode.map (filterKnownKeys >> Dict.union attributes) + ) + + +{-| For a given decoder, keep the values from a dict that pass the decoder +-} +decodeDictFilterMap : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a) +decodeDictFilterMap decoder = + Json.Decode.dict Json.Decode.value + |> Json.Decode.map + (Dict.toList + >> List.filterMap + (\( key, value ) -> + case Json.Decode.decodeValue decoder value of + Err _ -> + Nothing + + Ok v -> + Just ( key, v ) + ) + >> Dict.fromList + ) + + +decodeAttributes : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a) +decodeAttributes decoder = + Json.Decode.oneOf + [ Json.Decode.field attributeKey (decodeDictFilterMap decoder) + , Json.Decode.succeed Dict.empty + ] + + +decodeEvents : (EventHandler -> Json.Decode.Decoder msg) -> Json.Decode.Decoder (Dict String (Json.Decode.Decoder msg)) +decodeEvents taggedEventDecoder = + Json.Decode.oneOf + [ Json.Decode.field eventKey (Json.Decode.dict (Json.Decode.map taggedEventDecoder Json.Decode.value)) + , Json.Decode.succeed Dict.empty + ] + + +{-| decode fact +-} +decodeFacts : HtmlContext msg -> Json.Decode.Decoder (Facts msg) +decodeFacts (HtmlContext taggers eventDecoder) = + Json.Decode.map5 Facts + decodeStyles + (decodeEvents (eventDecoder taggers)) + (Json.Decode.maybe (Json.Decode.field attributeNamespaceKey Json.Decode.value)) + (decodeOthers Json.Decode.string) + (decodeOthers Json.Decode.bool) + + +{-| Just empty facts +-} +emptyFacts : Facts msg +emptyFacts = + { styles = Dict.empty + , events = Dict.empty + , attributeNamespace = Nothing + , stringAttributes = Dict.empty + , boolAttributes = Dict.empty + } + + +{-| Decode a JSON object into an Attribute. You have to pass a function that +decodes events from event attributes. If you don't want to decode event msgs, +you can ignore it: + + decodeAttribute (\_ -> ()) jsonHtml + +If you do want to decode them, you will probably need to write some native code +like elm-html-test does to extract the function inside those. + +-} +decodeAttribute : Json.Decode.Decoder Attribute +decodeAttribute = + Json.Decode.field "key" Json.Decode.string + |> Json.Decode.andThen + (\key -> + if key == attributeKey then + Json.Decode.map2 AttributeRecord + (Json.Decode.field "realKey" Json.Decode.string) + (Json.Decode.field "value" Json.Decode.string) + |> Json.Decode.map Attribute + else if key == attributeNamespaceKey then + Json.Decode.map3 NamespacedAttributeRecord + (Json.Decode.field "realKey" Json.Decode.string) + (Json.Decode.at [ "value", "value" ] Json.Decode.string) + (Json.Decode.at [ "value", "namespace" ] Json.Decode.string) + |> Json.Decode.map NamespacedAttribute + else if key == styleKey then + Json.Decode.map2 (,) + (Json.Decode.field "_0" Json.Decode.string) + (Json.Decode.field "_1" Json.Decode.string) + |> elmListDecoder + |> Json.Decode.field "value" + |> Json.Decode.map Styles + else if key == eventKey then + Json.Decode.map3 EventRecord + (Json.Decode.field "realKey" Json.Decode.string) + (Json.Decode.at [ "value", "decoder" ] Json.Decode.value) + (Json.Decode.at [ "value", "options" ] decodeOptions) + |> Json.Decode.map Event + else + Json.Decode.field "value" Json.Decode.value + |> Json.Decode.map (PropertyRecord key >> Property) + ) + + +decodeOptions : Json.Decode.Decoder Html.Events.Options +decodeOptions = + Json.Decode.map2 Html.Events.Options + (Json.Decode.field "stopPropagation" Json.Decode.bool) + (Json.Decode.field "preventDefault" Json.Decode.bool) + + +elmListDecoder : Json.Decode.Decoder a -> Json.Decode.Decoder (List a) +elmListDecoder itemDecoder = + elmListDecoderHelp itemDecoder [] + |> Json.Decode.map List.reverse + + +elmListDecoderHelp : Json.Decode.Decoder a -> List a -> Json.Decode.Decoder (List a) +elmListDecoderHelp itemDecoder items = + Json.Decode.field "ctor" Json.Decode.string + |> Json.Decode.andThen + (\ctor -> + case ctor of + "[]" -> + Json.Decode.succeed items + + "::" -> + Json.Decode.field "_0" itemDecoder + |> Json.Decode.andThen + (\value -> + Json.Decode.field "_1" (elmListDecoderHelp itemDecoder (value :: items)) + ) + + _ -> + Json.Decode.fail <| "Unrecognized constructor for an Elm List: " ++ ctor + ) + + +{-| A list of Void elements as defined by the HTML5 specification. These +elements must not have closing tags and most not be written as self closing +either +-} +voidElements : List String +voidElements = + [ "area" + , "base" + , "br" + , "col" + , "embed" + , "hr" + , "img" + , "input" + , "link" + , "meta" + , "param" + , "source" + , "track" + , "wbr" + ] + + +{-| A list of all Raw Text Elements as defined by the HTML5 specification. They +can contain only text and have restrictions on which characters can appear +within its innerHTML +-} +rawTextElements : List String +rawTextElements = + [ "script", "style" ] + + +{-| A list of all Escapable Raw Text Elements as defined by the HTML5 +specification. They can have text and character references, but the text must +not contain an ambiguous ampersand along with addional restrictions: + +-} +escapableRawTextElements : List String +escapableRawTextElements = + [ "textarea", "title" ] + + + +{- Foreign elements are elements from the MathML namespace and the + SVG namespace. TODO: detect these nodes and handle them correctly. Right + now they will just be treated as Normal elements. +-} + + +{-| Identify the kind of element. Helper to convert an tag name into a type for +pattern matching. +-} +toElementKind : String -> ElementKind +toElementKind element = + if List.member element voidElements then + VoidElements + else if List.member element rawTextElements then + RawTextElements + else if List.member element escapableRawTextElements then + EscapableRawTextElements + else + -- All other allowed HTML elements are normal elements + NormalElements diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Markdown.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Markdown.elm new file mode 100644 index 0000000..121d4fc --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/Markdown.elm @@ -0,0 +1,70 @@ +module ElmHtml.Markdown exposing (..) + +{-| Markdown helpers + +@docs MarkdownOptions, MarkdownModel, baseMarkdownModel + +@docs encodeOptions, encodeMarkdownModel, decodeMarkdownModel + +-} + +import Json.Encode +import Json.Decode exposing (field) + + +{-| Just a default markdown model +-} +baseMarkdownModel : MarkdownModel +baseMarkdownModel = + { options = + { githubFlavored = Just { tables = False, breaks = False } + , defaultHighlighting = Nothing + , sanitize = False + , smartypants = False + } + , markdown = "" + } + + +{-| options markdown expects +-} +type alias MarkdownOptions = + { githubFlavored : Maybe { tables : Bool, breaks : Bool } + , defaultHighlighting : Maybe String + , sanitize : Bool + , smartypants : Bool + } + + +{-| An internal markdown model. Options are the things you give markdown, markdown is the string +-} +type alias MarkdownModel = + { options : MarkdownOptions + , markdown : String + } + + +{-| We don't really care about encoding options right now +TODO: we will if we want to represent things as we do for elm-html +-} +encodeOptions : MarkdownOptions -> Json.Decode.Value +encodeOptions options = + Json.Encode.null + + +{-| encode markdown model +-} +encodeMarkdownModel : MarkdownModel -> Json.Decode.Value +encodeMarkdownModel model = + Json.Encode.object + [ ( "options", encodeOptions model.options ) + , ( "markdown", Json.Encode.string model.markdown ) + ] + + +{-| decode a markdown model +-} +decodeMarkdownModel : Json.Decode.Decoder MarkdownModel +decodeMarkdownModel = + field "markdown" Json.Decode.string + |> Json.Decode.map (MarkdownModel baseMarkdownModel.options) diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToElmString.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToElmString.elm new file mode 100644 index 0000000..e6e2077 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToElmString.elm @@ -0,0 +1,143 @@ +module ElmHtml.ToElmString + exposing + ( toElmString + , nodeRecordToString + , toElmStringWithOptions + , FormatOptions + , defaultFormatOptions + ) + +{-| Convert ElmHtml to string of Elm code. + +@docs nodeRecordToString, toElmString, toElmStringWithOptions + +@docs FormatOptions, defaultFormatOptions + +-} + +import String +import Dict exposing (Dict) +import ElmHtml.InternalTypes exposing (..) + + +{-| Formatting options to be used for converting to string +-} +type alias FormatOptions = + { indent : Int + , newLines : Bool + } + + +{-| default formatting options +-} +defaultFormatOptions : FormatOptions +defaultFormatOptions = + { indent = 0 + , newLines = False + } + + +nodeToLines : FormatOptions -> ElmHtml msg -> List String +nodeToLines options nodeType = + case nodeType of + TextTag { text } -> + [ "Html.text \"" ++ text ++ "\"" ] + + NodeEntry record -> + nodeRecordToString options record + + CustomNode record -> + [] + + MarkdownNode record -> + [ record.model.markdown ] + + NoOp -> + [] + + +{-| Convert a given html node to a string based on the type +-} +toElmString : ElmHtml msg -> String +toElmString = + toElmStringWithOptions defaultFormatOptions + + +{-| same as toElmString, but with options +-} +toElmStringWithOptions : FormatOptions -> ElmHtml msg -> String +toElmStringWithOptions options = + nodeToLines options + >> String.join + (if options.newLines then + "\n" + else + "" + ) + + +{-| Convert a node record to a string. This basically takes the tag name, then +pulls all the facts into tag declaration, then goes through the children and +nests them under this one +-} +nodeRecordToString : FormatOptions -> NodeRecord msg -> List String +nodeRecordToString options { tag, children, facts } = + let + openTag : List (Maybe String) -> String + openTag extras = + let + trimmedExtras = + List.filterMap (\x -> x) extras + |> List.map String.trim + |> List.filter ((/=) "") + + filling = + case trimmedExtras of + [] -> + "" + + more -> + " " ++ (String.join " " more) + in + "Html." ++ tag ++ " [" ++ filling + + childrenStrings = + List.map (nodeToLines options) children + |> List.concat + |> List.map ((++) (String.repeat options.indent " ")) + + styles = + case Dict.toList facts.styles of + [] -> + Nothing + + styles -> + styles + |> List.map (\( key, value ) -> "(\"" ++ key ++ "\",\"" ++ value ++ "\")") + |> String.join ", " + |> (\styleString -> "Html.Attributes.style [" ++ styleString ++ "]") + |> Just + + classes = + Dict.get "className" facts.stringAttributes + |> Maybe.map (\name -> "Html.Attributes.class [\"" ++ name ++ "\"]") + + stringAttributes = + Dict.filter (\k v -> k /= "className") facts.stringAttributes + |> Dict.toList + |> List.map (\( k, v ) -> "Html.Attributes." ++ k ++ " \"" ++ v ++ "\"") + |> String.join ", " + |> Just + + boolAttributes = + Dict.toList facts.boolAttributes + |> List.map (\( k, v ) -> "Html.Attributes.property \"" ++ k ++ "\" <| Json.Encode.bool " ++ toString v) + |> String.join " " + |> Just + in + [ openTag [ classes, styles, stringAttributes, boolAttributes ] ] + ++ [ " ] " + , "[ " + , String.join "" childrenStrings + , "]" + ] diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToHtml.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToHtml.elm new file mode 100644 index 0000000..492c437 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToHtml.elm @@ -0,0 +1,82 @@ +module ElmHtml.ToHtml exposing (toHtml, factsToAttributes) + +{-| This module is particularly useful for putting parsed Html into Elm.Html at runtime. +Estentially allowing the user to use tools like html-to-elm on their code. + +@docs toHtml, factsToAttributes + +-} + +import String +import Dict exposing (Dict) +import ElmHtml.InternalTypes exposing (..) +import Html +import Html.Attributes +import Html.Events +import Json.Encode +import Json.Decode + + +{-| Turns ElmHtml into normal Elm Html +-} +toHtml : ElmHtml msg -> Html.Html msg +toHtml elmHtml = + case elmHtml of + TextTag text -> + Html.text text.text + + NodeEntry { tag, children, facts } -> + Html.node tag [] (List.map toHtml children) + + CustomNode record -> + let + _ = + Debug.log "Custom node is not supported" "" + in + Html.text "" + + MarkdownNode record -> + let + _ = + Debug.log "Markdown node is not supported" "" + in + Html.text "" + + NoOp -> + Html.text "" + + +stylesToAttribute : Dict String String -> Html.Attribute msg +stylesToAttribute = + Dict.toList + >> Html.Attributes.style + + +eventsToAttributes : Dict String (Json.Decode.Decoder msg) -> List (Html.Attribute msg) +eventsToAttributes = + Dict.toList + >> List.map (\( x, y ) -> Html.Events.on x y) + + +stringAttributesToAttributes : Dict String String -> List (Html.Attribute msg) +stringAttributesToAttributes = + Dict.toList + >> List.map (\( x, y ) -> Html.Attributes.attribute x y) + + +boolAttributesToAttributes : Dict String Bool -> List (Html.Attribute msg) +boolAttributesToAttributes = + Dict.toList + >> List.map (\( x, y ) -> Html.Attributes.property x (Json.Encode.bool y)) + + +{-| Turns a fact record into a list of attributes +-} +factsToAttributes : Facts msg -> List (Html.Attribute msg) +factsToAttributes facts = + List.concat + [ [ stylesToAttribute facts.styles ] + , eventsToAttributes facts.events + , stringAttributesToAttributes facts.stringAttributes + , boolAttributesToAttributes facts.boolAttributes + ] diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToString.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToString.elm new file mode 100644 index 0000000..e3db5a0 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/src/ElmHtml/ToString.elm @@ -0,0 +1,155 @@ +module ElmHtml.ToString + exposing + ( nodeToString + , nodeRecordToString + , nodeToStringWithOptions + , FormatOptions + , defaultFormatOptions + ) + +{-| Convert ElmHtml to string. + +@docs nodeRecordToString, nodeToString, nodeToStringWithOptions + +@docs FormatOptions, defaultFormatOptions +-} + +import String +import Dict exposing (Dict) +import ElmHtml.InternalTypes exposing (..) + + +{-| Formatting options to be used for converting to string +-} +type alias FormatOptions = + { indent : Int + , newLines : Bool + } + + +{-| default formatting options +-} +defaultFormatOptions : FormatOptions +defaultFormatOptions = + { indent = 0 + , newLines = False + } + + +nodeToLines : FormatOptions -> ElmHtml msg -> List String +nodeToLines options nodeType = + case nodeType of + TextTag { text } -> + [ text ] + + NodeEntry record -> + nodeRecordToString options record + + CustomNode record -> + [] + + MarkdownNode record -> + [ record.model.markdown ] + + NoOp -> + [] + + +{-| Convert a given html node to a string based on the type +-} +nodeToString : ElmHtml msg -> String +nodeToString = + nodeToStringWithOptions defaultFormatOptions + + +{-| same as nodeToString, but with options +-} +nodeToStringWithOptions : FormatOptions -> ElmHtml msg -> String +nodeToStringWithOptions options = + nodeToLines options + >> String.join + (if options.newLines then + "\n" + else + "" + ) + + +{-| Convert a node record to a string. This basically takes the tag name, then + pulls all the facts into tag declaration, then goes through the children and + nests them under this one +-} +nodeRecordToString : FormatOptions -> NodeRecord msg -> List String +nodeRecordToString options { tag, children, facts } = + let + openTag : List (Maybe String) -> String + openTag extras = + let + trimmedExtras = + List.filterMap (\x -> x) extras + |> List.map String.trim + |> List.filter ((/=) "") + + filling = + case trimmedExtras of + [] -> + "" + + more -> + " " ++ (String.join " " more) + in + "<" ++ tag ++ filling ++ ">" + + closeTag = + "" + + childrenStrings = + List.map (nodeToLines options) children + |> List.concat + |> List.map ((++) (String.repeat options.indent " ")) + + styles = + case Dict.toList facts.styles of + [] -> + Nothing + + styles -> + styles + |> List.map (\( key, value ) -> key ++ ":" ++ value ++ ";") + |> String.join "" + |> (\styleString -> "style=\"" ++ styleString ++ "\"") + |> Just + + classes = + Dict.get "className" facts.stringAttributes + |> Maybe.map (\name -> "class=\"" ++ name ++ "\"") + + stringAttributes = + Dict.filter (\k v -> k /= "className") facts.stringAttributes + |> Dict.toList + |> List.map (\( k, v ) -> k ++ "=\"" ++ v ++ "\"") + |> String.join " " + |> Just + + boolAttributes = + Dict.toList facts.boolAttributes + |> List.map (\( k, v ) -> k ++ "=" ++ (String.toLower <| toString v)) + |> String.join " " + |> Just + in + case toElementKind tag of + {- Void elements only have a start tag; end tags must not be + specified for void elements. + -} + VoidElements -> + [ openTag [ classes, styles, stringAttributes, boolAttributes ] ] + + {- TODO: implement restrictions for RawTextElements, + EscapableRawTextElements. Also handle ForeignElements correctly. + For now just punt and use the previous behavior for all other + element kinds. + -} + _ -> + [ openTag [ classes, styles, stringAttributes, boolAttributes ] ] + ++ childrenStrings + ++ [ closeTag ] diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Native/HtmlAsJson.js b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Native/HtmlAsJson.js new file mode 100644 index 0000000..b200044 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Native/HtmlAsJson.js @@ -0,0 +1,16 @@ +var _eeue56$elm_html_in_elm$Native_HtmlAsJson = (function() { + return { + unsafeCoerce: function(a) { + return a; + }, + eventDecoder: function (event) { + return event.decoder; + }, + eventHandler: F2(function(eventName, html) { + return html.facts.EVENT[eventName]; + }), + taggerFunction: function(tagger) { + return tagger; + } + }; +})(); diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Tests.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Tests.elm new file mode 100644 index 0000000..23d91b7 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/Tests.elm @@ -0,0 +1,311 @@ +module Tests exposing (..) + +import Dict +import ElmHtml.InternalTypes exposing (Attribute(..), ElmHtml(..), EventHandler, Facts, NodeRecord, Tagger, decodeAttribute, decodeElmHtml) +import ElmHtml.ToHtml +import ElmHtml.ToElmString exposing (toElmString) +import Expect +import Html exposing (Html, button, div, input, text) +import Html.Attributes exposing (class, colspan, disabled, style, value) +import Html.Events exposing (onCheck, onClick, onInput) +import Json.Decode exposing (decodeValue) +import Json.Encode +import Native.HtmlAsJson +import Svg.Attributes exposing (xlinkHref) +import Test exposing (..) + + +elmHtml : Test +elmHtml = + describe "ElmHtml parsing" + [ test "parsing a node" <| + \() -> + div [] [] + |> fromHtml + |> Expect.equal (Ok (NodeEntry decodedNode)) + , test "parsing a text" <| + \() -> + text "foo" + |> fromHtml + |> Expect.equal (Ok (TextTag { text = "foo" })) + , test "parsing attributes" <| + \() -> + let + facts = + { decodedFacts + | stringAttributes = Dict.fromList [ ( "className", "foo" ), ( "value", "bar" ) ] + , boolAttributes = Dict.fromList [ ( "disabled", True ) ] + } + + expected = + { decodedNode | tag = "button", facts = facts } + in + button [ class "foo", value "bar", disabled True ] [] + |> fromHtml + |> Expect.equal (Ok (NodeEntry expected)) + , test "parsing children" <| + \() -> + let + expected = + { decodedNode + | children = [ NodeEntry decodedNode, TextTag { text = "foo" } ] + , descendantsCount = 2 + } + in + div [] + [ div [] [] + , text "foo" + ] + |> fromHtml + |> Expect.equal (Ok (NodeEntry expected)) + , describe "parsing events" + [ testParsingEvent "click" (onClick SomeMsg) + , testParsingEvent "input" (onInput InputMsg) + , testParsingEvent "change" (onCheck CheckMsg) + ] + , describe "parsing Html.map" + [ test "adds the correct tagger to a mapped button" <| + \() -> + let + taggedNode = + input [ onInput identity ] [] + |> Html.map (\msg -> msg ++ "bar") + |> fromHtml + in + taggedNode + |> Result.andThen (simulate "input" "{\"target\": {\"value\": \"foo\"}}") + |> Expect.equal (Ok "foobar") + , test "adds two taggers to a double mapped button with changing types" <| + \() -> + let + taggedNode = + input [ onInput identity ] [] + |> Html.map (\str -> [ str ] ++ [ "bar" ]) + |> Html.map (\list -> ( list, "baz" )) + |> fromHtml + in + taggedNode + |> Result.andThen (simulate "input" "{\"target\": {\"value\": \"foo\"}}") + |> Expect.equal (Ok ( [ "foo", "bar" ], "baz" )) + ] + ] + + +elmHtmlToHtml : Test +elmHtmlToHtml = + describe "Turning the AST into Html" + [ test "parsing a node" <| + \() -> + div [] [] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [] []) + , test "parsing a text" <| + \() -> + text "foo" + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| text "foo") + , test "parsing a text in a div" <| + \() -> + div [] [ text "foo" ] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [] [ text "foo" ]) + , test "parsing a text in a div in a div in a div " <| + \() -> + div [] [ div [] [ text "banana", div [] [ text "foo", text "bar" ] ] ] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [] [ div [] [ text "banana", div [] [ text "foo", text "bar" ] ] ]) + , test "parsing styles in a div" <| + \() -> + div [ Html.Attributes.style [ ( "background", "red" ) ] ] [ text "foo" ] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [ Html.Attributes.style [ ( "background", "red" ) ] ] [ text "foo" ]) + , test "parsing attributes a div" <| + \() -> + div [ Html.Attributes.name "fish", Html.Attributes.checked True ] [ text "foo" ] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [ Html.Attributes.name "fish", Html.Attributes.checked True ] [ text "foo" ]) + , test "parsing attributes in a nested div" <| + \() -> + div [ Html.Attributes.name "fish", Html.Attributes.checked True ] [ Html.li [ Html.Attributes.type_ "hello" ] [ text "foo" ] ] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [ Html.Attributes.name "fish", Html.Attributes.checked True ] [ Html.li [ Html.Attributes.type_ "hello" ] [ text "foo" ] ]) + , test "parsing events in a div" <| + \() -> + div [ Html.Events.onClick True ] [] + |> fromHtml + |> Result.map ElmHtml.ToHtml.toHtml + |> Expect.equal (Ok <| div [ Html.Events.onClick True ] []) + ] + + +elmHtmlToElmString : Test +elmHtmlToElmString = + describe "Turning the AST into Elm, but as a string" + [ test "parsing a node" <| + \() -> + div [] [] + |> fromHtml + |> Result.map toElmString + |> Expect.equal (Ok <| "Html.div [ ] [ ]") + , test "parsing a text" <| + \() -> + text "foo" + |> fromHtml + |> Result.map toElmString + |> Expect.equal (Ok <| "Html.text \"foo\"") + , test "parsing a nested node" <| + \() -> + div [] [ div [] [ text "hello" ] ] + |> fromHtml + |> Result.map toElmString + |> Expect.equal (Ok <| "Html.div [ ] [ Html.div [ ] [ Html.text \"hello\"]]") + , test "parsing an attribute" <| + \() -> + div [ Html.Attributes.checked True ] [ text "hello" ] + |> fromHtml + |> Result.map toElmString + |> Expect.equal (Ok <| "Html.div [ Html.Attributes.property \"checked\" <| Json.Encode.bool True ] [ Html.text \"hello\"]") + ] + + +attributes : Test +attributes = + describe "Attribute parsing" + [ test "parsing Attribute" <| + \() -> + colspan 1 + |> fromAttribute + |> Expect.equal (Ok (Attribute { key = "colspan", value = "1" })) + , test "parsing NamespacedAttribute" <| + \() -> + xlinkHref "#id" + |> fromAttribute + |> Expect.equal + (Ok (NamespacedAttribute { key = "xlink:href", value = "#id", namespace = "http://www.w3.org/1999/xlink" })) + , test "parsing Property" <| + \() -> + disabled True + |> fromAttribute + |> Expect.equal (Ok (Property { key = "disabled", value = Json.Encode.bool True })) + , test "parsing Event" <| + \() -> + onClick () + |> fromAttribute + |> Expect.equal + (Ok (Event { key = "click", decoder = toJson (Json.Decode.succeed ()), options = Html.Events.defaultOptions })) + , test "parsing Styles" <| + \() -> + style [ ( "margin", "0" ) ] + |> fromAttribute + |> Expect.equal (Ok (Styles [ ( "margin", "0" ) ])) + ] + + +type Msg + = SomeMsg + | InputMsg String + | CheckMsg Bool + + +toJson : a -> Json.Decode.Value +toJson = + Native.HtmlAsJson.unsafeCoerce + + +eventDecoder : EventHandler -> Json.Decode.Decoder msg +eventDecoder eventHandler = + Native.HtmlAsJson.eventDecoder eventHandler + + +eventHandler : String -> Html a -> Json.Decode.Value +eventHandler eventName node = + Native.HtmlAsJson.eventHandler eventName node + + +taggerFunction : Tagger -> (a -> msg) +taggerFunction tagger = + Native.HtmlAsJson.taggerFunction tagger + + +taggedEventDecoder : List Tagger -> EventHandler -> Json.Decode.Decoder msg +taggedEventDecoder taggers eventHandler = + case taggers of + [] -> + eventDecoder eventHandler + + [ tagger ] -> + Json.Decode.map (taggerFunction tagger) (eventDecoder eventHandler) + + tagger :: taggers -> + Json.Decode.map (taggerFunction tagger) (taggedEventDecoder taggers eventHandler) + + +fromAttribute : Html.Attribute a -> Result String Attribute +fromAttribute attribute = + toJson attribute + |> decodeValue decodeAttribute + + +decodedNode : NodeRecord msg +decodedNode = + { tag = "div" + , children = [] + , facts = decodedFacts + , descendantsCount = 0 + } + + +decodedFacts : Facts msg +decodedFacts = + { styles = Dict.fromList [] + , events = Dict.fromList [] + , attributeNamespace = Nothing + , stringAttributes = Dict.fromList [] + , boolAttributes = Dict.fromList [] + } + + +fromHtml : Html a -> Result String (ElmHtml msg) +fromHtml html = + toJson html + |> decodeValue (decodeElmHtml taggedEventDecoder) + + +simulate : String -> String -> ElmHtml msg -> Result String msg +simulate eventName event parsedHtml = + case parsedHtml of + NodeEntry node -> + Dict.get eventName node.facts.events + |> Result.fromMaybe "Tried to trigger event on something other than a NodeEntry" + |> Result.andThen (\eventDecoder -> Json.Decode.decodeString eventDecoder event) + + _ -> + Err "Tried to trigger event on something other than a NodeEntry" + + +testParsingEvent : String -> Html.Attribute a -> Test +testParsingEvent eventName eventAttribute = + test ("parsing " ++ eventName) <| + \() -> + let + node = + button [ eventAttribute ] [] + + facts = + { decodedFacts + | events = Dict.fromList [ ( eventName, eventDecoder (eventHandler eventName node) ) ] + } + + expected = + { decodedNode | tag = "button", facts = facts } + in + node + |> fromHtml + |> Expect.equal (Ok (NodeEntry expected)) diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/elm-package.json b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/elm-package.json new file mode 100644 index 0000000..2547f1d --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-in-elm/5.2.0/tests/elm-package.json @@ -0,0 +1,19 @@ +{ + "version": "1.0.0", + "summary": "Test Suites", + "repository": "https://github.com/eeue56/elm-html-in-elm.git", + "license": "BSD3", + "source-directories": [ + "../src", + "." + ], + "exposed-modules": [], + "native-modules": true, + "dependencies": { + "elm-community/elm-test": "4.0.0 <= v < 5.0.0", + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0", + "elm-lang/svg": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/.gitignore b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/.gitignore new file mode 100644 index 0000000..a594364 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/.gitignore @@ -0,0 +1,4 @@ +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/LICENSE b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/LICENSE new file mode 100644 index 0000000..c495756 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2016, Noah +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/README.md b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/README.md new file mode 100644 index 0000000..ff7a43c --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/README.md @@ -0,0 +1,3 @@ +# elm-html-query + +Query things using a [ElmHtml](http://package.elm-lang.org/packages/eeue56/elm-html-in-elm/latest) representation. This project is used alongside [elm-html-test](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest) to implement Html-based tests in Elm. diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/elm-package.json b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/elm-package.json new file mode 100644 index 0000000..1d86091 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "3.0.0", + "summary": "Query for things inside ElmHtml", + "repository": "https://github.com/eeue56/elm-html-query.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "ElmHtml.Query" + ], + "dependencies": { + "eeue56/elm-html-in-elm": "5.0.0 <= v < 6.0.0", + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/src/ElmHtml/Query.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/src/ElmHtml/Query.elm new file mode 100644 index 0000000..04ad962 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-query/3.0.0/src/ElmHtml/Query.elm @@ -0,0 +1,350 @@ +module ElmHtml.Query + exposing + ( Selector(..) + , query + , queryAll + , queryInNode + , queryChildren + , queryChildrenAll + , queryById + , queryByClassName + , queryByClassList + , queryByStyle + , queryByTagName + , queryByAttribute + , queryByBoolAttribute + , getChildren + ) + +{-| +Query things using ElmHtml + +@docs Selector +@docs query, queryAll, queryChildren, queryChildrenAll, queryInNode +@docs queryById, queryByClassName, queryByClassList, queryByStyle, queryByTagName, queryByAttribute, queryByBoolAttribute +@docs getChildren +-} + +import Dict +import String +import ElmHtml.InternalTypes exposing (..) + + +{-| Selectors to query a Html element +- Id, classname, classlist, tag are all what you'd expect +- Attribute and bool attribute are attributes +- ConainsText just searches inside for the given text +-} +type Selector + = Id String + | ClassName String + | ClassList (List String) + | Tag String + | Attribute String String + | BoolAttribute String Bool + | Style (List ( String, String )) + | ContainsText String + | Multiple (List Selector) + + +{-| Query for a node with a given tag in a Html element +-} +queryByTagName : String -> ElmHtml msg -> List (ElmHtml msg) +queryByTagName tagname = + query (Tag tagname) + + +{-| Query for a node with a given id in a Html element +-} +queryById : String -> ElmHtml msg -> List (ElmHtml msg) +queryById id = + query (Id id) + + +{-| Query for a node with a given classname in a Html element +-} +queryByClassName : String -> ElmHtml msg -> List (ElmHtml msg) +queryByClassName classname = + query (ClassName classname) + + +{-| Query for a node with all the given classnames in a Html element +-} +queryByClassList : List String -> ElmHtml msg -> List (ElmHtml msg) +queryByClassList classList = + query (ClassList classList) + + +{-| Query for a node with the given style in a Html element +-} +queryByStyle : List ( String, String ) -> ElmHtml msg -> List (ElmHtml msg) +queryByStyle style = + query (Style style) + + +{-| Query for a node with a given attribute in a Html element +-} +queryByAttribute : String -> String -> ElmHtml msg -> List (ElmHtml msg) +queryByAttribute key value = + query (Attribute key value) + + +{-| Query for a node with a given attribute in a Html element +-} +queryByBoolAttribute : String -> Bool -> ElmHtml msg -> List (ElmHtml msg) +queryByBoolAttribute key value = + query (BoolAttribute key value) + + +{-| Query an ElmHtml element using a selector, searching all children. +-} +query : Selector -> ElmHtml msg -> List (ElmHtml msg) +query selector = + queryInNode selector + + +{-| Query an ElmHtml node using multiple selectors, considering both the node itself +as well as all of its descendants. +-} +queryAll : List Selector -> ElmHtml msg -> List (ElmHtml msg) +queryAll selectors = + query (Multiple selectors) + + +{-| Query an ElmHtml node using a selector, considering both the node itself +as well as all of its descendants. +-} +queryInNode : Selector -> ElmHtml msg -> List (ElmHtml msg) +queryInNode = + queryInNodeHelp Nothing + + +{-| Query an ElmHtml node using a selector, considering both the node itself +as well as all of its descendants. +-} +queryChildren : Selector -> ElmHtml msg -> List (ElmHtml msg) +queryChildren = + queryInNodeHelp (Just 1) + + +{-| Returns just the immediate children of an ElmHtml node +-} +getChildren : ElmHtml msg -> List (ElmHtml msg) +getChildren elmHtml = + case elmHtml of + NodeEntry { children } -> + children + + _ -> + [] + + +{-| Query to ensure an ElmHtml node has all selectors given, without considering +any descendants lower than its immediate children. +-} +queryChildrenAll : List Selector -> ElmHtml msg -> List (ElmHtml msg) +queryChildrenAll selectors = + queryInNodeHelp (Just 1) (Multiple selectors) + + +queryInNodeHelp : Maybe Int -> Selector -> ElmHtml msg -> List (ElmHtml msg) +queryInNodeHelp maxDescendantDepth selector node = + case node of + NodeEntry record -> + let + childEntries = + descendInQuery maxDescendantDepth selector record.children + in + if predicateFromSelector selector node then + node :: childEntries + else + childEntries + + TextTag { text } -> + case selector of + ContainsText innerText -> + if String.contains innerText text then + [ node ] + else + [] + + _ -> + [] + + MarkdownNode { facts, model } -> + if predicateFromSelector selector node then + [ node ] + else + [] + + _ -> + [] + + +descendInQuery : Maybe Int -> Selector -> List (ElmHtml msg) -> List (ElmHtml msg) +descendInQuery maxDescendantDepth selector children = + case maxDescendantDepth of + Nothing -> + -- No maximum, so continue. + List.concatMap + (queryInNodeHelp Nothing selector) + children + + Just depth -> + if depth > 0 then + -- Continue with maximum depth reduced by 1. + List.concatMap + (queryInNodeHelp (Just (depth - 1)) selector) + children + else + [] + + +predicateFromSelector : Selector -> ElmHtml msg -> Bool +predicateFromSelector selector html = + case html of + NodeEntry record -> + record + |> nodeRecordPredicate selector + + MarkdownNode markdownModel -> + markdownModel + |> markdownPredicate selector + + _ -> + False + + +hasAllSelectors : List Selector -> ElmHtml msg -> Bool +hasAllSelectors selectors record = + List.map predicateFromSelector selectors + |> List.map (\selector -> selector record) + |> List.all identity + + +hasAttribute : String -> String -> Facts msg -> Bool +hasAttribute attribute query facts = + case Dict.get attribute facts.stringAttributes of + Just id -> + id == query + + Nothing -> + False + + +hasBoolAttribute : String -> Bool -> Facts msg -> Bool +hasBoolAttribute attribute value facts = + case Dict.get attribute facts.boolAttributes of + Just id -> + id == value + + Nothing -> + False + + +hasClass : String -> Facts msg -> Bool +hasClass query facts = + List.member query (classnames facts) + + +hasClasses : List String -> Facts msg -> Bool +hasClasses classList facts = + containsAll classList (classnames facts) + + +hasStyle : List ( String, String ) -> Facts msg -> Bool +hasStyle style facts = + containsAll style (Dict.toList facts.styles) + + +classnames : Facts msg -> List String +classnames facts = + Dict.get "className" facts.stringAttributes + |> Maybe.withDefault "" + |> String.split " " + + +containsAll : List a -> List a -> Bool +containsAll a b = + b + |> List.foldl (\i acc -> List.filter ((/=) i) acc) a + |> List.isEmpty + + +nodeRecordPredicate : Selector -> (NodeRecord msg -> Bool) +nodeRecordPredicate selector = + case selector of + Id id -> + .facts + >> hasAttribute "id" id + + ClassName classname -> + .facts + >> hasClass classname + + ClassList classList -> + .facts + >> hasClasses classList + + Tag tag -> + .tag + >> (==) tag + + Attribute key value -> + .facts + >> hasAttribute key value + + BoolAttribute key value -> + .facts + >> hasBoolAttribute key value + + Style style -> + .facts + >> hasStyle style + + ContainsText text -> + always False + + Multiple selectors -> + NodeEntry + >> hasAllSelectors selectors + + +markdownPredicate : Selector -> (MarkdownNodeRecord msg -> Bool) +markdownPredicate selector = + case selector of + Id id -> + .facts + >> hasAttribute "id" id + + ClassName classname -> + .facts + >> hasClass classname + + ClassList classList -> + .facts + >> hasClasses classList + + Tag tag -> + always False + + Attribute key value -> + .facts + >> hasAttribute key value + + BoolAttribute key value -> + .facts + >> hasBoolAttribute key value + + Style style -> + .facts + >> hasStyle style + + ContainsText text -> + .model + >> .markdown + >> String.contains text + + Multiple selectors -> + MarkdownNode + >> hasAllSelectors selectors diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.gitignore b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.gitignore new file mode 100644 index 0000000..a594364 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.gitignore @@ -0,0 +1,4 @@ +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.travis.yml b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.travis.yml new file mode 100644 index 0000000..8e2e764 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/.travis.yml @@ -0,0 +1,31 @@ +sudo: false + +cache: + directories: + - tests/elm-stuff/build-artifacts + +os: + - osx + - linux + +env: + matrix: + - ELM_VERSION=0.18 TARGET_NODE_VERSION=node + - ELM_VERSION=0.18 TARGET_NODE_VERSION=4.2 + +before_install: + - if [ ${TRAVIS_OS_NAME} == "osx" ]; + then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh; + fi + +install: + - nvm install $TARGET_NODE_VERSION + - nvm use $TARGET_NODE_VERSION + - node --version + - npm --version + - npm install -g elm@$ELM_VERSION + - npm install -g elm-test@beta + + +script: + - elm-test diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/LICENSE b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/LICENSE new file mode 100644 index 0000000..cc2e236 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2016, Noah Hall, Richard Feldman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/README.md b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/README.md new file mode 100644 index 0000000..818fda3 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/README.md @@ -0,0 +1,122 @@ +# elm-html-test + +Test views by writing expectations about `Html` values. [![Build Status](https://travis-ci.org/eeue56/elm-html-test.svg?branch=master)](https://travis-ci.org/eeue56/elm-html-test) + +```elm +import Html +import Html.Attributes exposing (class) +import Test exposing (test) +import Test.Html.Query as Query +import Test.Html.Selector exposing (text, tag) + + +test "Button has the expected text" <| + \() -> + Html.div [ class "container" ] + [ Html.button [] [ Html.text "I'm a button!" ] ] + |> Query.fromHtml + |> Query.find [ tag "button" ] + |> Query.has [ text "I'm a button!" ] +``` + +These tests are designed to be written in a pipeline like this: + +1. Call [`Query.fromHtml`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#fromHtml) on your [`Html`](http://package.elm-lang.org/packages/elm-lang/html/latest/Html#Html) to begin querying it. +2. Use queries like [`Query.find`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#find), [`Query.findAll`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#findAll), and [`Query.children`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#children) to find the elements to test. +3. Create expectations using things like [`Query.has`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#has) and [`Query.count`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#count). + +These are normal expectations, so you can use them with [`fuzz`](http://package.elm-lang.org/packages/elm-community/elm-test/latest/Test#fuzz) just as easily as with [`test`](http://package.elm-lang.org/packages/elm-community/elm-test/3.1.0/Test#test)! + +## Querying + +Queries come in two flavors: [`Single`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#Single) and [`Multiple`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#Multiple). + +This is because some queries are expected to return a single result, whereas +others may return multiple results. + +If a `Single` query finds exactly one result, it will succeed and continue with +any further querying or expectations. If it finds zero results, or more than one, +the test will fail. + +Since other querying and expectation functions are written in terms of `Single` +and `Multiple`, the compiler can help make sure queries are connected as +expected. For example, [`count`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#count) accepts a `Multiple`, because counting a single element does not make much sense! + +If you have a `Multiple` and want to use an expectation that works on a `Single`, +such as [`Query.has`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#has), you can use [`Query.each`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Query#each) to run the expectation on each of the elements in the `Multiple`. + +## Selecting elements by `Html.Attribute msg` + +Ordinary `Html.Attribute msg` values can be used to select elements using +`Test.Html.Selector.attribute`. It is important when using this selector to +understand its behavior. + +- `Html.Attributes.class` and `Html.Attributes.classList` will work the same as + [`Test.Html.Selector.classes`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Selector#classes), + matching any element with at least the given classes. This behavior echoes + that of `element.querySelectorAll('.my-class')` from JavaScript, where any + element with at least `.my-class` will match the query. + +- `Html.Attributes.style` will work the same way as + [`Test.Html.Selector.styles`](http://package.elm-lang.org/packages/eeue56/elm-html-test/latest/Test-Html-Selector#styles), + matching any element with at least the given style properties. + +- Any other `String` attributes and properties like `title`, or `Bool` + attributes like `disabled` will match elements with the exact value for those + attributes. + +- Any attributes from `Html.Events`, or attributes with values that have types + other than `String` or `Bool` will not match anything. + +The example below demonstrates usage + +```elm +import Html +import Html.Attributes as Attr +import Test exposing (test, describe) +import Test.Html.Query as Query +import Test.Html.Selector exposing (attribute, text) + +tests = + describe "attributes" + [ test "the welcome

says hello!" <| + \() -> + Html.div [] [ Html.h1 [ Attr.title "greeting" ] [ Html.text "Hello!" ] ] + |> Query.fromHtml + |> Query.find [ attribute <| Attr.title "greeting" ] + |> Query.has [ text "Hello!" ] + , test "the .Hello.World div has the class Hello" <| + \() -> + Html.div + [ Attr.classList + [ ( True, "Hello" ) + , ( True, "World" ) + ] + ] + |> Query.fromHtml + |> Query.find + [ attribute <| + Attr.classList [ ( True, Hello ) ] + ] + , test "the header is red" <| + \() -> + Html.header + [ Attr.style + [ ( "backround-color", "red" ) + , ( "color", "yellow" ) + ] + ] + |> Query.fromHtml + |> Query.find + [ attribute <| + Attr.style [ ( "backround-color", "red" ) ] + ] + ] +``` + + +## Releases +| Version | Notes | +| ------- | ----- | +| [**1.1.0**](https://github.com/eeue56/elm-html-test/tree/1.1.0) | Support for events by @rogeriochaves +| [**1.0.0**](https://github.com/eeue56/elm-html-test/tree/1.0.0) | Initial release diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/elm-package.json b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/elm-package.json new file mode 100644 index 0000000..41455ac --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/elm-package.json @@ -0,0 +1,23 @@ +{ + "version": "5.1.1", + "summary": "Write tests for your Html.", + "repository": "https://github.com/eeue56/elm-html-test.git", + "license": "BSD3", + "source-directories": [ + "src" + ], + "exposed-modules": [ + "Test.Html.Selector", + "Test.Html.Query", + "Test.Html.Event" + ], + "native-modules": true, + "dependencies": { + "eeue56/elm-html-in-elm": "5.1.0 <= v < 6.0.0", + "eeue56/elm-html-query": "3.0.0 <= v < 4.0.0", + "elm-community/elm-test": "4.0.0 <= v < 5.0.0", + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/.travis.yml b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/.travis.yml new file mode 100644 index 0000000..458f91b --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/.travis.yml @@ -0,0 +1,46 @@ +sudo: false + +cache: + directories: + - test/elm-stuff/build-artifacts + - sysconfcpus + +os: + - osx + - linux + +env: + matrix: + - ELM_VERSION=0.18.0 TARGET_NODE_VERSION=node + - ELM_VERSION=0.18.0 TARGET_NODE_VERSION=4.0 + +before_install: + - if [ ${TRAVIS_OS_NAME} == "osx" ]; + then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh; + fi + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142 + if [ ! -d sysconfcpus/bin ]; + then + git clone https://github.com/obmarg/libsysconfcpus.git; + cd libsysconfcpus; + ./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus; + make && make install; + cd ..; + fi + +install: + - nvm install $TARGET_NODE_VERSION + - nvm use $TARGET_NODE_VERSION + - node --version + - npm --version + - cd tests + - npm install -g elm@$ELM_VERSION elm-test + - mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old + - printf '%s\n\n' '#!/bin/bash' 'echo "Running elm-make with sysconfcpus -n 2"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old "$@"' > $(npm config get prefix)/bin/elm-make + - chmod +x $(npm config get prefix)/bin/elm-make + - npm install + - elm package install --yes + +script: + - elm-test diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/ExampleApp.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/ExampleApp.elm new file mode 100644 index 0000000..fac7484 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/ExampleApp.elm @@ -0,0 +1,57 @@ +module ExampleApp exposing (..) + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onClick) +import Html.Keyed as Keyed +import Html.Lazy as Lazy + + +type alias Model = + () + + +exampleModel : Model +exampleModel = + () + + +type Msg + = GoToHome + | GoToExamples + + +view : Model -> Html Msg +view model = + div [ class "container" ] + [ header [ class "funky themed", id "heading" ] + [ a [ href "http://elm-lang.org", onClick GoToHome ] [ text "home" ] + , a [ href "http://elm-lang.org/examples", onClick GoToExamples ] [ text "examples" ] + , a [ href "http://elm-lang.org/docs" ] [ text "docs" ] + ] + , section [ class "funky themed", id "section" ] + [ someList ] + , footer [] [ text "this is the footer" ] + ] + + +someList : Html Msg +someList = + Keyed.ul [ class "some-list" ] + [ ( "1" + , Lazy.lazy (\_ -> li [ class "list-item themed" ] [ text "first item" ]) + Nothing + ) + , ( "2" + , Lazy.lazy (\_ -> li [ class "list-item themed" ] [ text "second item" ]) + Nothing + ) + , ( "3" + , Lazy.lazy (\_ -> li [ class "list-item themed selected" ] [ text "third item" ]) + Nothing + ) + , ( "4" + , Lazy.lazy (\_ -> li [ class "list-item themed" ] [ text "fourth item" ]) + Nothing + ) + ] diff --git a/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/FailingTests.elm b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/FailingTests.elm new file mode 100644 index 0000000..b89b6a1 --- /dev/null +++ b/part10/tests/elm-stuff/packages/eeue56/elm-html-test/5.1.1/examples/FailingTests.elm @@ -0,0 +1,117 @@ +port module Main exposing (..) + +import ExampleApp exposing (Msg(..), exampleModel, view) +import Expect +import Json.Encode exposing (Value) +import Test exposing (..) +import Test.Html.Event as Event +import Test.Html.Query as Query +import Test.Html.Selector exposing (..) +import Test.Runner.Node exposing (TestProgram, run) + + +main : TestProgram +main = + [ testView + ] + |> Test.concat + |> run emit + + +port emit : ( String, Value ) -> Cmd msg + + +testView : Test +testView = + let + output = + view exampleModel + |> Query.fromHtml + in + describe "view exampleModel" + [ test "expect 4x
  • somewhere on the page" <| + \() -> + output + |> Query.findAll [ tag "li" ] + |> Query.count (Expect.equal 4) + , test "expect 4x
  • inside a