diff --git a/elm/Elm.cabal b/Elm.cabal similarity index 77% rename from elm/Elm.cabal rename to Elm.cabal index 6a40f21..d304871 100644 --- a/elm/Elm.cabal +++ b/Elm.cabal @@ -1,6 +1,5 @@ - Name: Elm -Version: 0.7.2 +Version: 0.8 Synopsis: The Elm language module. Description: Elm aims to make client-side web-development more pleasant. It is a statically/strongly typed, functional reactive @@ -19,10 +18,11 @@ Copyright: Copyright: (c) 2011-2012 Evan Czaplicki Category: Compiler, Language -Build-type: Simple +Build-type: Custom Extra-source-files: changelog.txt -Data-files: elm-runtime-0.7.2.js +Data-dir: dist/data +Data-files: elm-runtime.js docs.json Cabal-version: >=1.8 source-repository head @@ -32,7 +32,7 @@ source-repository head Library exposed-modules: Language.Elm, Language.Elm.Quasi - Hs-Source-Dirs: src, src/Gen + Hs-Source-Dirs: compiler, compiler/Gen, compiler/Model, compiler/Transform other-modules: Ast, Context, CompileToJS, @@ -41,6 +41,8 @@ Library ExtractNoscript, GenerateHtml, Guid, + Libraries, + LoadLibraries, Optimize, Initialize, Rename, @@ -65,10 +67,10 @@ Library containers >= 0.3, transformers >= 0.2, mtl >= 2, + deepseq, parsec >= 3.1.1, blaze-html == 0.5.* || == 0.6.*, blaze-markup == 0.5.1.*, - deepseq, text, template-haskell, shakespeare >= 1, @@ -76,11 +78,16 @@ Library bytestring, hjsmin, indents, - filepath + filepath, + template-haskell, + json, + directory Executable elm Main-is: Compiler.hs - Hs-Source-Dirs: src, src/Gen + Hs-Source-Dirs: compiler, compiler/Gen, compiler/Model, compiler/Transform + extensions: CPP + cpp-options: -DELM_COMPILEDATADIR="dist/data" other-modules: Ast, Context, CompileToJS, @@ -89,6 +96,8 @@ Executable elm ExtractNoscript, GenerateHtml, Guid, + Libraries, + LoadLibraries, Optimize, Initialize, Rename, @@ -113,15 +122,16 @@ Executable elm containers >= 0.3, transformers >= 0.2, mtl >= 2, + deepseq, parsec >= 3.1.1, blaze-html == 0.5.* || == 0.6.*, blaze-markup == 0.5.1.*, - deepseq, cmdargs, pandoc >= 1.10, bytestring, hjsmin, indents, +<<<<<<< .mine filepath @@ -154,3 +164,37 @@ test-suite Main hs-source-dirs: src, tests main-is: Main.hs +======= + filepath, + template-haskell, + json, + directory + +Executable elm-doc + Main-is: Docs.hs + Hs-Source-Dirs: compiler, compiler/Model, compiler/Transform + other-modules: Ast, + Context, + Parse.Library, + Parse.Modules, + Rename + + Build-depends: base >=4.2 && <5, + containers >= 0.3, + transformers >= 0.2, + mtl >= 2, + parsec >= 3.1.1, + pandoc >= 1.10, + cmdargs, + indents + + + + + + + + + + +>>>>>>> .theirs diff --git a/Examples/elm-happstack/Main.hs b/Examples/elm-happstack/Main.hs deleted file mode 100644 index 93f660c..0000000 --- a/Examples/elm-happstack/Main.hs +++ /dev/null @@ -1,71 +0,0 @@ -{-# LANGUAGE QuasiQuotes, TemplateHaskell #-} - -import Control.Monad (msum) -import Happstack.Server -import Language.Elm -import Language.Elm.Quasi - -elmRuntime="elm-runtime.js" -elmRTPath='/':elmRuntime - --- elmResponse is a "nice to have" helper function for compiling --- Elm code when using Elm with Happstack. At some point this might --- be moved to an elm-happstack package. -elmResponse :: ElmSource a - => String -- ^ Page title - -> a -- ^ elm source - -> Response -elmResponse title = toResponse . toHtml elmRTPath title - --- embedding variables (in this case URLs) -rootHandler :: ServerPart Response -rootHandler = ok $ elmResponse "Welcome!" $ elmIndex - where - mouse = "/mouse" -- all three of these variables are used in elm_source/index.elm - clock = "/clock" - shapes = "/shapes" - elmIndex = $(elmFile "elm_source/index.elm") - --- loading elm source from file - -mouseHandler :: ServerPart Response -mouseHandler = ok $ elmResponse "Mouse position demo" - $(elmFile "elm_source/mouse.elm") - -clockHandler :: ServerPart Response -clockHandler = ok $ elmResponse "A clock" $(elmFile "elm_source/clock.elm") - --- embedding elm code inside Haskell using the QuasiQuoter: -shapesPage = [elm| -square = rect 200 200 (150,150) -circle = oval 140 140 (150,150) -pentagon = ngon 5 60 (150,150) - -main = collage 300 300 - [ outlined black square - , filled green pentagon - , customOutline [8,4] blue circle - ] -|] - -shapesHandler :: ServerPart Response -shapesHandler = ok $ elmResponse "Simple shapes" $ shapesPage - --- routing -elmExample :: String -> ServerPart Response -elmExample elmLoc = do - msum [ nullDir >> rootHandler - , dir elmRuntime $ nullDir >> - serveFile (guessContentTypeM mimeTypes) elmLoc - , dir "mouse" $ nullDir >> - mouseHandler - , dir "clock" $ nullDir >> - clockHandler - , dir "shapes" $ nullDir >> - shapesHandler - ] - -main :: IO () -main = do - elmLoc <- Language.Elm.runtimeLocation - simpleHTTP nullConf {port = 3000} $ elmExample elmLoc diff --git a/Examples/elm-happstack/elm_source/clock.elm b/Examples/elm-happstack/elm_source/clock.elm deleted file mode 100644 index 37c35fa..0000000 --- a/Examples/elm-happstack/elm_source/clock.elm +++ /dev/null @@ -1,13 +0,0 @@ - -import Time (every) - -hand clr len time = - let t = pi * time / 30 - pi / 2 in - solid clr $ line [(200,200), (200 + len * cos t, 200 + len * sin t)] - -clock t = collage 400 400 [ filled (rgb 96 176 224) $ ngon 12 110 (200, 200) - , hand red 100 t - , hand black 100 (t/60) - , hand black 60 (t/720) ] - -main = lift clock (every 1) diff --git a/Examples/elm-happstack/elm_source/index.elm b/Examples/elm-happstack/elm_source/index.elm deleted file mode 100644 index b8d73ba..0000000 --- a/Examples/elm-happstack/elm_source/index.elm +++ /dev/null @@ -1,44 +0,0 @@ -title w = size w 60 . text . header . toText $ "Elm-Happstack" - -lightGrey = rgb 240 241 244 -mediumGrey = rgb 216 221 225 -heading outer inner = - color mediumGrey . size outer 61 . - color lightGrey . size outer 60 . - size inner 60 $ title inner - -skeleton body outer = - let inner = if outer < 820 then outer - 20 else 800 in - flow down [ heading outer inner - , body outer inner - ] - ----------------------- - -section = text . bold . Text.height (5/4) . toText - --- splicing of values works but literal substitution of strings --- for this reason, we need to have quotes. -mouseLink = "#{mouse}" -clockLink = "#{clock}" -shapesLink = "#{shapes}" - - -info w = List.map (\f -> f ()) . List.intersperse (\x -> plainText " ") . List.map ((\e x -> e) . width w) $ - [ section "Written in Elm, served with Happstack" - , text $ toText "This page is written in " ++ Text.link "http://elm-lang.org/" (toText "Elm") ++ - toText " and served using the " ++ - Text.link "http://happstack.com/" (toText "Happstack Web Framework") ++ - toText ". Since you are looking at this page it is safe to assume that you already have the example code. " - , text $ toText "URLs are rendered using simple QuasiQuoter variable interpolation." - , section "More examples:" - , text $ toText "- " ++ Text.link mouseLink (toText "A simple mouse input example") - , text $ toText "- " ++ Text.link clockLink (toText "An animated analog clock") - , text $ toText "- " ++ Text.link shapesLink (toText "Some simple rendered shapes") - ] - --- The following line does not parse, replaced it something slightly different --- body outer inner = width outer . flow down $ (:) (plainText " ") $ info inner -body outer inner = width outer . flow down $ info inner - -main = lift (skeleton body) Window.width diff --git a/Examples/elm-happstack/elm_source/mouse.elm b/Examples/elm-happstack/elm_source/mouse.elm deleted file mode 100644 index 71c0c7c..0000000 --- a/Examples/elm-happstack/elm_source/mouse.elm +++ /dev/null @@ -1,15 +0,0 @@ - --- Move your mouse around above the canvas! - -import Mouse (position) -import Window (dimensions) - -myBlue = rgb 0 85 170 -myGreen = rgba 28 267 85 (1/2) - -scene (x,y) (w,h) = - collage w h [ rotate (toFloat (x+y) / 1000) $ filled myBlue $ ngon 4 100 (200,200) - , filled myGreen $ ngon 5 30 (x,y) - ] - -main = lift2 scene Mouse.position Window.dimensions diff --git a/Examples/elm-js/GameSkeleton/GameSkeleton.elm b/Examples/elm-js/GameSkeleton/GameSkeleton.elm deleted file mode 100644 index a3a8256..0000000 --- a/Examples/elm-js/GameSkeleton/GameSkeleton.elm +++ /dev/null @@ -1,82 +0,0 @@ -module GameSkeleton where - - - -{-- Part 1: Model the user input ---------------------------------------------- - -What information do you need to represent all relevant user input? - -Task: Redefine `UserInput` to include all of the information you need. - Redefine `userInput` to be a signal that correctly models the user - input as described by `UserInput`. - -------------------------------------------------------------------------------} - -data UserInput = UserInput - -userInput = constant UserInput - -data Input = Input Float UserInput - - - -{-- Part 2: Model the game ---------------------------------------------------- - -What information do you need to represent the entire game? - -Tasks: Redefine `GameState` to represent your particular game. - Redefine `defaultGame` to represent your initial game state. - -For example, if you want to represent many objects that just have a position, -your GameState might just be a list of coordinates and your default game might -be an empty list (no objects at the start): - - data GameState = GameState [(Float,Float)] - defaultGame = GameState [] - -------------------------------------------------------------------------------} - -data GameState = GameState - -defaultGame = GameState - - - -{-- Part 3: Update the game --------------------------------------------------- - -How does the game step from one state to another based on user input? - -Task: redefine `stepGame` to use the UserInput and GameState - you defined in parts 1 and 2. Maybe use some helper functions - to break up the work, stepping smaller parts of the game. - -------------------------------------------------------------------------------} - -stepGame (Input delta (UserInput)) (GameState) = GameState - - - -{-- Part 4: Display the game -------------------------------------------------- - -How should the GameState be displayed to the user? - -Task: redefine `display` to use the GameState you defined in part 2. - -------------------------------------------------------------------------------} - -display (w,h) gameState = asText gameState - - - -{-- That's all folks! --------------------------------------------------------- - -The following code puts it all together and show it on screen. - -------------------------------------------------------------------------------} - -delta = fps 60 -input = sampleOn delta (lift2 Input delta userInput) - -gameState = foldp stepGame defaultGame input - -main = lift2 display Window.dimensions gameState diff --git a/Examples/elm-js/Logging/Log.elm b/Examples/elm-js/Logging/Log.elm deleted file mode 100644 index 3dcaf25..0000000 --- a/Examples/elm-js/Logging/Log.elm +++ /dev/null @@ -1,17 +0,0 @@ - -module Log where - -import Foreign.JavaScript -import Signal.Input - - -foreign export jsevent "logMessage" - messages :: Signal JSString - -(field, message) = textField "" -(butn , pressed) = button " Log " - -messages = - lift castStringToJSString $ keepWhen pressed "" message - -main = field `beside` butn \ No newline at end of file diff --git a/Examples/elm-js/Logging/LogHelp.js b/Examples/elm-js/Logging/LogHelp.js deleted file mode 100644 index b485d81..0000000 --- a/Examples/elm-js/Logging/LogHelp.js +++ /dev/null @@ -1,3 +0,0 @@ -document.addEventListener('logMessage', function(e) { - console.log(e.value); - }); \ No newline at end of file diff --git a/Examples/elm-js/Logging/README.md b/Examples/elm-js/Logging/README.md deleted file mode 100644 index aaeb22d..0000000 --- a/Examples/elm-js/Logging/README.md +++ /dev/null @@ -1,16 +0,0 @@ - -To compile this example yourself use: - - elm --import-js="LogHelp.js" Log.elm - -This compiles the Elm file and includes the necessary JavaScript code. -It produces a self-contained HTML file. - - -You can see the logged messages in the developer console of your browser. -The keyboard shortcut is F12 in many browsers. - - -Note: Not all browsers like reading the elm-runtime-x.y.z.js file from -an absolute path, so you may have to specify a relative path with -the --runtime flag (e.g. --runtime="../../../elm/elm-runtime-0.3.5.js"). diff --git a/Examples/elm-js/Maps/Map.elm b/Examples/elm-js/Maps/Map.elm deleted file mode 100644 index 6572fbb..0000000 --- a/Examples/elm-js/Maps/Map.elm +++ /dev/null @@ -1,14 +0,0 @@ - -module Map where - -import JavaScript.Experimental - -foreign import jsevent "provideMap" - (castElementToJSElement $ spacer 640 360) - jsMaps :: Signal JSElement - - -center (w,h) elem = container w h middle elem -maps = lift (castJSElementToElement 640 360) jsMaps - -main = lift2 center Window.dimensions maps \ No newline at end of file diff --git a/Examples/elm-js/Maps/MapHelp.js b/Examples/elm-js/Maps/MapHelp.js deleted file mode 100644 index db62a69..0000000 --- a/Examples/elm-js/Maps/MapHelp.js +++ /dev/null @@ -1,25 +0,0 @@ - -document.body.onload = function() { - -var lib = document.createElement('script'); -lib.addEventListener('load', function() { - var div = document.createElement('div'); - div.id = "demoMap"; - div.style.width = "640px"; - div.style.height = "360px"; - - var e = document.createEvent('Event'); - e.initEvent('provideMap', true, true); - e.value = div; - document.dispatchEvent(e); - - setTimeout(function() { - var map = new OpenLayers.Map("demoMap"); - map.addLayer(new OpenLayers.Layer.OSM()); - map.zoomToMaxExtent(); - }, 0); - }); -lib.src = "http://www.openlayers.org/api/OpenLayers.js"; -document.head.appendChild(lib); - -} \ No newline at end of file diff --git a/Examples/elm-js/Maps/README.md b/Examples/elm-js/Maps/README.md deleted file mode 100644 index 6fa505d..0000000 --- a/Examples/elm-js/Maps/README.md +++ /dev/null @@ -1,15 +0,0 @@ - -To compile this example yourself use: - - elm --import-js="MapHelp.js" Map.elm - -This compiles the Elm file and includes the necessary JavaScript code. -It produces a self-contained HTML file. - - -Note: Not all browsers like reading the elm-runtime-x.y.z.js file from -an absolute path, so you may have to specify a relative path with -the --runtime flag (e.g. --runtime="../../../elm/elm-runtime-0.3.5.js"). - -Warning: I am not sure how stable the OpenLayers API is. This is for -example only! diff --git a/Examples/elm-js/Pong/Pong.elm b/Examples/elm-js/Pong/Pong.elm deleted file mode 100644 index abe1820..0000000 --- a/Examples/elm-js/Pong/Pong.elm +++ /dev/null @@ -1,263 +0,0 @@ - -{----- Overview ------------------------------------------------------ - - This game displays some of the strengths of Functional Reactive - Programming (FRP). By the end of this file we will have written an - entire GUI/game without any imperative code! No global mutable state, - no flipping pixels, no destructive updates. In fact, Elm disallows all - of these things at the language level. So good design and safe coding - practices are a requirement, not just self-inforced suggestions. - - This code neatly divides Pong into three major parts: modeling the - game, updating the game, and viewing the game. It may be helpful to - think of it as a functional variation on the Model-View-Controller - paradigm. - - The code for Pong is structured as follows: - - 1. MODEL: - First we need to define Pong. We do this by modelling Pong with - simple data structures. We need two categories of model: - - Inputs to the game. For Pong, this is keyboard input from - users and clock-ticks from the frame rate manager. - - A model of the game itself: paddles, ball, score, etc. - Without a model of the game we would have nothing to update - or display! - These models are the basis for the next two sections, holding - all of the information about Pong that we will need. - - 2. UPDATE: - When new inputs come in, we need to update the current state - of the game. Without updates, this version of Pong would be very - very boring! This section defines a number of 'step functions' - that step the game forward based on our inputs. By separating - this from the model and display code, we can change how the game - works (how it steps forward) without changing anything else: the - underlying model and the display code need not be touched. - - 3. VIEW: - Finally, we need a display function that defines the user's view - of the game. This code is separate from the game logic, so like - the update logic, it can be modified without affecting any other - part of the program. We can also define many different views - of the same underlying model. In Pong there's not much need for - this, but as your model becomes more complex this may be very - useful! - - If you would like to make a game or larger application in Elm, use - this structure! Maybe even use this file as a starting point for - playing around with your own ideas. - - Let's get started! - ------------------------------------------------------------------------} - - -module Pong where - -import JavaScript - - --- Set the frames per second (FPS) to 60, calculate the deltas (the --- difference between the two latest times, the amount of time since --- the last frame), and convert the time into a number of seconds. - -delta = lift inSeconds (fps 60) - - ------------------------------------------------------------------------- ------- Modelling User Input ------ ------------------------------------------------------------------------- - --- During gameplay, all keyboard input is about the position of the --- two paddles. So the keyboard input can be reduced to two directions, --- each represented by an integer in {-1,0,1}. Furthermore, the SPACE --- key is used to start the game between rounds, so we also need a --- boolean value to represent whether it is pressed. - -data KeyInput = KeyInput Bool Int Int - -defaultKeyInput = KeyInput False 0 0 - -keyInput = lift3 KeyInput Keyboard.space - (lift .y Keyboard.wasd) - (lift .y Keyboard.arrows) - - ------------------------------------------------------------------------- ------- Combining all inputs ------ ------------------------------------------------------------------------- - --- The inputs to this game include a timestep (which we extracted from --- JavaScript) and the keyboard input from the users. - -data Input = Input Float KeyInput - --- Combine both kinds of inputs and filter out keyboard events. We only --- want the game to refresh on clock-ticks, not key presses too. - -input = sampleOn delta (lift2 Input delta keyInput) - - - ------------------------------------------------------------------------- ------- Modelling Pong / a State Machine ------ ------------------------------------------------------------------------- - --- Pong has two obvious components: the ball and two paddles. - -data Paddle = Paddle Float -- y-position -data Ball = Ball (Float,Float) (Float,Float) -- position and velocity - --- But we also want to keep track of the current score and whether --- the ball is currently in play. This will allow us to have rounds --- of play rather than just having the ball move around continuously. - -data Score = Score Int Int -data State = Play | BetweenRounds - --- Together, this information makes up the state of the game. We model --- Pong by using the inputs (defined above) to update the state of the --- game! - -data GameState = GameState State Score Ball Paddle Paddle - - --- I have chosen to parameterize the size of the board, so it can --- be changed with minimal effort. - -gameWidth = 600 -gameHeight = 400 -halfWidth = gameWidth / 2 -halfHeight = gameHeight / 2 - - --- Before we can update anything, we must first define the default --- configuration of the game. In our case we want to start between --- rounds with a score of zero to zero. - -defaultGame = GameState BetweenRounds - (Score 0 0) - (Ball (halfWidth, halfHeight) (150,150)) - (Paddle halfHeight) - (Paddle halfHeight) - - - ------------------------------------------------------------------------- ------- Stepping from State to State ------ ------------------------------------------------------------------------- - --- Now to step the game from one state to another. We can break this up --- into smaller components. - --- First, we define a step function for updating the position of --- paddles. It depends on our timestep and a desired direction (given --- by keyboard input). - -stepPaddle delta dir (Paddle y) = - Paddle $ clamp 20 (gameHeight-20) (y - toFloat dir * 200 * delta) - - --- We must also step the ball forward. This is more complicated due to --- the many kinds of collisions that can happen. All together, this --- function figures out the new velocity of the ball based on --- collisions with the top and bottom borders and collisions with the --- paddles. This new velocity is used to calculate a new position. - --- This function also determines whether a point has been scored and --- who receives the point. Thus, its output is a new Ball and points --- to be added to each player. - -makePositive n = if n > 0 then n else 0-n -makeNegative n = if n > 0 then 0-n else n -within epsilon n x = x > n - epsilon && x < n + epsilon - -stepVelocity velocity lowerCollision upperCollision = - if lowerCollision then makePositive velocity else - if upperCollision then makeNegative velocity else velocity - -stepBall delta (Ball (x,y) (vx,vy)) (Paddle y1) (Paddle y2) = - let hitPaddle1 = within 20 y1 y && within 8 25 x - hitPaddle2 = within 20 y2 y && within 8 (gameWidth - 25) x - vx' = stepVelocity vx hitPaddle1 hitPaddle2 - vy' = stepVelocity vy (y < 7) (y > gameHeight - 7) - scored = x > gameWidth || x < 0 - x' = if scored then halfWidth else x + vx' * delta - y' = if scored then halfHeight else y + vy' * delta - in ( Ball (x',y') (vx',vy') - , if x > gameWidth then 1 else 0 - , if x < 0 then 1 else 0 ) - - --- Finally, we define a step function for the entire game. This steps from state to --- state based on the inputs to the game. - -stepGame (Input delta (KeyInput space dir1 dir2)) - (GameState state (Score s1 s2) ball paddle1 paddle2) = - let (ball',s1',s2') = if state == Play then stepBall delta ball paddle1 paddle2 - else (ball, 0, 0) - state' = case state of - Play -> if s1' /= s2' then BetweenRounds else state - BetweenRounds -> if space then Play else state - in GameState state' - (Score (s1+s1') (s2+s2')) - ball' - (stepPaddle delta dir1 paddle1) - (stepPaddle delta dir2 paddle2) - - --- Now we put it all together. We have a signal of inputs that changes whenever there --- is a clock tick. This input signal carries the all the information we need about --- the keyboard. We also have a step function that steps from one game-state to the --- next based on some inputs. - --- The `gameState` signal steps forward every time a new input comes in. It starts --- as the default game and progresses based on user behavior. - -gameState = foldp stepGame defaultGame input - - - ------------------------------------------------------------------------- ------- Displaying the Game ------ ------------------------------------------------------------------------- - --- These functions take a GameState and turn it into something a user --- can see and understand. It is totally independent of how the game --- updates, it only needs to know the current game state. This allows us --- to change how the game looks without changing any of the logic of the --- game. - - --- This function displays the current score and directions. - -scoreBoard w inPlay p1 p2 = - let code = text . monospace . toText - stack top bottom = flow down [ code " ", code top, code bottom ] - msg = width w . centeredText . monospace $ toText "Press SPACE to begin" - board = flow right [ stack "W" "S", spacer 20 1 - , text . Text.height 4 . toText $ show p1 ++ " " ++ show p2 - , spacer 20 1, stack "↑" "↓" ] - score = container w (heightOf board) midTop board - in if inPlay then score else score `above` msg - - --- This function displays the entire GameState. - -display (w,h) (GameState state (Score p1 p2) (Ball pos _) (Paddle y1) (Paddle y2)) = - layers - [ let pongGreen = rgb 60 100 60 in - container w h middle $ collage gameWidth gameHeight - [ filled pongGreen (rect gameWidth gameHeight (halfWidth,halfHeight)) - , filled white (oval 15 15 pos) -- ball - , filled white (rect 10 40 ( 20, y1)) -- first paddle - , filled white (rect 10 40 (gameWidth - 20, y2)) -- second paddle - ] - , scoreBoard w (state == Play) p1 p2 - ] - --- We can now define a view of the game (a signal of Elements) that changes --- as the GameState changes. This is what the users will see. - -main = lift2 display Window.dimensions gameState diff --git a/Examples/elm-js/Pong/README.md b/Examples/elm-js/Pong/README.md deleted file mode 100644 index 7adc5f0..0000000 --- a/Examples/elm-js/Pong/README.md +++ /dev/null @@ -1,11 +0,0 @@ - - -To compile this example yourself use: - - elm Pong.elm - -It produces a self-contained HTML file called Pong.html. - -As of version 0.6 of the compiler, no external code is necessary -to make this work, so the code is slightly cleaner and simpler than -the "Pong in Elm" walkthrough. diff --git a/Examples/elm-js/Redirect/README.md b/Examples/elm-js/Redirect/README.md deleted file mode 100644 index 30fcf7f..0000000 --- a/Examples/elm-js/Redirect/README.md +++ /dev/null @@ -1,12 +0,0 @@ - -To compile this example yourself use: - - elm --import-js="RedirectHelp.js" Redirect.elm - -This compiles the Elm file and includes the necessary JavaScript code. -It produces a self-contained HTML file. - - -Note: Not all browsers like reading the elm-runtime-x.y.z.js file from -an absolute path, so you may have to specify a relative path with -the --runtime flag (e.g. --runtime="../../../elm/elm-runtime-0.3.5.js"). diff --git a/Examples/elm-js/Redirect/Redirect.elm b/Examples/elm-js/Redirect/Redirect.elm deleted file mode 100644 index 481ccce..0000000 --- a/Examples/elm-js/Redirect/Redirect.elm +++ /dev/null @@ -1,17 +0,0 @@ - -module Redirect where - -import Foreign.JavaScript -import Signal.Input - - -foreign export jsevent "redirect" - redirectTo :: Signal JSString - -(butn, pressed) = button " Redirect to elm-lang.org " - -redirectTo = - lift castStringToJSString $ - keepWhen pressed "" (constant "http://elm-lang.org/") - -main = butn \ No newline at end of file diff --git a/Examples/elm-js/Redirect/RedirectHelp.js b/Examples/elm-js/Redirect/RedirectHelp.js deleted file mode 100644 index 69a7616..0000000 --- a/Examples/elm-js/Redirect/RedirectHelp.js +++ /dev/null @@ -1,3 +0,0 @@ -document.addEventListener('redirect', function(e) { - if (e.value.length > 0) { window.location = e.value; } - }); \ No newline at end of file diff --git a/Examples/elm-js/Title/ChangeTitle.elm b/Examples/elm-js/Title/ChangeTitle.elm deleted file mode 100644 index 0b9c046..0000000 --- a/Examples/elm-js/Title/ChangeTitle.elm +++ /dev/null @@ -1,14 +0,0 @@ - -module ChangeTitle where - -import Foreign.JavaScript -import Signal.Input - - -foreign export jsevent "changeTitle" - title :: Signal JSString - -(field, title) = let (f,t) = textField "" in - (f, lift castStringToJSString t) - -main = plainText "Change this page's title to: " `beside` field \ No newline at end of file diff --git a/Examples/elm-js/Title/ChangeTitleHelp.js b/Examples/elm-js/Title/ChangeTitleHelp.js deleted file mode 100644 index 66bcd9d..0000000 --- a/Examples/elm-js/Title/ChangeTitleHelp.js +++ /dev/null @@ -1,3 +0,0 @@ -document.addEventListener('changeTitle', function(e) { - document.title = e.value; - }); \ No newline at end of file diff --git a/Examples/elm-js/Title/README.md b/Examples/elm-js/Title/README.md deleted file mode 100644 index 3ba36d9..0000000 --- a/Examples/elm-js/Title/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -To compile this example yourself use: - - elm --import-js="ChangeTitleHelp.js" ChangeTitle.elm - -This compiles the Elm file and includes the necessary JavaScript code. -It produces a self-contained HTML file. diff --git a/Examples/elm-yesod/Main.hs b/Examples/elm-yesod/Main.hs deleted file mode 100644 index 195de31..0000000 --- a/Examples/elm-yesod/Main.hs +++ /dev/null @@ -1,81 +0,0 @@ -{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings, TypeFamilies, MultiParamTypeClasses #-} - -import Language.Elm -import Language.Elm.Quasi -import Language.Elm.Yesod -import Yesod -import Text.Hamlet - -data ElmTest = ElmTest - --- loading external elm code -mousePage = $(elmFile "elm_source/mouse.elm") - -clockPage = $(elmFile "elm_source/clock.elm") - --- embedding elm code inside Haskell using the QuasiQuoter: -shapesPage = [elm| -square = rect 200 200 (150,150) -circle = oval 140 140 (150,150) -pentagon = ngon 5 60 (150,150) - -main = collage 300 300 - [ outlined black square - , filled green pentagon - , customOutline [8,4] blue circle - ] -|] - --- our Yesod App -mkYesod "ElmTest" [parseRoutes| -/ RootR GET -/mouse MouseR GET -/clock ClockR GET -/shapes ShapesR GET -|] - --- Your App data type needs to have an instance of YesodElm (see line 75&76) --- so that toWidget can work with QuasiQuoted elm code. All URL interpolation --- is done automatically. (e.g. lines 28-30 in elm_source/index.elm) -getMouseR :: Handler RepHtml -getMouseR = - defaultLayout $ do - setTitle "Mouse position demo" - toWidget mousePage - -getClockR :: Handler RepHtml -getClockR = - defaultLayout $ do - setTitle "A clock" - toWidget clockPage - -getShapesR :: Handler RepHtml -getShapesR = - defaultLayout $ do - setTitle "Simple shapes" - toWidget shapesPage - -getRootR :: Handler RepHtml -getRootR = - defaultLayout $ do - setTitle "Welcome!" - toWidget $(elmFile "elm_source/index.elm") - - --- Our Yesod instance contains the default layout, which inserts the elm-min.js --- file in the site's tag. The YesodElm instance defines the location of --- elm-min.js - -instance Yesod ElmTest where - jsLoader _ = BottomOfHeadBlocking - defaultLayout widget = do - mmsg <- getMessage - pc <- widgetToPageContent $ do - $(whamletFile "templates/default-layout.hamlet") - hamletToRepHtml $(hamletFile "templates/default-layout-wrapper.hamlet") - -instance YesodElm ElmTest where - urlElmJs _ = Right $ "https://raw.github.com/evancz/Elm/master/elm/elm-runtime-0.7.2.js" - -main :: IO () -main = warpDebug 3000 ElmTest \ No newline at end of file diff --git a/Examples/elm-yesod/elm_source/clock.elm b/Examples/elm-yesod/elm_source/clock.elm deleted file mode 100644 index b4c79b3..0000000 --- a/Examples/elm-yesod/elm_source/clock.elm +++ /dev/null @@ -1,11 +0,0 @@ - -hand clr len time = - let t = pi * inSeconds time / 30 - pi / 2 in - solid clr $ line [(200,200), (200 + len * cos t, 200 + len * sin t)] - -clock t = collage 400 400 [ filled (rgb 96 176 224) $ ngon 12 110 (200, 200) - , hand red 100 t - , hand black 100 (t/60) - , hand black 60 (t/720) ] - -main = lift clock (every second) diff --git a/Examples/elm-yesod/elm_source/index.elm b/Examples/elm-yesod/elm_source/index.elm deleted file mode 100644 index f372f7f..0000000 --- a/Examples/elm-yesod/elm_source/index.elm +++ /dev/null @@ -1,35 +0,0 @@ -title w = size w 60 . text . header . toText $ "Elm-Yesod" - -lightGrey = rgb 240 241 244 -mediumGrey = rgb 216 221 225 -heading outer inner = - color mediumGrey . size outer 61 . - color lightGrey . size outer 60 . - size inner 60 $ title inner - -skeleton body outer = - let inner = if outer < 820 then outer - 20 else 800 in - flow down [ heading outer inner - , body outer inner - ] - ----------------------- - -section = text . bold . Text.height (5/4) . toText - -info w = List.map (\f -> f ()) . List.intersperse (\x -> plainText " ") . List.map ((\e x -> e) . width w) $ - [ section "Written in Elm, served with Yesod" - , text $ toText "This page is written in " ++ Text.link "http://elm-lang.org/" (toText "Elm") ++ - toText " and served using the " ++ - Text.link "http://yesodweb.com/" (toText "Yesod Web Framework") ++ - toText ". Since you are looking at this page it is safe to assume that you already have the example code. " - , text $ toText "Type-safe URLs are rendered using simple QuasiQuoter variable interpolation." - , section "More examples:" - , text $ toText "- " ++ Text.link "@{MouseR}" (toText "A simple mouse input example") - , text $ toText "- " ++ Text.link "@{ClockR}" (toText "An animated analog clock") - , text $ toText "- " ++ Text.link "@{ShapesR}" (toText "Some simple rendered shapes") - ] - -body outer inner = width outer . flow down . (:) (plainText " ") $ info inner - -main = lift (skeleton body) Window.width diff --git a/Examples/elm-yesod/elm_source/mouse.elm b/Examples/elm-yesod/elm_source/mouse.elm deleted file mode 100644 index 6a8531f..0000000 --- a/Examples/elm-yesod/elm_source/mouse.elm +++ /dev/null @@ -1,13 +0,0 @@ - --- Move your mouse around above the canvas! - -myBlue = rgb 0 85 170 -myGreen = rgba 28 267 85 0.5 - -scene (x,y) (w,h) = - collage w h - [ rotate (toFloat (x+y) / 1000) (filled myBlue (ngon 4 100 (200,200))) - , filled myGreen (ngon 5 30 (x,y)) - ] - -main = lift2 scene Mouse.position Window.dimensions diff --git a/Examples/elm-yesod/templates/default-layout-wrapper.hamlet b/Examples/elm-yesod/templates/default-layout-wrapper.hamlet deleted file mode 100644 index 576e365..0000000 --- a/Examples/elm-yesod/templates/default-layout-wrapper.hamlet +++ /dev/null @@ -1,8 +0,0 @@ -$doctype 5 - - - - #{pageTitle pc} - ^{pageHead pc} - <body> - ^{pageBody pc} \ No newline at end of file diff --git a/Examples/elm-yesod/templates/default-layout.hamlet b/Examples/elm-yesod/templates/default-layout.hamlet deleted file mode 100644 index 58c9295..0000000 --- a/Examples/elm-yesod/templates/default-layout.hamlet +++ /dev/null @@ -1,3 +0,0 @@ -$maybe msg <- mmsg - <div .message>#{msg} -^{widget} \ No newline at end of file diff --git a/Examples/mario_mp/.gitignore b/Examples/mario_mp/.gitignore deleted file mode 100644 index 466bedf..0000000 --- a/Examples/mario_mp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.html -mario_mp diff --git a/Examples/mario_mp/Clicks.elm b/Examples/mario_mp/Clicks.elm deleted file mode 100644 index fa12120..0000000 --- a/Examples/mario_mp/Clicks.elm +++ /dev/null @@ -1,6 +0,0 @@ - -module Clicks where -import WebSocket -msgs = show <~ count Mouse.clicks -main = asText <~ open "ws://localhost:8080/ws" msgs - diff --git a/Examples/mario_mp/Mario.elm b/Examples/mario_mp/Mario.elm deleted file mode 100644 index 4830ecf..0000000 --- a/Examples/mario_mp/Mario.elm +++ /dev/null @@ -1,91 +0,0 @@ - -module Mario where - -import Dict -import JavaScript -import JSON -import Random -import WebSocket - -{- INPUT -} - -jumpStep isJump obj = if isJump && obj.y == 0 then { obj | vy <- 5 } else obj -gravityStep t obj = { obj | vy <- if obj.y > 0 then obj.vy - t/4 else obj.vy } -timeStep t obj = let {x,y,vx,vy} = obj in - { obj | x <- x + t * vx , y <- max 0 $ y + t * vy } -walkStep dir obj = { obj | vx <- dir, dir <- if | dir < 0 -> "left" - | dir > 0 -> "right" - | otherwise -> obj.dir } - -step t d j = timeStep t . gravityStep t . jumpStep j . walkStep d - -delta = lift (flip (/) 20) (fps 25) -leftRight = toFloat . .x <~ Keyboard.arrows -jump = (\{y} -> y > 0) <~ Keyboard.arrows -steps = sampleOn delta (lift3 step delta leftRight jump) - -{- LOCAL STATE -} - -initialMario = { x = 0, y = 0, vx = 0, vy = 0, dir = "right" } -stateSignal = foldp ($) initialMario steps - -encode obj id = - castJSStringToString . (toPrettyJSString "") . JSON.fromList $ - [ ("id", JsonNumber id) - , ("x", JsonNumber obj.x) - , ("y", JsonNumber obj.y) - , ("vx", JsonNumber obj.vx) - , ("dir", JsonString obj.dir) ] ---encode obj id = show id ++ " " ++ show obj.x ++ " " ++ show obj.y - -clientID = inRange 0 99999 -myStream = encode <~ stateSignal ~ clientID - -{- NETWORK LAYER -} - -worldMessageStream = open "ws://localhost:8080/ws" myStream - --- :: String -> Maybe (Float, Record) -parsePlayer msg = - case fromString msg of - Nothing -> Nothing - Just json -> - let id = findNumber "id" json - x = findNumber "x" json - y = findNumber "y" json - vx = findNumber "vx" json - dir = findString "dir" json - in Just (id, { x = x, y = y, vx = vx, vy = 0, dir = dir }) - --- :: Maybe (Float, Record) -> Dict String Record -> Dict String Record -updateWorldPositions maybeMario marioDict = case maybeMario of - Just (id, mario) -> (Dict.insert) (show id) mario marioDict - Nothing -> marioDict - --- :: Signal (Dict String Record) -worldPositions = foldp updateWorldPositions Dict.empty (parsePlayer <~ worldMessageStream) ---worldPositions = constant empty - -marios = Dict.values <~ worldPositions - -{- RENDER CODE -} - --- :: Record -> Form -mario2Form (w,h) mario = - let verb = if mario.vx /= 0 then "walk" else "stand" - src = "/imgs/mario/" ++ verb ++ "/" ++ mario.dir ++ ".gif" - in toForm (mario.x, (h-63)-mario.y) (image 35 35 src) - --- :: (Int,Int) -> [Record] -> Element -render (w,h) marios = - collage w h ( (filled cyan $ rect w h (w `div` 2, h `div` 2)) - : (filled green $ rect w 50 (w `div` 2,h-25)) - : List.map (mario2Form (w,h)) marios ) - -{- PUTTING IT TOGETHER -} - --- :: Signal Element -main = render <~ Window.dimensions ~ marios ---main = above <~ ((plainText . show) <~ (marios)) ~ (render <~ Window.dimensions ~ marios) ---main = (plainText . show) <~ (marios) - diff --git a/Examples/mario_mp/Object.elm b/Examples/mario_mp/Object.elm deleted file mode 100644 index 42bb457..0000000 --- a/Examples/mario_mp/Object.elm +++ /dev/null @@ -1,8 +0,0 @@ - -module Object where - -import JavaScript -import JSON - -main = plainText . castJSStringToString . (toPrettyJSString "") . fromList $ [ ("answer", JsonNumber 42) ] - diff --git a/Examples/mario_mp/Values.elm b/Examples/mario_mp/Values.elm deleted file mode 100644 index 54eae62..0000000 --- a/Examples/mario_mp/Values.elm +++ /dev/null @@ -1,7 +0,0 @@ - -module Values where - -import Dict - -main = constant . plainText . show . values $ empty - diff --git a/Examples/mario_mp/conn.go b/Examples/mario_mp/conn.go deleted file mode 100644 index 569b148..0000000 --- a/Examples/mario_mp/conn.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "code.google.com/p/go.net/websocket" -) - -type connection struct { - // The websocket connection. - ws *websocket.Conn - - // Buffered channel of outbound messages. - send chan string -} - -func (c *connection) reader() { - for { - var message string - err := websocket.Message.Receive(c.ws, &message) - if err != nil { - break - } - h.broadcast <- message - } - c.ws.Close() -} - -func (c *connection) writer() { - for message := range c.send { - err := websocket.Message.Send(c.ws, message) - if err != nil { - break - } - } - c.ws.Close() -} - -func wsHandler(ws *websocket.Conn) { - c := &connection{send: make(chan string, 256), ws: ws} - h.register <- c - defer func() { h.unregister <- c }() - go c.writer() - c.reader() -} diff --git a/Examples/mario_mp/elm-runtime.js b/Examples/mario_mp/elm-runtime.js deleted file mode 120000 index a9aaf0c..0000000 --- a/Examples/mario_mp/elm-runtime.js +++ /dev/null @@ -1 +0,0 @@ -../../elm/elm-runtime.js \ No newline at end of file diff --git a/Examples/mario_mp/hub.go b/Examples/mario_mp/hub.go deleted file mode 100644 index f45decb..0000000 --- a/Examples/mario_mp/hub.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -type hub struct { - // Registered connections. - connections map[*connection]bool - - // Inbound messages from the connections. - broadcast chan string - - // Register requests from the connections. - register chan *connection - - // Unregister requests from connections. - unregister chan *connection -} - -var h = hub{ - broadcast: make(chan string), - register: make(chan *connection), - unregister: make(chan *connection), - connections: make(map[*connection]bool), -} - -func (h *hub) run() { - for { - select { - case c := <-h.register: - h.connections[c] = true - case c := <-h.unregister: - delete(h.connections, c) - close(c.send) - case m := <-h.broadcast: - for c := range h.connections { - select { - case c.send <- m: - default: - delete(h.connections, c) - close(c.send) - go c.ws.Close() - } - } - } - } -} diff --git a/Examples/mario_mp/imgs/mario/stand/left.gif b/Examples/mario_mp/imgs/mario/stand/left.gif deleted file mode 100644 index 9e8ec00..0000000 Binary files a/Examples/mario_mp/imgs/mario/stand/left.gif and /dev/null differ diff --git a/Examples/mario_mp/imgs/mario/stand/right.gif b/Examples/mario_mp/imgs/mario/stand/right.gif deleted file mode 100644 index 56fbc91..0000000 Binary files a/Examples/mario_mp/imgs/mario/stand/right.gif and /dev/null differ diff --git a/Examples/mario_mp/imgs/mario/walk/left.gif b/Examples/mario_mp/imgs/mario/walk/left.gif deleted file mode 100644 index c2143a2..0000000 Binary files a/Examples/mario_mp/imgs/mario/walk/left.gif and /dev/null differ diff --git a/Examples/mario_mp/imgs/mario/walk/right.gif b/Examples/mario_mp/imgs/mario/walk/right.gif deleted file mode 100644 index 4e69804..0000000 Binary files a/Examples/mario_mp/imgs/mario/walk/right.gif and /dev/null differ diff --git a/Examples/mario_mp/main.go b/Examples/mario_mp/main.go deleted file mode 100644 index d574d1e..0000000 --- a/Examples/mario_mp/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "code.google.com/p/go.net/websocket" - "flag" - "log" - "net/http" -) - -var addr = flag.String("addr", ":8080", "http service address") - -func fileHandler(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, r.URL.Path[1:]) -} - -func main() { - flag.Parse() - go h.run() - http.HandleFunc("/", fileHandler) - http.Handle("/ws", websocket.Handler(wsHandler)) - if err := http.ListenAndServe(*addr, nil); err != nil { - log.Fatal("ListenAndServe:", err) - } -} diff --git a/Examples/mario_mp/makefile b/Examples/mario_mp/makefile deleted file mode 100644 index c7e995e..0000000 --- a/Examples/mario_mp/makefile +++ /dev/null @@ -1,19 +0,0 @@ -all: mario_mp Mario.html Clicks.html Object.html Values.html - -mario_mp: *.go - go build - -Mario.html: Mario.elm - elm -r elm-runtime.js Mario.elm - -Clicks.html: Clicks.elm - elm -r elm-runtime.js Clicks.elm - -Object.html: Object.elm - elm -r elm-runtime.js Object.elm - -Values.html: Values.elm - elm -r elm-runtime.js Values.elm - -clean: - rm -rf *.html mario_mp diff --git a/elm-server/LICENSE b/LICENSE similarity index 100% rename from elm-server/LICENSE rename to LICENSE diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..35ab781 --- /dev/null +++ b/Setup.hs @@ -0,0 +1,156 @@ +import Distribution.Simple +import Distribution.Simple.LocalBuildInfo +import Distribution.Simple.Setup +import Distribution.PackageDescription + +import System.Cmd +import System.Directory +import System.FilePath +import System.IO +import System.Process + +import Control.Monad + +-- Part 1 +-- ------ +-- Add a build callout +-- We need to build elm-doc and run it because that generates the file "docs.json" needs by Libraries.hs +-- which is part of the elm library and executable +-- Unfort. there seems to be no way to tell cabal that: +-- (a) elm-doc generates docs.json, and +-- (b) elm (library) depends on docs.json +-- Therefore, we either use make instead (or a script), or hack around in cabal + +-- Part 2 +-- ------ +-- Add a post-build callout. +-- We need to build the runtime.js after we've built elm (because we use elm to generate some of the JavaScript), +-- but before cabal does the install file copy step + +-- Assumptions +-- Elm.cabal expects the generated files to end up in dist/data +rtsDir lbi = (buildDir lbi) </> ".." </> "data" -- git won't look in dist + cabal will clean it +jsDir lbi = (buildDir lbi) </> ".." </> "js" + +-- The runtime is called: +rts lbi = (rtsDir lbi) </> "elm-runtime.js" + +-- The json file is called: + +-- The elm-docs executable is called: +elmDoc = "elm-doc" +elm_doc lbi = (buildDir lbi) </> elmDoc </> elmDoc + +types lbi = (rtsDir lbi) </> "docs.json" + +-- buildDir with LocalBuildInfo points to "dist/build" (usually) +elm lbi = (buildDir lbi) </> "elm" </> "elm" + +-- Care! This appears to be based on an unstable API +-- See: http://www.haskell.org/cabal/release/cabal-latest/doc/API/Cabal/Distribution-Simple.html#2 + + +main :: IO () +main = defaultMainWithHooks simpleUserHooks { {-- buildHook = myBuild, --} postBuild = myPostBuildWithTypes } + + +-- Build + +-- Not currently used. buildTypes is in 'myPostBuildWithTypes' +-- If using this again, change postBuild to 'myPostBuild' +-- Purpose is to make sure docs.json was built before elm exec was (as elm exec depended on it) +-- This is no longer true and the code below seems to affect cabal's build dependencies +myBuild :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO () +myBuild pd lbi uh bf = do + putStrLn $ "Custom build step started: compile " ++ elmDoc + withExe pd (\x -> putStrLn (exeName x)) + buildHook simpleUserHooks (filterExe elmDoc pd) (filterLBI elmDoc lbi) uh bf + putStrLn "Custom build step started: build docs.json" + buildTypes lbi -- see note(1) below + putStrLn "Custom build step started: compile everything" + buildHook simpleUserHooks pd lbi uh bf + +-- note(1): We use to include docs.json directly into LoadLibraries at compile time +-- If docs.json is used in other (template) haskell files, they should be copied +-- and compiled in a separate directory (eg, dist/copiedSrc). +-- This is to make sure they are re-compiled on docs.json changes. +-- Copying is a better solution than 'touch'ing the source files +-- (touch is non-portable and confusing wrt RCS). + +-- In the PackageDescription, the list of stuff to build is held in library (in a Maybe) +-- and the executables list. We want a PackageDescription that only mentions the executable 'name' +filterExe name pd = pd { + library = Nothing, + executables = filter (\x -> (exeName x == name)) (executables pd) + } + +-- It's not enough to fix the PackageDescription, we also have to fix the LocalBuildInfo. +-- This includes the component build order (data ComponentName) which is horribly internal. +filterLBI name lbi = lbi { + libraryConfig = Nothing, + compBuildOrder = [CExeName name], + executableConfigs = filter (\a -> (fst a == name)) (executableConfigs lbi) + } + +buildTypes lbi = do + createDirectoryIfMissing False (rtsDir lbi) -- dist should already exist + files <- getFiles ".elm" "libraries" + system (elm_doc lbi ++ " " ++ unwords files ++ " > " ++ (types lbi)) + putStrLn $ "Custom build step completed: " ++ elmDoc + + +-- Post Build + +myPostBuildWithTypes :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO () +myPostBuildWithTypes as bfs pd lbi = do + putStrLn "Custom build step started: build docs.json" + buildTypes lbi -- see note(1) below + myPostBuild as bfs pd lbi + +myPostBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO () +myPostBuild as bfs pd lbi = do + putStrLn "Custom post build step started: build elm-runtime.js" + buildRuntime lbi + postBuild simpleUserHooks as bfs pd lbi + +getFiles ext dir = do + contents <- map (dir </>) `fmap` getDirectoryContents dir + let files = filter (\f -> takeExtension f == ext) contents + dirs = filter (not . hasExtension) contents + filess <- mapM (getFiles ext) dirs + return (files ++ concat filess) + +appendJS lbi file = do + putStrLn (dropExtension file) + str <- readFile file + length str `seq` return () + appendFile (rts lbi) str + +appendElm lbi file = do + jsFile <- runElm lbi file + appendJS lbi jsFile + +-- replace 'system' call with 'runProcess' which handles args better and allows env variable +-- "Elm_datadir" which is used by LoadLibraries to find docs.json +runElm :: LocalBuildInfo -> String -> IO FilePath +runElm lbi file = do + rts_c <- canonicalizePath (rts lbi) -- dist/data/elm-runtime.js + let js = jsDir lbi -- dist/js + let j = dropFileName (js </> file) -- dist/js/libraries/ + createDirectoryIfMissing True j -- must do before any canonicalization + out_c <- canonicalizePath js -- dist/js (root folder) + elm_c <- canonicalizePath (elm lbi) -- dist/build/elm/elm + rtd_c <- canonicalizePath (rtsDir lbi) -- dist/data (for docs.json) + handle <- runProcess elm_c ["--only-js", "--no-prelude", "--output-directory="++out_c, file] + Nothing (Just [("Elm_datadir", rtd_c)]) Nothing Nothing Nothing + exitCode <- waitForProcess handle + return $ j </> replaceExtension (takeFileName file) ".js" + + +buildRuntime lbi = do + createDirectoryIfMissing False (rtsDir lbi) -- dist should already exist + writeFile (rts lbi) "Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\ + \Elm.Graphics = {}; ElmRuntime = {}; ElmRuntime.Render = {}\n" + mapM_ (appendJS lbi) =<< getFiles ".js" "libraries" + mapM_ (appendElm lbi) =<< getFiles ".elm" "libraries" + mapM_ (appendJS lbi) =<< getFiles ".js" "runtime" diff --git a/elm/changelog.txt b/changelog.txt similarity index 100% rename from elm/changelog.txt rename to changelog.txt diff --git a/elm/src/Compiler.hs b/compiler/Compiler.hs similarity index 56% rename from elm/src/Compiler.hs rename to compiler/Compiler.hs index 3932c90..7250fe3 100644 --- a/elm/src/Compiler.hs +++ b/compiler/Compiler.hs @@ -2,10 +2,11 @@ module Main where import Data.Either (lefts, rights) -import Data.List (intersect, intercalate) +import Data.List (intersect, intercalate,lookup) import Data.Maybe (fromMaybe) import Data.Version (showVersion) import System.Console.CmdArgs +import System.Exit import System.FilePath import Text.Blaze.Html.Renderer.String (renderHtml) @@ -16,6 +17,7 @@ import Ast import Initialize import CompileToJS import GenerateHtml +import qualified Libraries as Libraries import Paths_Elm data ELM = @@ -25,7 +27,8 @@ data ELM = , separate_js :: Bool , only_js :: Bool , import_js :: [FilePath] - , generate_noscript :: Bool + , no_prelude :: Bool + , noscript :: Bool , minify :: Bool , output_directory :: Maybe FilePath } @@ -38,7 +41,8 @@ elm = ELM { make = False &= help "automatically compile dependencies." , separate_js = False &= help "Compile to separate HTML and JS files." , only_js = False &= help "Compile only to JavaScript." , import_js = [] &= typFile &= help "Include a JavaScript file before the body of the Elm program. Can be used many times. Files will be included in the given order." - , generate_noscript = True &= help "Add generated <noscript> tag to HTML output." + , no_prelude = False &= help "Do not import Prelude by default, used only when compiling standard libraries." + , noscript = True &= help "Add generated <noscript> tag to HTML output." , minify = False &= help "Minify generated JavaScript" , output_directory = Nothing &= typFile &= help "Output files to directory specified. Defaults to the location of original file." } &= @@ -47,37 +51,41 @@ elm = ELM { make = False &= help "automatically compile dependencies." main = do args <- cmdArgs elm - mini <- getDataFileName ("elm-runtime-" ++ showVersion version ++ ".js") + mini <- getDataFileName "elm-runtime.js" compileArgs mini args -compileArgs mini (ELM _ [] _ _ _ _ _ _ _) = - putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help" -compileArgs mini (ELM make files rtLoc split only js nscrpt isMini outputDir) = - mapM_ (fileTo isMini make what js nscrpt outputDir loc) files - where loc = fromMaybe mini rtLoc - what | only = JS - | split = Split - | otherwise = HTML +compileArgs mini flags = + case files flags of + [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help" + fs -> mapM_ (fileTo flags what loc) fs + where loc = fromMaybe mini (runtime flags) + what | only_js flags = JS + | separate_js flags = Split + | otherwise = HTML data What = JS | HTML | Split -fileTo isMini make what jsFiles noscript outputDir rtLoc file = do - let jsStyle = if isMini then Minified else Readable - formatJS = if isMini then BS.unpack . JS.minify . BS.pack else id - ems <- build make file - jss <- concat `fmap` mapM readFile jsFiles +fileTo flags what rtLoc file = do + let jsStyle = if minify flags then Minified else Readable + formatJS = if minify flags then BS.unpack . JS.minify . BS.pack else id + prelude = not (no_prelude flags) + ems <- if make flags then build prelude file + else do src <- readFile file + return (fmap (:[]) (buildFromSource prelude src)) + jss <- concat `fmap` mapM readFile (import_js flags) case ems of - Left err -> putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err - Right ms -> - let path = fromMaybe "" outputDir </> file + Left err -> do putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err + exitFailure + Right ms' -> + let path = fromMaybe "" (output_directory flags) </> file js = replaceExtension path ".js" html = replaceExtension path ".html" - pairs = map ((,) (fst ms)) (snd ms) - txt = jss ++ concatMap jsModule pairs + ms = if no_prelude flags then ms' else map Libraries.addPrelude ms' + txt = jss ++ concatMap jsModule ms in case what of JS -> writeFile js (formatJS txt) HTML -> writeFile html . renderHtml $ - modulesToHtml jsStyle "" rtLoc jss noscript pairs + modulesToHtml jsStyle "" rtLoc jss (noscript flags) ms Split -> - do writeFile html . renderHtml $ linkedHtml rtLoc js pairs + do writeFile html . renderHtml $ linkedHtml rtLoc js ms writeFile js (formatJS txt) diff --git a/compiler/Docs.hs b/compiler/Docs.hs new file mode 100644 index 0000000..0fc2ae2 --- /dev/null +++ b/compiler/Docs.hs @@ -0,0 +1,65 @@ + +module Main where + +import Ast +import Control.Applicative ((<$>), (<*>)) +import Data.List (intercalate) +import Data.Maybe (catMaybes) +import Parse.Library +import Parse.Modules (moduleDef) +import Text.Parsec hiding (newline,spaces) +import System.Environment +import System.Exit + + +main = do + srcs <- mapM readFile =<< getArgs + case mapM docParse srcs of + Left err -> putStrLn err >> exitFailure + Right ms -> putStrLn (toModules ms) + +toModules ms = wrap (intercalate ",\n " (map toModule ms)) + where wrap s = "{ \"modules\" : [\n " ++ s ++ "\n ]\n}" + +toModule (name, values) = + "{ \"name\" : " ++ show name ++ ",\n " ++ + "\"values\" : [\n " ++ vs ++ "\n ]\n }" + where vs = intercalate ",\n " (map toValue values) + +toValue (name, tipe, desc) = + "{ \"name\" : " ++ show name ++ + ",\n \"type\" : " ++ show tipe ++ + ",\n \"desc\" : " ++ show desc ++ "\n }" + +docParse :: String -> Either String (String, [(String, String, String)]) +docParse = setupParser $ do + optional freshLine + (names, exports) <- option (["Main"],[]) moduleDef + info <- many (annotation exports <|> try skip <|> end) + return (intercalate "." names, catMaybes info) + where + skip = manyTill anyChar simpleNewline >> return Nothing + end = many1 anyChar >> return Nothing + +annotation :: [String] -> IParser (Maybe (String, String, String)) +annotation exports = + try ((\c n t -> export (n,t,c)) <$> comment <*> (try adt <|> name) <*> tipe) + where + comment = concatMap clip <$> many lineComment + clip str = case str of { ' ':rest -> rest ; _ -> str } ++ "\n" + + name = do v <- lowVar <|> parens symOp + whitespace ; hasType ; whitespace ; return v + + tipe = manyTill anyChar (try (simpleNewline >> notFollowedBy (string " "))) + + export info@(name,_,_) = + if null exports || name `elem` exports then Just info else Nothing + + adt = lookAhead ((string "data" <|> string "type") >> whitespace >> capVar) + + +setupParser p source = + case iParse p "" source of + Right result -> Right result + Left err -> Left $ "Parse error at " ++ show err diff --git a/elm/src/Gen/Cases.hs b/compiler/Gen/Cases.hs similarity index 88% rename from elm/src/Gen/Cases.hs rename to compiler/Gen/Cases.hs index 0114f64..4bfb8ae 100644 --- a/elm/src/Gen/Cases.hs +++ b/compiler/Gen/Cases.hs @@ -57,8 +57,15 @@ match vs cs def matchVar :: [String] -> [([Pattern],CExpr)] -> Match -> GuidCounter Match matchVar (v:vs) cs def = match vs (map subVar cs) def - where subVar (PVar x : ps, C t s e) = (ps, C t s $ subst x (Var v) e) - subVar (PAnything : ps, ce) = (ps, ce) + where + subVar (p:ps, ce@(C t s e)) = + let ctx = C t s in + (ps, case p of + PVar x -> C t s $ subst x (Var v) e + PAnything -> ce + PRecord fs -> + ctx $ foldr (\x -> subst x (Access (ctx (Var v)) x)) e fs + ) matchCon :: [String] -> [([Pattern],CExpr)] -> Match -> GuidCounter Match matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css diff --git a/compiler/Gen/CompileToJS.hs b/compiler/Gen/CompileToJS.hs new file mode 100644 index 0000000..3c09620 --- /dev/null +++ b/compiler/Gen/CompileToJS.hs @@ -0,0 +1,338 @@ +module CompileToJS (showErr, jsModule) where + +import Control.Arrow (first,second) +import Control.Monad (liftM,(<=<),join,ap) +import Data.Char (isAlpha,isDigit) +import Data.List (intercalate,sortBy,inits,foldl') +import qualified Data.Map as Map +import Data.Either (partitionEithers) +import qualified Text.Pandoc as Pan + +import Ast +import Context +import Rename (derename) +import Cases +import Guid +import Rename (deprime) +import Types.Types ( Type(RecordT) ) + +showErr :: String -> String +showErr err = globalAssign "Elm.Main" (jsFunc "elm" body) + where msg = show . concatMap (++"<br>") . lines $ err + body = "var T = Elm.Text(elm);\n\ + \return { main : T.text(T.monospace(" ++ msg ++ ")) };" + +indent = concatMap f + where f '\n' = "\n " + f c = [c] + +internalImports = + [ ("N" , "Elm.Native"), + ("_N", "N.Utils(elm)"), + ("_L", "N.List(elm)"), + ("_E", "N.Error(elm)"), + ("_str", "N.JavaScript(elm).toString") + ] + +parens s = "(" ++ s ++ ")" +brackets s = "{" ++ s ++ "}" +jsObj = brackets . intercalate ", " +jsList ss = "["++ intercalate "," ss ++"]" +jsFunc args body = "function(" ++ args ++ "){" ++ indent body ++ "}" +assign x e = "\nvar " ++ x ++ " = " ++ e ++ ";" +ret e = "\nreturn "++ e ++";" +iff a b c = a ++ "?" ++ b ++ ":" ++ c +quoted s = "'" ++ concatMap f s ++ "'" + where f '\n' = "\\n" + f '\'' = "\\'" + f '\t' = "\\t" + f '\"' = "\\\"" + f '\\' = "\\\\" + f c = [c] + +globalAssign n e = "\n" ++ assign' n e ++ ";" +assign' n e = n ++ " = " ++ e + +jsModule (Module names exports imports stmts) = + setup ("Elm":modNames) ++ globalAssign ("Elm." ++ modName) (jsFunc "elm" program) + where + modNames = if null names then ["Main"] else names + modName = intercalate "." modNames + includes = concatMap jsImport imports + body = stmtsToJS stmts + defs = assign "$op" "{}" + program = "\nvar " ++ usefulFuncs ++ ";" ++ defs ++ includes ++ body ++ + setup ("elm":"Native":modNames) ++ + assign "_" ("elm.Native." ++ modName ++ "||{}") ++ + getExports exports stmts ++ setup ("elm":modNames) ++ + ret (assign' ("elm." ++ modName) "_") ++ "\n" + setup modNames = concatMap (\n -> globalAssign n $ n ++ "||{}") . + map (intercalate ".") . drop 2 . inits $ init modNames + usefulFuncs = intercalate ", " (map (uncurry assign') internalImports) + +getExports names stmts = "\n"++ intercalate ";\n" (op : map fnPair fns) + where exNames n = either derename id n `elem` names + exports | null names = concatMap get stmts + | otherwise = filter exNames (concatMap get stmts) + + (fns,ops) = partitionEithers exports + + opPair op = "'" ++ op ++ "' : $op['" ++ op ++ "']" + fnPair fn = let fn' = derename fn in "_." ++ fn' ++ " = " ++ fn + + op = ("_.$op = "++) . jsObj $ map opPair ops + + get' (FnDef x _ _) = Left x + get' (OpDef op _ _ _) = Right op + get s = case s of Definition d -> [ get' d ] + Datatype _ _ tcs -> map (Left . fst) tcs + ImportEvent _ _ x _ -> [ Left x ] + ExportEvent _ _ _ -> [] + TypeAlias _ _ _ -> [] + TypeAnnotation _ _ -> [] + + +jsImport (modul, how) = + case how of + As name -> assign name ("Elm." ++ modul ++ parens "elm") + Hiding vs -> include ++ " var hiding=" ++ (jsObj $ map (++":1") vs) ++ + "; for(var k in _){if(k in hiding)continue;" ++ + "eval('var '+k+'=_[\"'+k+'\"]')}" + Importing vs -> include ++ named + where + imprt v = assign' v ("_." ++ v) + def (o:p) = imprt (if isOp o then "$op['" ++ o:p ++ "']" else deprime (o:p)) + named = if null vs then "" else "\nvar " ++ intercalate ", " (map def vs) ++ ";" + where + include = "\nvar _ = Elm." ++ modul ++ parens "elm" ++ ";" ++ setup modul + setup moduleName = " var " ++ concatMap (++";") (defs ++ [assign' moduleName "_"]) + where + defs = map (\n -> assign' n (n ++ "||{}")) (subnames moduleName) + subnames = map (intercalate ".") . tail . inits . init . split + split names = case go [] names of + (name, []) -> [name] + (name, ns) -> name : split ns + go name str = case str of + '.':rest -> (reverse name, rest) + c:rest -> go (c:name) rest + [] -> (reverse name, []) + + + +stmtsToJS :: [Statement] -> String +stmtsToJS stmts = run $ do program <- mapM toJS (sortBy cmpStmt stmts) + return (concat program) + where + cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2) + valueOf s = case s of + Datatype _ _ _ -> 1 + ImportEvent _ _ _ _ -> 2 + Definition (FnDef f [] _) -> + if derename f == "main" then 5 else 4 + Definition _ -> 3 + ExportEvent _ _ _ -> 6 + TypeAlias _ _ _ -> 0 + TypeAnnotation _ _ -> 0 + +class ToJS a where + toJS :: a -> GuidCounter String + +instance ToJS Def where + toJS (FnDef x [] e) = assign x `liftM` toJS' e + toJS (FnDef f as e) = (assign f . wrapper . func) `liftM` toJS' e + where + func body = jsFunc (intercalate ", " as) (ret body) + wrapper e | length as == 1 = e + | otherwise = 'F' : show (length as) ++ parens e + toJS (OpDef op a1 a2 e) = + do body <- toJS' e + let func = "F2" ++ parens (jsFunc (a1 ++ ", " ++ a2) (ret body)) + return (globalAssign ("$op['" ++ op ++ "']") func) + +instance ToJS Statement where + toJS stmt = + case stmt of + Definition d -> toJS d + Datatype _ _ tcs -> concat `liftM` mapM (toJS . toDef) tcs + where toDef (name,args) = + let vars = map (('a':) . show) [1..length args] in + Definition . FnDef name vars . noContext $ + Data (derename name) (map (noContext . Var) vars) + ImportEvent js base elm _ -> + do v <- toJS' base + return $ concat [ "\nvar " ++ elm ++ "=Elm.Signal(elm).constant(" ++ v ++ ");" + , "\ndocument.addEventListener('", js + , "_' + elm.id, function(e) { elm.notify(", elm + , ".id, e.value); });" ] + ExportEvent js elm _ -> + return $ concat [ "\nlift(function(v) { " + , "var e = document.createEvent('Event');" + , "e.initEvent('", js, "_' + elm.id, true, true);" + , "e.value = v;" + , "document.dispatchEvent(e); return v; })(", elm, ");" ] + TypeAnnotation _ _ -> return "" + TypeAlias n _ t -> return "" + +toJS' :: CExpr -> GuidCounter String +toJS' (C txt span expr) = + case expr of + MultiIf ps -> multiIfToJS span ps + Case e cases -> caseToJS span e cases + _ -> toJS expr + +remove x e = "_N.remove('" ++ x ++ "', " ++ e ++ ")" +addField x v e = "_N.insert('" ++ x ++ "', " ++ v ++ ", " ++ e ++ ")" +setField fs e = "_N.replace(" ++ jsList (map f fs) ++ ", " ++ e ++ ")" + where f (x,v) = "['" ++ x ++ "'," ++ v ++ "]" +access x e = e ++ "." ++ x +makeRecord kvs = record `liftM` collect kvs + where + combine r (k,v) = Map.insertWith (++) k v r + collect = liftM (foldl' combine Map.empty) . mapM prep + prep (k, as, e@(C t s _)) = + do v <- toJS' (foldr (\x e -> C t s $ Lambda x e) e as) + return (k,[v]) + fields fs = + brackets ("\n "++intercalate ",\n " (map (\(k,v) -> k++":"++v) fs)) + hidden = fields . map (second jsList) . + filter (not . null . snd) . Map.toList . Map.map tail + record kvs = fields . (("_", hidden kvs) :) . Map.toList . Map.map head $ kvs + + +instance ToJS Expr where + toJS expr = + case expr of + Var x -> return $ x + Chr c -> return $ quoted [c] + Str s -> return $ "_str" ++ parens (quoted s) + IntNum n -> return $ show n + FloatNum n -> return $ show n + Boolean b -> return $ if b then "true" else "false" + Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi + Access e x -> access x `liftM` toJS' e + Remove e x -> remove x `liftM` toJS' e + Insert e x v -> addField x `liftM` toJS' v `ap` toJS' e + Modify e fs -> do fs' <- (mapM (\(x,v) -> (,) x `liftM` toJS' v) fs) + setField fs' `liftM` toJS' e + Record fs -> makeRecord fs + Binop op e1 e2 -> binop op `liftM` toJS' e1 `ap` toJS' e2 + + If eb et ef -> + parens `liftM` (iff `liftM` toJS' eb `ap` toJS' et `ap` toJS' ef) + + Lambda v e -> liftM (jsFunc v . ret) (toJS' e) + + App e1 e2 -> jsApp e1 e2 + Let defs e -> jsLet defs e + Data name es -> + do fs <- mapM toJS' es + return $ case name of + "Nil" -> jsNil + "Cons" -> jsCons (head fs) ((head . tail) fs) + _ -> jsObj $ ("ctor:" ++ show name) : fields + where fields = zipWith (\n e -> "_" ++ show n ++ ":" ++ e) [0..] fs + + Markdown doc -> return $ "text('" ++ pad ++ md ++ pad ++ "')" + where pad = "<div style=\"height:0;width:0;\"> </div>" + md = formatMarkdown $ Pan.writeHtmlString Pan.def doc + +jsApp e1 e2 = + do f <- toJS' func + as <- mapM toJS' args + return $ case as of + [a] -> f ++ parens a + _ -> "A" ++ show (length as) ++ parens (intercalate ", " (f:as)) + where + (func, args) = go [e2] e1 + go args e = + case e of + (C _ _ (App e1 e2)) -> go (e2 : args) e1 + _ -> (e, args) + +formatMarkdown = concatMap f + where f '\'' = "\\'" + f '\n' = "\\n" + f '"' = "\"" + f c = [c] + +multiIfToJS span ps = + case last ps of + (C _ _ (Var "otherwise"), e) -> toJS' e >>= \b -> format b (init ps) + _ -> format ("_E.If" ++ parens (quoted (show span))) ps + where + format base ps = + foldr (\c e -> parens $ c ++ " : " ++ e) base `liftM` mapM f ps + f (b,e) = do b' <- toJS' b + e' <- toJS' e + return (b' ++ " ? " ++ e') + +jsLet defs e' = do ds <- jsDefs defs + e <- toJS' e' + return $ jsFunc "" (concat ds ++ ret e) ++ "()" + where + jsDefs defs = mapM toJS (sortBy f defs) + f a b = compare (valueOf a) (valueOf b) + valueOf (FnDef _ args _) = min 1 (length args) + valueOf (OpDef _ _ _ _) = 1 + +caseToJS span e ps = do + match <- caseToMatch ps + e' <- toJS' e + let (match',stmt) = case (match,e) of + (Match name _ _, C _ _ (Var x)) -> (matchSubst [(name,x)] match, "") + (Match name _ _, _) -> (match, assign name e') + _ -> (match, "") + matches <- matchToJS span match' + return $ "function(){ " ++ stmt ++ matches ++ " }()" + +matchToJS span match = + case match of + Match name clauses def -> + do cases <- concat `liftM` mapM (clauseToJS span name) clauses + finally <- matchToJS span def + return $ concat [ "\nswitch (", name, ".ctor) {", + indent cases, "\n}", finally ] + Fail -> return ("_E.Case" ++ parens (quoted (show span))) + Break -> return "break;" + Other e -> ret `liftM` toJS' e + Seq ms -> concat `liftM` mapM (matchToJS span) (dropEnd [] ms) + where + dropEnd acc [] = acc + dropEnd acc (m:ms) = + case m of + Other _ -> acc ++ [m] + _ -> dropEnd (acc ++ [m]) ms + +clauseToJS span var (Clause name vars e) = do + let vars' = map (\n -> var ++ "._" ++ show n) [0..] + s <- matchToJS span $ matchSubst (zip vars vars') e + return $ concat [ "\ncase ", quoted name, ":", indent s ] + +jsNil = "_L.Nil" +jsCons e1 e2 = "_L.Cons(" ++ e1 ++ "," ++ e2 ++ ")" +jsRange e1 e2 = "_L.range" ++ parens (e1 ++ "," ++ e2) +jsCompare e1 e2 op = parens ("_N.cmp(" ++ e1 ++ "," ++ e2 ++ ").ctor" ++ op) + +binop (o:p) e1 e2 + | isAlpha o || '_' == o = (o:p) ++ parens e1 ++ parens e2 + | otherwise = + let ops = ["+","-","*","/","&&","||"] in + case o:p of + "::" -> jsCons e1 e2 + "++" -> "_L.append" ++ parens (e1 ++ "," ++ e2) + "$" -> e1 ++ parens e2 + "<|" -> e1 ++ parens e2 + "|>" -> e2 ++ parens e1 + "." -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x") + "^" -> "Math.pow(" ++ e1 ++ "," ++ e2 ++ ")" + "==" -> "_N.eq(" ++ e1 ++ "," ++ e2 ++ ")" + "/=" -> "!_N.eq(" ++ e1 ++ "," ++ e2 ++ ")" + "<" -> jsCompare e1 e2 "==='LT'" + ">" -> jsCompare e1 e2 "==='GT'" + "<=" -> jsCompare e1 e2 "!=='GT'" + ">=" -> jsCompare e1 e2 "!=='LT'" + "<~" -> "A2(lift," ++ e1 ++ "," ++ e2 ++ ")" + "~" -> "A3(lift2,F2(function(f,x){return f(x)}),"++e1++","++e2++")" + _ | elem (o:p) ops -> parens (e1 ++ (o:p) ++ e2) + | otherwise -> concat [ "$op['", o:p, "']" + , parens e1, parens e2 ] \ No newline at end of file diff --git a/elm/src/Gen/ExtractNoscript.hs b/compiler/Gen/ExtractNoscript.hs similarity index 95% rename from elm/src/Gen/ExtractNoscript.hs rename to compiler/Gen/ExtractNoscript.hs index c5588d3..6e3ccef 100644 --- a/elm/src/Gen/ExtractNoscript.hs +++ b/compiler/Gen/ExtractNoscript.hs @@ -36,7 +36,6 @@ instance Extract Expr where (_ , ss1 , ss2 ) -> ss1 ++ ss2 Lambda v e -> f e App (C _ _ (App (C _ _ (Var "link")) src)) txt -> linkExtract src txt - App (C _ _ (App (C _ _ (Var "Graphics.link")) src)) txt -> linkExtract src txt App (C _ _ (App (C _ _ (Var "Text.link")) src)) txt -> linkExtract src txt App (C _ _ (Var "header")) e -> tag "h1" e App (C _ _ (Var "bold")) e -> tag "b" e diff --git a/compiler/Gen/GenerateHtml.hs b/compiler/Gen/GenerateHtml.hs new file mode 100644 index 0000000..1265727 --- /dev/null +++ b/compiler/Gen/GenerateHtml.hs @@ -0,0 +1,75 @@ +{-# LANGUAGE OverloadedStrings #-} +module GenerateHtml (generateHtml, + modulesToHtml, linkedHtml, + JSStyle (..) + ) where + +import Data.List (intercalate) +import Text.Blaze (preEscapedToMarkup) +import Text.Blaze.Html (Html) +import qualified Text.Blaze.Html5 as H +import Text.Blaze.Html5 ((!)) +import qualified Text.Blaze.Html5.Attributes as A + +import Text.Jasmine (minify) +import qualified Data.ByteString.Lazy.Char8 as BS + +import Ast +import Initialize (buildFromSource) +import CompileToJS +import ExtractNoscript +import Libraries as Libraries + +data JSStyle = Minified | Readable + +makeScript :: JSStyle -> Either String String -> H.Html +makeScript _ (Left s) = + H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ "" +makeScript jsStyle (Right s) = + H.script ! A.type_ "text/javascript" $ preEscapedToMarkup content + where content = case jsStyle of + Minified -> BS.unpack . minify . BS.pack $ s + Readable -> s + +-- |This function compiles Elm code into simple HTML. +-- +-- Usage example: +-- +-- > generateHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|] +generateHtml :: String -- ^ Location of elm-runtime.js as expected by the browser + -> String -- ^ The page title + -> String -- ^ The elm source code. + -> Html +generateHtml libLoc title source = + case buildFromSource True source of + Right modul -> modulesToHtml Readable title libLoc [] True [modul] + Left err -> createHtml Readable libLoc title (Right $ showErr err) + (H.noscript "") "Main" + + +modulesToHtml jsStyle title libLoc jss nscrpt modules = + createHtml jsStyle libLoc title' js noscript altTitle + where + js = Right $ jss ++ concatMap jsModule modules + noscript = if nscrpt then extractNoscript $ last modules else "" + title' = if null title then altTitle else title + altTitle = intercalate "." names + where Module names _ _ _ = last modules + + +linkedHtml rtLoc jsLoc modules = + createHtml Readable rtLoc title (Left jsLoc) (H.noscript "") title + where + title = (\(Module names _ _ _) -> intercalate "." names) (last modules) + + +createHtml jsStyle libLoc title js noscript moduleToLoad = + H.docTypeHtml $ do + H.head $ do + H.meta ! A.charset "UTF-8" + H.title . H.toHtml $ title + makeScript Readable (Left libLoc) + makeScript jsStyle js + H.body $ do + H.script ! A.type_ "text/javascript" $ preEscapedToMarkup ("Elm.fullscreen(Elm." ++ moduleToLoad ++ ")" :: String) + H.noscript $ preEscapedToMarkup noscript diff --git a/compiler/Initialize.hs b/compiler/Initialize.hs new file mode 100644 index 0000000..0d80655 --- /dev/null +++ b/compiler/Initialize.hs @@ -0,0 +1,97 @@ +module Initialize (build, buildFromSource) where + +import Control.Applicative ((<$>)) +import Control.Monad.Error +import Data.List (lookup,nub) +import qualified Data.Map as Map + +import Ast +import Data.Either (lefts,rights) +import Data.List (intercalate,partition) +import Parse.Parser (parseProgram, preParse) +import Rename +import qualified Libraries as Libs +import Types.Types ((-:)) +import Types.Hints (hints) +import Types.Unify +import Types.Alias (dealias, mistakes) +import Optimize +import CompileToJS (jsModule) + +checkMistakes :: Module -> Either String Module +checkMistakes modul@(Module name ex im stmts) = + case mistakes stmts of + m:ms -> Left (unlines (m:ms)) + [] -> return modul + +checkTypes :: Module -> Either String Module +checkTypes modul = + do subs <- unify hints modul + subs `seq` return (optimize (renameModule modul)) + +check :: Module -> Either String Module +check = checkMistakes >=> checkTypes + +buildFromSource :: Bool -> String -> Either String Module +buildFromSource withPrelude src = (check . add) =<< (parseProgram src) + where add = if withPrelude then Libs.addPrelude else id + +build :: Bool -> FilePath -> IO (Either String [Module]) +build withPrelude root = do + names <- getSortedModuleNames root + case names of + Left err -> return (Left err) + Right ns -> do srcs <- zipWithM buildFile' [1..] ns + return (sequence srcs) + where + buildFile' n name = putStrLn (msg n name) >> buildFile withPrelude name + msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name + +buildFile :: Bool -> String -> IO (Either String Module) +buildFile withPrelude moduleName = + let filePath = toFilePath moduleName in + case isNative moduleName of + True -> return (Right $ Module [moduleName] [] [] []) + --return (Left "Can't do that yet") + --Right `liftM` readFile filePath + False -> do txt <- readFile filePath + return $ buildFromSource withPrelude txt + + +getSortedModuleNames :: FilePath -> IO (Either String [String]) +getSortedModuleNames root = do + deps <- readDeps [] root + return (sortDeps =<< deps) + +type Deps = (String, [String]) + +sortDeps :: [Deps] -> Either String [String] +sortDeps deps = go [] (nub deps) + where + msg = "A cyclical or missing module dependency or was detected in: " + + go :: [String] -> [Deps] -> Either String [String] + go sorted [] = Right sorted + go sorted unsorted = + case partition (all (`elem` sorted) . snd) unsorted of + ([],m:ms) -> Left (msg ++ intercalate ", " (map fst (m:ms)) ++ show sorted ++ show unsorted) + (srtd,unsrtd) -> go (sorted ++ map fst srtd) unsrtd + +readDeps :: [FilePath] -> FilePath -> IO (Either String [Deps]) +readDeps seen root = do + txt <- readFile root + case preParse txt of + Left err -> return (Left err) + Right (name,deps) -> do rest <- mapM (readDeps seen' . toFilePath) newDeps + return $ do rs <- sequence rest + return ((name, realDeps) : concat rs) + where realDeps = filter (`notElem` builtIns) deps + newDeps = filter (`notElem` seen) realDeps + seen' = root : seen ++ newDeps + builtIns = Map.keys Libs.libraries + +isNative name = takeWhile (/='.') name == "Native" +toFilePath name = map swapDots name ++ ext + where swapDots '.' = '/' + swapDots c = c + ext = if isNative name then ".js" else ".elm" diff --git a/compiler/Language/Elm.hs b/compiler/Language/Elm.hs new file mode 100644 index 0000000..9971ffd --- /dev/null +++ b/compiler/Language/Elm.hs @@ -0,0 +1,58 @@ +{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} +{- | This module exports the functions necessary for compiling Elm code into the + respective HTML, JS and CSS code. + + The type class @'ElmSource'@ requires an instance for all types that the Elm + compiler understands. The provided instances for String, Text and QuasiQuoted + Elm source code should be sufficient. + + The documentation for the Elm language is available at + <http://elm-lang.org/Documentation.elm>, and many interactive examples are + available at <http://elm-lang.org/Examples.elm> + + Example implementations using Yesod and Happstack are available + at <https://github.com/tazjin/Elm/tree/master/Examples> +-} +module Language.Elm ( + compile, toHtml, + moduleName, + runtime, docs + ) where + +import qualified Ast as Ast +import qualified Libraries as Libraries +import Data.List (intercalate) +import Data.Version (showVersion) +import CompileToJS (showErr, jsModule) +import ExtractNoscript +import GenerateHtml +import Initialize +import Text.Blaze.Html (Html) +import Paths_Elm + +-- |This function compiles Elm code to JavaScript. +compile :: String -> String +compile source = either showErr jsModule modul + where modul = buildFromSource True source + +-- |This function extracts the module name of a given source program. +moduleName :: String -> String +moduleName source = either (const "Main") getName modul + where modul = buildFromSource False source + getName (Ast.Module names _ _ _) = intercalate "." names + +-- |This function compiles Elm code into a full HTML page. +toHtml :: String -- ^ Location of elm-min.js as expected by the browser + -> String -- ^ The page title + -> String -- ^ The elm source code + -> Html +toHtml = generateHtml + +-- |The absolute path to Elm's runtime system. +runtime :: IO FilePath +runtime = getDataFileName "elm-runtime.js" + +-- |The absolute path to Elm's core library documentation. +docs :: IO FilePath +docs = getDataFileName "docs.json" + diff --git a/elm/src/Language/Elm/Quasi.hs b/compiler/Language/Elm/Quasi.hs similarity index 100% rename from elm/src/Language/Elm/Quasi.hs rename to compiler/Language/Elm/Quasi.hs diff --git a/elm/src/Ast.hs b/compiler/Model/Ast.hs similarity index 81% rename from elm/src/Ast.hs rename to compiler/Model/Ast.hs index c6cae24..eb87fb3 100644 --- a/elm/src/Ast.hs +++ b/compiler/Model/Ast.hs @@ -2,7 +2,7 @@ module Ast where import Context -import Data.Char (isDigit) +import Data.Char (isDigit, isSymbol) import Data.List (intercalate) import Types.Types import qualified Text.Pandoc as Pandoc @@ -12,8 +12,8 @@ data Module = Module [String] Exports Imports [Statement] type Exports = [String] type Imports = [(String, ImportMethod)] -data ImportMethod = As String | Hiding [String] | Importing [String] - deriving (Eq,Ord) +data ImportMethod = As String | Importing [String] | Hiding [String] + deriving (Eq, Ord, Show) data Pattern = PData String [Pattern] @@ -73,24 +73,27 @@ plist = foldr pcons pnil ptuple es = PData ("Tuple" ++ show (length es)) es brkt s = "{ " ++ s ++ " }" +parensIf b s = if b then parens s else s +isOp c = isSymbol c || elem c "+-/*=.$<>:&|^?%#@~!" instance Show Pattern where - show (PRecord fs) = brkt (intercalate ", " fs) - show (PVar x) = x - show PAnything = "_" - show (PData "Cons" [hd@(PData "Cons" _),tl]) = - parens (show hd) ++ " : " ++ show tl - where parens s = "(" ++ s ++ ")" - show (PData "Cons" [hd,tl]) = show hd ++ " : " ++ show tl - show (PData "Nil" []) = "[]" - show (PData name ps) = + show p = + case p of + PRecord fs -> brkt (intercalate ", " fs) + PVar x -> x + PAnything -> "_" + PData "Cons" [hd@(PData "Cons" _),tl] -> + parens (show hd) ++ " :: " ++ show tl + PData "Cons" [hd,tl] -> show hd ++ " : " ++ show tl + PData "Nil" [] -> "[]" + PData name ps -> if take 5 name == "Tuple" && all isDigit (drop 5 name) then parens . intercalate ", " $ map show ps - else (if null ps then id else parens) $ unwords (name : map show ps) - where parens s = "(" ++ s ++ ")" + else parensIf (not (null ps)) $ unwords (name : map show ps) instance Show Expr where show e = + let show' (C _ _ e) = parensIf (needsParens e) (show e) in case e of IntNum n -> show n FloatNum n -> show n @@ -116,7 +119,7 @@ instance Show Expr where where iff (b,e) = show b ++ " -> " ++ show e sep = concatMap ("\n | " ++) Let defs e -> "let { "++intercalate " ; " (map show defs)++" } in "++show e - Var x -> x + Var (c:cs) -> if isOp c then parens (c:cs) else c:cs Case e pats -> "case "++ show e ++" of " ++ brkt (intercalate " ; " pats') where pats' = map (\(p,e) -> show p ++ " -> " ++ show e) pats Data name es @@ -138,13 +141,13 @@ getLambdas (C _ _ (Lambda x e)) = (x:xs,e') where (xs,e') = getLambdas e getLambdas e = ([],e) -show' (C _ _ e) = if needsParens e then "(" ++ show e ++ ")" else show e - -needsParens (Binop _ _ _) = True -needsParens (Lambda _ _) = True -needsParens (App _ _) = True -needsParens (If _ _ _) = True -needsParens (Let _ _) = True -needsParens (Case _ _) = True -needsParens (Data name (x:xs)) = name /= "Cons" -needsParens _ = False +needsParens e = + case e of + Binop _ _ _ -> True + Lambda _ _ -> True + App _ _ -> True + If _ _ _ -> True + Let _ _ -> True + Case _ _ -> True + Data name (x:xs) -> name /= "Cons" + _ -> False diff --git a/elm/src/Context.hs b/compiler/Model/Context.hs similarity index 100% rename from elm/src/Context.hs rename to compiler/Model/Context.hs diff --git a/elm/src/Guid.hs b/compiler/Model/Guid.hs similarity index 77% rename from elm/src/Guid.hs rename to compiler/Model/Guid.hs index a3fa952..0681b00 100644 --- a/elm/src/Guid.hs +++ b/compiler/Model/Guid.hs @@ -1,5 +1,5 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Guid (guid, run, runAt, GuidCounter) where +module Guid (guid, set, run, runAt, GuidCounter) where import Control.Monad.State (evalState, State, get, put) @@ -13,5 +13,7 @@ guid = GC $ do n <- get put (n + 1) return n +set n = GC (put n) + run = runAt 0 runAt n x = evalState (runGC x) n \ No newline at end of file diff --git a/compiler/Model/Libraries.hs b/compiler/Model/Libraries.hs new file mode 100644 index 0000000..d050571 --- /dev/null +++ b/compiler/Model/Libraries.hs @@ -0,0 +1,59 @@ +module Libraries (libraries, addPrelude) where + +import Ast +import Control.Applicative ((<$>),(<*>)) +import qualified Data.Map as Map +import Data.List (inits) +import Text.JSON +import LoadLibraries as Libs + +addPrelude :: Module -> Module +addPrelude (Module name exs ims stmts) = Module name exs (customIms ++ ims) stmts + where customIms = concatMap addModule prelude + + addModule (n, method) = case lookup n ims of + Nothing -> [(n, method)] + Just (As m) -> [(n, method)] + Just _ -> [] + +prelude = text : map (\n -> (n, Hiding [])) modules + where + text = ("Text", Hiding ["link", "color", "height"]) + modules = [ "Prelude", "Signal", "List", "Maybe", "Time" + , "Graphics.Element", "Color", "Graphics.Collage" ] + +libraries :: Map.Map String (Map.Map String String) +libraries = + case getLibs of + Error err -> error err + Ok libs -> Map.unionWith Map.union libs nilAndTuples + where nilAndTuples = Map.singleton "Prelude" (Map.fromList pairs) + pairs = + [ ("Cons", "a -> [a] -> [a]") + , ("Nil", "[a]") + ] ++ map makeTuple (inits ['a'..'i']) + + makeTuple cs = + let name = "Tuple" ++ show (length cs) + in (name, concatMap (\c -> c : " -> ") cs ++ + name ++ concatMap (\c -> [' ',c]) cs) + +getLibs :: Result (Map.Map String (Map.Map String String)) +getLibs = do + obj <- decodeStrict Libs.docs :: Result (JSObject JSValue) + modules <- valFromObj "modules" obj :: Result [JSObject JSValue] + Map.fromList `fmap` mapM getValues modules + + +get :: String -> JSObject JSValue -> Result String +get = valFromObj + +getValue :: JSObject JSValue -> Result (String,String) +getValue obj = (,) <$> get "name" obj <*> get "type" obj + +getValues :: JSObject JSValue -> Result (String, Map.Map String String) +getValues obj = do + name <- get "name" obj + vs <- valFromObj "values" obj + vals <- mapM getValue vs + return (name, Map.fromList vals) \ No newline at end of file diff --git a/compiler/Model/LoadLibraries.hs b/compiler/Model/LoadLibraries.hs new file mode 100644 index 0000000..df900bd --- /dev/null +++ b/compiler/Model/LoadLibraries.hs @@ -0,0 +1,34 @@ +module LoadLibraries (docs) where + +import Control.DeepSeq (force) +import qualified Control.Exception as E +import Paths_Elm +import System.Directory +import System.FilePath +import System.IO.Unsafe (unsafePerformIO) + +-- See stackoverflow discussion for trade-off between using unsafeIO or TemplateHaskell: +-- http://stackoverflow.com/questions/12716215/load-pure-global-variable-from-file + +-- Given the awkwardness of including a compile-time generated file +-- vs loading static data, then the unsafeIO seems better. + +{-# NOINLINE docs #-} +docs :: String +docs = force $ unsafePerformIO (safeReadDocs =<< getDataFileName "docs.json") + +safeReadDocs :: FilePath -> IO String +safeReadDocs name = E.catch (readDocs name) (emitError name) + +readDocs :: FilePath -> IO String +readDocs name = do + exists <- doesFileExist name + if exists then readFile name + else ioError . userError $ "File Not Found" + + +emitError :: FilePath -> IOError -> IO String +emitError name err = do + putStrLn $ "Error! Types for standard library not loaded properly!\n File should be here:" ++ name ++ "\n The file is created and copied by command: cabal install" + putStrLn (show err) + return "{\"modules\":[]}" diff --git a/elm/src/Parse/Binops.hs b/compiler/Parse/Binops.hs similarity index 98% rename from elm/src/Parse/Binops.hs rename to compiler/Parse/Binops.hs index fa4a4a4..7cf4595 100644 --- a/elm/src/Parse/Binops.hs +++ b/compiler/Parse/Binops.hs @@ -28,6 +28,7 @@ table = [ (9, R, ".") , (3, R, "&&") , (2, R, "||") , (0, R, "$") + , (0, R, "<|"), (0, L, "|>") ] opLevel op = Map.findWithDefault 9 op dict diff --git a/elm/src/Parse/Expr.hs b/compiler/Parse/Expr.hs similarity index 100% rename from elm/src/Parse/Expr.hs rename to compiler/Parse/Expr.hs diff --git a/elm/src/Parse/Foreign.hs b/compiler/Parse/Foreign.hs similarity index 100% rename from elm/src/Parse/Foreign.hs rename to compiler/Parse/Foreign.hs diff --git a/elm/src/Parse/Library.hs b/compiler/Parse/Library.hs similarity index 95% rename from elm/src/Parse/Library.hs rename to compiler/Parse/Library.hs index 4ecf660..b3af65f 100644 --- a/elm/src/Parse/Library.hs +++ b/compiler/Parse/Library.hs @@ -6,7 +6,7 @@ import Context import Control.Applicative ((<$>),(<*>)) import Control.Monad import Control.Monad.State -import Data.Char (isSymbol,isUpper) +import Data.Char (isUpper) import Rename (deprime) import Text.Parsec hiding (newline,spaces,State) import Text.Parsec.Indent @@ -16,7 +16,7 @@ reserveds = [ "if", "then", "else" , "let", "in" , "data", "type" , "module", "where" - , "import", "as", "hiding" + , "import", "as", "hiding", "open" , "export", "foreign" ] expecting = flip (<?>) @@ -58,8 +58,6 @@ reserved word = anyOp :: IParser String anyOp = betwixt '`' '`' var <|> symOp <?> "infix operator (e.g. +, *, ||)" -isOp c = isSymbol c || elem c "+-/*=.$<>:&|^?%#@~!" - symOp :: IParser String symOp = do op <- many1 (satisfy isOp) guard (op `notElem` [ "=", "..", "->", "--", "|", "\8594", ":" ]) @@ -162,7 +160,7 @@ whitespace :: IParser () whitespace = optional forcedWS <?> "" freshLine :: IParser [[String]] -freshLine = try (do { many1 newline; many space_nl }) <|> try (many1 space_nl) <?> "" +freshLine = try (many1 newline >> many space_nl) <|> try (many1 space_nl) <?> "" where space_nl = try $ spaces >> many1 newline newline :: IParser String diff --git a/elm/src/Parse/Modules.hs b/compiler/Parse/Modules.hs similarity index 77% rename from elm/src/Parse/Modules.hs rename to compiler/Parse/Modules.hs index 04ff99c..391be4a 100644 --- a/elm/src/Parse/Modules.hs +++ b/compiler/Parse/Modules.hs @@ -30,18 +30,17 @@ import' :: IParser (String, ImportMethod) import' = do reserved "import" whitespace + open <- optionMaybe (reserved "open") + whitespace name <- intercalate "." <$> dotSep1 capVar - method <- option (Hiding []) $ try (whitespace >> - (as' <|> hiding' <|> importing')) - return (name, method) + case open of + Just _ -> return (name, Hiding []) + Nothing -> let how = try (whitespace >> (as' <|> importing')) + in (,) name <$> option (Importing []) how as' :: IParser ImportMethod as' = reserved "as" >> whitespace >> As <$> capVar <?> "alias for module" -hiding' :: IParser ImportMethod -hiding' = reserved "hiding" >> whitespace >> - Hiding <$> varList <?> "listing of hidden values" - importing' :: IParser ImportMethod importing' = Importing <$> varList <?> "listing of imported values (x,y,z)" \ No newline at end of file diff --git a/elm/src/Parse/Parser.hs b/compiler/Parse/Parser.hs similarity index 54% rename from elm/src/Parse/Parser.hs rename to compiler/Parse/Parser.hs index b5d3419..d943ec6 100644 --- a/elm/src/Parse/Parser.hs +++ b/compiler/Parse/Parser.hs @@ -1,10 +1,10 @@ -module Parse.Parser (parseProgram) where +module Parse.Parser (parseProgram, preParse) where import Ast import Control.Applicative ((<$>), (<*>)) import Control.Monad import Data.Char (isSymbol, isDigit) -import Data.List (foldl') +import Data.List (foldl',intercalate) import Text.Parsec hiding (newline,spaces) import Parse.Library @@ -14,8 +14,8 @@ import Parse.Modules import Parse.Foreign -statement = let defs = [ foreignDef, datatype, typeAlias, typeAnnotation ] in - (:[]) <$> choice defs <|> def <?> "datatype or variable definition" +statement = choice (typeAlias:defs) <|> def <?> "datatype or variable definition" + where defs = map ((:[]) <$>) [ foreignDef, datatype, typeAnnotation ] freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do freshLine @@ -33,7 +33,20 @@ program = do optional freshLine ; optional spaces ; eof return $ Module names exports is statements -parseProgram source = - case iParse program "" source of +parseProgram = setupParser program + +preParse :: String -> Either String (String, [String]) +preParse = setupParser $ do + optional skip + (,) <$> option "Main" moduleName <*> option [] imprts + where + skip = try (manyTill anyChar (try (string "/**"))) + imprts = fmap (map fst) imports `followedBy` freshLine + getName = intercalate "." . fst + moduleName = do optional freshLine + getName <$> moduleDef `followedBy` freshLine + +setupParser p source = + case iParse p "" source of Right result -> Right result Left err -> Left $ "Parse error at " ++ show err diff --git a/elm/src/Parse/Patterns.hs b/compiler/Parse/Patterns.hs similarity index 94% rename from elm/src/Parse/Patterns.hs rename to compiler/Parse/Patterns.hs index 829cbec..27a10c7 100644 --- a/elm/src/Parse/Patterns.hs +++ b/compiler/Parse/Patterns.hs @@ -88,10 +88,11 @@ matchSingle :: Pattern -> CExpr -> Pattern -> GuidCounter [Def] matchSingle pat exp@(C t s _) p = let ctx = C t s in case p of - PData _ ps -> do x <- guid - let v = '_' : show x - dss <- mapM (matchSingle p . ctx $ Var v) ps - return (FnDef v [] exp : concat dss) + PData _ ps -> do + x <- guid + let v = '_' : show x + dss <- mapM (matchSingle pat . ctx $ Var v) ps + return (FnDef v [] exp : concat dss) PVar x -> return [ FnDef x [] (ctx $ Case exp [(pat, ctx $ Var x)]) ] diff --git a/elm/src/Parse/Types.hs b/compiler/Parse/Types.hs similarity index 90% rename from elm/src/Parse/Types.hs rename to compiler/Parse/Types.hs index b038e4f..61eb882 100644 --- a/elm/src/Parse/Types.hs +++ b/compiler/Parse/Types.hs @@ -9,8 +9,9 @@ import Data.List (lookup) import Text.Parsec import Text.Parsec.Indent +import Context import Parse.Library -import Types.Types hiding (string,parens) +import Types.Types hiding (parens,string) import Guid data ParseType = VarPT String @@ -46,10 +47,7 @@ typeUnambiguous :: IParser ParseType typeUnambiguous = typeList <|> typeTuple <|> typeRecord typeSimple :: IParser ParseType -typeSimple = dealias <$> var - where dealias "String" = listPT (VarPT "Char") - dealias "Time" = VarPT "Float" - dealias v = VarPT v +typeSimple = VarPT <$> var typeApp :: IParser ParseType typeApp = do name <- capVar <?> "type constructor" @@ -70,8 +68,9 @@ typeConstructor :: IParser (String, [ParseType]) typeConstructor = (,) <$> (capVar <?> "another type constructor") <*> spacePrefix (typeSimple <|> typeUnambiguous) -typeAlias :: IParser Statement +typeAlias :: IParser [Statement] typeAlias = do + start <- getPosition reserved "type" <?> "type alias (type Point = {x:Int, y:Int})" forcedWS alias <- capVar @@ -79,9 +78,21 @@ typeAlias = do whitespace ; string "=" ; whitespace let n = length args tipe <- typeExpr + end <- getPosition case toTypeWith alias (zip args [1..n]) tipe of - Right t -> return (TypeAlias alias [1..n] t) Left msg -> fail msg + Right t -> return (TypeAlias alias [1..n] t : ctor) + where ctor = case tipe of + RecordPT _ kvs -> [toConstructor start end alias kvs] + _ -> [] + +toConstructor start end alias kvs = + Definition (FnDef alias args (ctxt (Record rec))) + where + ctxt = pos start end + args = map fst kvs + rec = map (\a -> (a, [], ctxt (Var a))) args + typeAnnotation :: IParser Statement typeAnnotation = TypeAnnotation <$> try start <*> (toType <$> typeExpr) diff --git a/compiler/Transform/LetBoundVars.hs b/compiler/Transform/LetBoundVars.hs new file mode 100644 index 0000000..e64b96d --- /dev/null +++ b/compiler/Transform/LetBoundVars.hs @@ -0,0 +1,53 @@ +module LetBoundVars (letBoundVars) where + +import Context +import Ast + +class LetBoundVars a where + letBoundVars :: a -> [String] + +instance LetBoundVars a => LetBoundVars [a] where + letBoundVars = concatMap letBoundVars + +instance LetBoundVars Statement where + letBoundVars stmt = + case stmt of + Definition d -> letBoundVars d + Datatype _ _ tcs -> [] + ImportEvent _ e _ _ -> letBoundVars e + ExportEvent _ _ _ -> [] + TypeAnnotation _ _ -> [] + TypeAlias _ _ _ -> [] + +instance LetBoundVars Def where + letBoundVars (FnDef n _ e) = n : letBoundVars e + letBoundVars (OpDef _ _ _ e) = letBoundVars e + +instance LetBoundVars e => LetBoundVars (Context e) where + letBoundVars (C _ _ e) = letBoundVars e + +instance LetBoundVars Expr where + letBoundVars expr = + let f = letBoundVars in + case expr of + IntNum _ -> [] + FloatNum _ -> [] + Chr _ -> [] + Str _ -> [] + Boolean _ -> [] + Range e1 e2 -> f e1 ++ f e2 + Access e _ -> [] + Remove e _ -> [] + Insert e1 _ e2 -> f e1 ++ f e2 + Modify e ps -> f e ++ concatMap (f . snd) ps + Record trps -> concatMap (\(_,_,e) -> f e) trps + Binop op e1 e2 -> f e1 ++ f e2 + Lambda x e -> f e + App e1 e2 -> f e1 ++ f e2 + If e1 e2 e3 -> concatMap f [e1,e2,e3] + MultiIf ps -> concatMap (\(b,e) -> f b ++ f e) ps + Let defs e -> concatMap letBoundVars defs ++ f e + Var x -> [] + Data name es -> concatMap f es + Case e cases -> f e ++ concatMap (f . snd) cases + Markdown _ -> [] diff --git a/elm/src/Optimize.hs b/compiler/Transform/Optimize.hs similarity index 97% rename from elm/src/Optimize.hs rename to compiler/Transform/Optimize.hs index 468364a..0242d6d 100644 --- a/elm/src/Optimize.hs +++ b/compiler/Transform/Optimize.hs @@ -112,7 +112,7 @@ binop op ce1@(C t1 s1 e1) ce2@(C t2 s2 e2) = ("||", Boolean True, _) -> Boolean True ("||", Boolean False, _) -> e2 - (":", _, _) -> let (C _ _ e) = cons ce1 ce2 in e + ("::", _, _) -> let (C _ _ e) = cons ce1 ce2 in e ("++", Str s1, Str s2) -> Str $ s1 ++ s2 ("++", Str s1, Binop "++" (C _ _ (Str s2)) ce) -> @@ -124,6 +124,8 @@ binop op ce1@(C t1 s1 e1) ce2@(C t2 s2 e2) = ("++", _, Data "Nil" []) -> e1 ("++", Data "Cons" [h,t], _) -> Data "Cons" [h, noContext $ binop "++" t ce2] + ("|>", _, _) -> App ce2 ce1 + ("<|", _, _) -> App ce1 ce2 ("$", _, _) -> App ce1 ce2 (".", _, _) -> Lambda "x" (noContext $ diff --git a/elm/src/Rename.hs b/compiler/Transform/Rename.hs similarity index 98% rename from elm/src/Rename.hs rename to compiler/Transform/Rename.hs index ea2c843..2b1f491 100644 --- a/elm/src/Rename.hs +++ b/compiler/Transform/Rename.hs @@ -133,6 +133,8 @@ patternExtend pattern env = first (PData name . reverse) `liftM` foldM f ([], env) ps where f (rps,env') p = do (rp,env'') <- patternExtend p env' return (rp:rps, env'') + PRecord fs -> + return (pattern, foldr (\f e n -> if n == f then f else env n) env fs) patternRename :: (String -> String) -> (Pattern, CExpr) -> GuidCounter (Pattern, CExpr) patternRename env (p,e) = do diff --git a/elm/src/Replace.hs b/compiler/Transform/Replace.hs similarity index 100% rename from elm/src/Replace.hs rename to compiler/Transform/Replace.hs diff --git a/elm/src/Substitute.hs b/compiler/Transform/Substitute.hs similarity index 100% rename from elm/src/Substitute.hs rename to compiler/Transform/Substitute.hs diff --git a/elm/src/Types/Alias.hs b/compiler/Types/Alias.hs similarity index 71% rename from elm/src/Types/Alias.hs rename to compiler/Types/Alias.hs index d9d496a..5f28ae8 100644 --- a/elm/src/Types/Alias.hs +++ b/compiler/Types/Alias.hs @@ -1,5 +1,5 @@ -module Types.Alias (dealias, mistakes) where +module Types.Alias (dealias, get, mistakes) where import Ast import Control.Arrow (second) @@ -10,37 +10,39 @@ import Types.Substitutions (subst) import Types.Types builtins :: [(String,([X],Type))] -builtins = [ ("String", ([], string)) ] +builtins = + let touch = ("t0", time) : map (flip (,) int) ["x","y","x0","y0","id"] + state = [("string", string), ("selectionStart", int), ("selectionEnd", int)] + line = [("color", tipe "Color"), ("width", float), + ("cap", tipe "LineCap"), ("join", tipe "LineJoin"), + ("miterLimit", float), ("dashing", listOf int), + ("dashOffset", int)] + makeRecord fields = + RecordT (Map.fromList $ map (second (:[])) fields) EmptyRecord + in [ ("String", ([], listOf char)), + ("Time", ([], float)), + ("KeyCode", ([], int)), + ("Touch", ([], makeRecord touch)), + ("FieldState", ([], makeRecord state)), + ("LineStyle", ([], makeRecord line)) + ] -getAliases :: [Statement] -> Map.Map String ([X],Type) -getAliases stmts = Map.fromList (builtins ++ concatMap getAlias stmts) +get :: [Statement] -> Map.Map String ([X],Type) +get stmts = Map.fromList (builtins ++ concatMap getAlias stmts) where getAlias stmt = case stmt of TypeAlias alias xs t -> [(alias, (xs,t))] _ -> [] - -dealias :: [Statement] -> [Statement] -dealias stmts = map dealiasS stmts - where - dealiasT :: Type -> Type - dealiasT t = - case t of - ADT name ts -> case Map.lookup name (getAliases stmts) of - Just (xs,t) -> dealiasT (subst (zip xs ts) t) - Nothing -> ADT name (map dealiasT ts) - LambdaT t u -> LambdaT (dealiasT t) (dealiasT u) - RecordT r t -> RecordT (Map.map (map dealiasT) r) (dealiasT t) - _ -> t - - dealiasS :: Statement -> Statement - dealiasS s = - case s of - Datatype n xs tcs -> Datatype n xs (map (second (map dealiasT)) tcs) - ExportEvent js elm tipe -> ExportEvent js elm (dealiasT tipe) - ImportEvent js e elm tipe -> ImportEvent js e elm (dealiasT tipe) - TypeAnnotation name tipe -> TypeAnnotation name (dealiasT tipe) - TypeAlias alias xs tipe -> TypeAlias alias xs (dealiasT tipe) - Definition _ -> s +dealias :: Map.Map String ([X],Type) -> Type -> Type +dealias aliases t = + let f = dealias aliases in + case t of + ADT name ts -> case Map.lookup name aliases of + Just (xs,t) -> f (subst (zip xs ts) t) + Nothing -> ADT name (map f ts) + LambdaT t u -> LambdaT (f t) (f u) + RecordT r t -> RecordT (Map.map (map f) r) (f t) + _ -> t mistakes :: [Statement] -> [String] mistakes stmts = badKinds stmts ++ dups stmts ++ badOrder stmts @@ -55,7 +57,7 @@ badKinds stmts = map msg (concatMap badS stmts) badT t = case t of ADT name ts -> - case Map.lookup name (getAliases stmts) of + case Map.lookup name (get stmts) of Just (xs,t) | length xs == length ts -> [] | otherwise -> [name] Nothing -> concatMap badT ts diff --git a/elm/src/Types/Constrain.hs b/compiler/Types/Constrain.hs similarity index 83% rename from elm/src/Types/Constrain.hs rename to compiler/Types/Constrain.hs index 325ec03..61c40e8 100644 --- a/elm/src/Types/Constrain.hs +++ b/compiler/Types/Constrain.hs @@ -4,6 +4,7 @@ module Types.Constrain (constrain) where import Control.Arrow (second) import Control.Monad (liftM,mapM,zipWithM,foldM) import Control.Monad.State (evalState) +import Data.Char (isDigit) import Data.List (foldl',sort,group,isPrefixOf,intercalate,isSuffixOf) import qualified Data.Map as Map import qualified Data.Set as Set @@ -13,32 +14,33 @@ import Context import Guid import Types.Types -import Types.Substitutions +import qualified Types.Substitutions as Subs beta = VarT `liftM` guid unionA = Map.unionWith (++) unionsA = Map.unionsWith (++) -getAliases imports hints = hints ++ concatMap aliasesFrom imports' - where imports' = map head . group $ sort imports - aliasesFrom (name,method) = - case method of - As alias -> concatMap (findAlias name alias) hints - Hiding [] -> concatMap (findAlias name "") hints - _ -> [] - findAlias mName' mAlias (name,tipe) = - let mName = mName' ++ "." in - case mName `isPrefixOf` name of - True -> [ (mAlias ++ drop (length mName) name, tipe) ] - False -> [] +getAliases imports hints = concatMap aliasesFrom imports + where aliasesFrom (name,method) = + let values = concatMap (getValue name) hints + in case method of + As alias -> map (\(n,t) -> (alias ++ "." ++ n, t)) values + Hiding vs -> filter (\(n,t) -> n `notElem` vs) values + Importing vs -> filter (\(n,t) -> n `elem` vs) values + getValue inModule (name,tipe) = + case inModule `isPrefixOf` name of + True -> [ (drop (length inModule + 1) name, tipe) ] + False -> [] -findAmbiguous hints hints' assumptions continue = - let potentialDups = map head . filter (\g -> length g > 1) . group $ sort hints' - dups = filter (\k -> Map.member k assumptions) potentialDups - in case dups of - n:_ -> return . Left $ "Error: Ambiguous occurrence of '" ++ n ++ "' could refer to " ++ - intercalate ", " (filter (isSuffixOf n) hints) - _ -> continue +findAmbiguous hints assumptions continue = + let potentialDups = map head . filter (\g -> length g > 1) . group . sort $ + filter (elem '.') hints + dups = filter (\k -> Map.member k assumptions) potentialDups + in case dups of + n:_ -> return . Left $ "Error: Ambiguous occurrence of '" ++ n ++ + "' could refer to " ++ + intercalate ", " (filter (isSuffixOf n) hints) + _ -> continue mergeSchemes :: [Map.Map String Scheme] -> GuidCounter (TVarMap, ConstraintSet, Map.Map String Scheme) @@ -59,21 +61,20 @@ mergeSchemes schmss = do (ass,css,sss) <- unzip3 `liftM` mapM split kvs constrain typeHints (Module _ _ imports stmts) = do (ass,css,schemess) <- unzip3 `liftM` mapM stmtGen stmts - hints <- typeHints + aliasHints <- getAliases imports `liftM` typeHints (as', cs', schemes) <- mergeSchemes schemess let constraints = Set.unions (cs':css) as = unionsA (as':ass) - extraImports = ("Time", Hiding ["read"]) : map (\n -> (n, Hiding [])) - ["List","Signal","Text","Graphics","Color"] - aliasHints = getAliases (imports ++ extraImports) hints allHints = Map.union schemes (Map.fromList aliasHints) insert as n = do v <- guid; return $ Map.insertWith' (\_ x -> x) n [v] as assumptions <- foldM insert as (Map.keys schemes) - findAmbiguous (map fst hints) (map fst aliasHints) assumptions $ do + findAmbiguous (map fst aliasHints) assumptions $ do let f k s vs = map (\v -> C (Just k) NoSpan $ v :<<: s) vs cs = concat . Map.elems $ Map.intersectionWithKey f allHints assumptions escapees = Map.keys $ Map.difference assumptions allHints - return . Right . (,) escapees $ Set.toList constraints ++ cs + return $ case escapees of + _ -> Right (Set.toList constraints ++ cs) + --_ -> Left ("Undefined variable(s): " ++ intercalate ", " escapees) type TVarMap = Map.Map String [X] type ConstraintSet = Set.Set (Context Constraint) @@ -232,13 +233,13 @@ caseGen tipe (p, ce@(C _ span e)) = do return ( as', Set.union cs cs', t ) patternGen :: (Constraint -> Context Constraint) - -> Type + -> Type -- Type of e in `case e of ...` -> TVarMap -> Pattern -> GuidCounter (TVarMap, ConstraintSet, Type) patternGen ctxt tipe as pattern = case pattern of - PAnything -> do b <- beta ; return (Map.empty, Set.empty, b) + PAnything -> do b <- beta ; return ( as, Set.empty, b ) PVar v -> do b <- beta let cs = map (ctxt . (b :=:) . VarT) (Map.findWithDefault [] v as) @@ -253,6 +254,15 @@ patternGen ctxt tipe as pattern = return ( Map.insert name [constr] as' , Set.insert (ctxt (VarT constr :=: t)) cs , output ) + PRecord fs -> + do pairs <- mapM (\f -> do b <- beta; return (f,b)) fs + b <- beta + let t = RecordT (Map.fromList $ map (second (:[])) pairs) b + mkCs (name,tipe) = map (ctxt . (tipe :=:) . VarT) + (Map.findWithDefault [] name as) + return ( foldr Map.delete as fs + , Set.fromList (ctxt (t :=: tipe) : concatMap mkCs pairs) + , t ) defScheme :: Def -> GuidCounter (Map.Map String [X], Scheme) @@ -273,7 +283,7 @@ defGenHelp name args e = do let as' = Map.findWithDefault [v] arg as return $ map (\y -> ctx arg NoSpan $ VarT x :=: VarT y) as' cs' <- concat `liftM` mapM genCs argDict - scheme <- generalize (concat $ Map.elems as') $ + scheme <- Subs.generalize (concat $ Map.elems as') $ Forall (map snd argDict) (cs' ++ Set.toList cs) tipe return ( as', Set.empty, (name, scheme) ) @@ -302,7 +312,7 @@ stmtGen stmt = , Map.singleton elm (Forall [] [] tipe) ) TypeAnnotation name tipe -> - do schm <- generalize [] (Forall [] [] tipe) + do schm <- Subs.generalize [] =<< Subs.superize name tipe return (Map.empty, Set.empty, Map.singleton name schm) TypeAlias _ _ _ -> return (Map.empty, Set.empty, Map.empty) diff --git a/compiler/Types/Hints.hs b/compiler/Types/Hints.hs new file mode 100644 index 0000000..7068857 --- /dev/null +++ b/compiler/Types/Hints.hs @@ -0,0 +1,31 @@ +module Types.Hints (hints) where + +import Control.Arrow (first) +import Control.Monad (liftM) +import Data.Maybe (catMaybes) +import qualified Data.Map as Map +import Guid +import qualified Libraries as Libs +import Parse.Library (iParse) +import Parse.Types +import qualified Types.Substitutions as Subs +import Types.Types + +hints :: GuidCounter [(String, Scheme)] +hints = liftM catMaybes (mapM toScheme values) + where + values :: [(String, String)] + values = addPrefixes (Map.toList (Map.map Map.toList Libs.libraries)) + + addPrefixes :: [(String,[(String, String)])] -> [(String, String)] + addPrefixes = concatMap (\(m,vs) -> map (first (\n -> m ++ "." ++ n)) vs) + + toScheme :: (String, String) -> GuidCounter (Maybe (String, Scheme)) + toScheme (name, 't':'y':'p':'e':' ':_) = return Nothing + toScheme (name, 'd':'a':'t':'a':' ':_) = return Nothing + toScheme (name, tipeString) = + let err = "compiler error parsing type of " ++ name ++ ":\n" ++ tipeString in + case iParse (fmap toType typeExpr) err tipeString of + Left err -> error (show err) + Right tipe -> do scheme <- Subs.generalize [] =<< Subs.superize name tipe + return (Just (name, scheme)) diff --git a/elm/src/Types/Solver.hs b/compiler/Types/Solver.hs similarity index 66% rename from elm/src/Types/Solver.hs rename to compiler/Types/Solver.hs index ac53de4..e3716a8 100644 --- a/elm/src/Types/Solver.hs +++ b/compiler/Types/Solver.hs @@ -13,14 +13,17 @@ import Guid import Types.Types import Types.Constrain import Types.Substitutions +import Types.Alias (dealias) isSolved ss (C _ _ (t1 :=: t2)) = t1 == t2 isSolved ss (C _ _ (x :<<: _)) = isJust (lookup x ss) isSolved ss c = False -crush :: Scheme -> GuidCounter (Either String Scheme) -crush (Forall xs cs t) = - do subs <- solver cs Map.empty +type Aliases = Map.Map String ([X],Type) + +crush :: Aliases -> Scheme -> GuidCounter (Either String Scheme) +crush aliases (Forall xs cs t) = + do subs <- solver aliases Map.empty cs return $ do ss' <- subs let ss = Map.toList ss' cs' = filter (not . isSolved ss) (subst ss cs) @@ -34,10 +37,11 @@ schemeSubHelp txt span x s t1 rltn t2 = do | otherwise = do (st, cs) <- concretize s return (subst [(x,st)] t, cs) -schemeSub x s c = do s' <- crush s - case s' of - Right s'' -> Right `liftM` schemeSub' x s'' c - Left err -> return $ Left err +schemeSub aliases x s c = + do s' <- crush aliases s + case s' of + Right s'' -> Right `liftM` schemeSub' x s'' c + Left err -> return $ Left err schemeSub' x s c@(C txt span constraint) = case constraint of @@ -77,29 +81,32 @@ recordConstraints eq fs t fs' t' = let tipe = RecordT (Map.singleton k bs) (VarT x) return (cs ++ [eq t tipe]) -solver :: [Context Constraint] +solver :: Aliases -> Map.Map X Type + -> [Context Constraint] -> GuidCounter (Either String (Map.Map X Type)) -solver [] subs = return $ Right subs -solver (C txt span c : cs) subs = +solver _ subs [] = return $ Right subs +solver aliases subs (C txt span c : cs) = let ctx = C txt span eq t1 t2 = ctx (t1 :=: t2) + solv = solver aliases subs + uniError' = uniError (\t1 t2 -> solv (eq t1 t2 : cs)) aliases txt span in case c of -- Destruct Type-constructors t1@(ADT n1 ts1) :=: t2@(ADT n2 ts2) -> - if n1 /= n2 then uniError txt span t1 t2 else - solver (zipWith eq ts1 ts2 ++ cs) subs + if n1 == n2 then solv (zipWith eq ts1 ts2 ++ cs) + else uniError' t1 t2 LambdaT t1 t2 :=: LambdaT t1' t2' -> - solver ([ eq t1 t1', eq t2 t2' ] ++ cs) subs + solv ([ eq t1 t1', eq t2 t2' ] ++ cs) RecordT fs t :=: RecordT fs' t' -> do cs' <- recordConstraints eq fs t fs' t' - solver (cs' ++ cs) subs + solv (cs' ++ cs) -- Type-equality VarT x :=: VarT y - | x == y -> solver cs subs + | x == y -> solv cs | otherwise -> case (Map.lookup x subs, Map.lookup y subs) of (Just (Super xts), Just (Super yts)) -> @@ -108,68 +115,69 @@ solver (C txt span c : cs) subs = in case Set.toList ts of [] -> unionError txt span xts yts [t] -> let cs1 = subst [(x,t),(y,t)] cs in - cs1 `seq` solver cs1 (setXY t subs) - _ -> solver cs $ setXY (Super ts) subs + cs1 `seq` solver aliases (setXY t subs) cs1 + _ -> solver aliases (setXY (Super ts) subs) cs (Just (Super xts), _) -> let cs2 = subst [(y,VarT x)] cs in - solver cs2 $ Map.insert y (VarT x) subs + solver aliases (Map.insert y (VarT x) subs) cs2 (_, _) -> let cs3 = subst [(x,VarT y)] cs in - solver cs3 $ Map.insert x (VarT y) subs + solver aliases (Map.insert x (VarT y) subs) cs3 VarT x :=: t -> do if x `occurs` t then occursError txt span (VarT x) t else (case Map.lookup x subs of - Nothing -> let cs4 = subst [(x,t)] cs in - solver cs4 . Map.map (subst [(x,t)]) $ - Map.insert x t subs + Nothing -> + let cs4 = subst [(x,t)] cs + subs' = Map.map (subst [(x,t)]) $ Map.insert x t subs + in solver aliases subs' cs4 Just (Super ts) -> let ts' = Set.intersection ts (Set.singleton t) in case Set.toList ts' of - [] -> solver (ctx (t :<: Super ts) : cs) subs + [] -> solv (ctx (t :<: Super ts) : cs) [t'] -> let cs5 = subst [(x,t)] cs in - solver cs5 $ Map.insert x t' subs - _ -> solver cs $ Map.insert x (Super ts') subs - Just t' -> solver (ctx (t' :=: t) : cs) subs + solver aliases (Map.insert x t' subs) cs5 + _ -> solver aliases (Map.insert x (Super ts') subs) cs + Just t' -> solv (ctx (t' :=: t) : cs) ) - t :=: VarT x -> solver ((ctx (VarT x :=: t)) : cs) subs + t :=: VarT x -> solv ((ctx (VarT x :=: t)) : cs) - t1 :=: t2 | t1 == t2 -> solver cs subs - | otherwise -> uniError txt span t1 t2 + t1 :=: t2 | t1 == t2 -> solv cs + | otherwise -> uniError' t1 t2 -- subtypes VarT x :<: Super ts -> case Map.lookup x subs of - Nothing -> solver cs $ Map.insert x (Super ts) subs + Nothing -> solver aliases (Map.insert x (Super ts) subs) cs Just (Super ts') -> case Set.toList $ Set.intersection ts ts' of [] -> unionError txt span ts ts' - [t] -> solver (subst [(x,t)] cs) $ Map.insert x t subs - ts'' -> solver cs $ - Map.insert x (Super $ Set.fromList ts'') subs + [t] -> solver aliases (Map.insert x t subs) (subst [(x,t)] cs) + ts'' -> solver aliases subs' cs + where subs' = Map.insert x (Super $ Set.fromList ts'') subs ADT "List" [t] :<: Super ts - | any f (Set.toList ts) -> solver cs subs + | any f (Set.toList ts) -> solv cs | otherwise -> subtypeError txt span (ADT "List" [t]) (Super ts) where f (ADT "List" [VarT _]) = True - f (ADT "List" [t']) = t == t' + f (ADT "List" [t']) = dealias aliases t == t' f _ = False t :<: Super ts - | Set.member t ts -> solver cs subs - | otherwise -> subtypeError txt span t (Super ts) + | Set.member t ts -> solv cs + | Set.member (dealias aliases t) ts -> solv cs + | otherwise -> subtypeError txt span t (Super ts) x :<<: s | any (occurs x) cs -> - do css <- mapM (schemeSub x s) cs + do css <- mapM (schemeSub aliases x s) cs case lefts css of err : _ -> return $ Left err - [] -> solver (concat (rights css)) subs + [] -> solv (concat (rights css)) | otherwise -> do (t,cs7) <- concretize s - let cs'' = (cs ++ ctx (VarT x :=: t) : cs7) - solver cs'' subs + solv (cs ++ ctx (VarT x :=: t) : cs7) showMsg msg = case msg of Just str -> "\nIn context: " ++ str @@ -181,10 +189,14 @@ occursError msg span t1 t2 = , "Occurs check: cannot construct the infinite type:\n" , show t1, " = ", show t2, showMsg msg ] -uniError msg span t1 t2 = - return . Left $ concat - [ "Type error (" ++ show span ++ "):\n" - , show t1, " is not equal to ", show t2, showMsg msg ] +uniError solveWith aliases msg span t1 t2 = + let t1' = dealias aliases t1 + t2' = dealias aliases t2 + in if t1 /= t1' || t2 /= t2' + then solveWith t1' t2' + else return . Left $ concat + [ "Type error (" ++ show span ++ "):\n" + , show t1, " is not equal to ", show t2, showMsg msg ] unionError msg span ts ts' = return . Left $ concat diff --git a/elm/src/Types/Substitutions.hs b/compiler/Types/Substitutions.hs similarity index 52% rename from elm/src/Types/Substitutions.hs rename to compiler/Types/Substitutions.hs index 71bccaf..70549b6 100644 --- a/elm/src/Types/Substitutions.hs +++ b/compiler/Types/Substitutions.hs @@ -1,16 +1,17 @@ - +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Types.Substitutions (subst, occurs, freeVars, concretize, rescheme, - generalize) where + generalize, + superize) where import Ast import Context -import Control.DeepSeq (NFData (..), deepseq) -import Control.Monad (liftM) -import Data.List (foldl') +import Control.Monad (liftM, liftM2) +import Control.Monad.State (runState, State, get, put) +import Data.List (nub) import qualified Data.Set as Set import qualified Data.Map as Map import Guid @@ -51,13 +52,14 @@ class FreeVars a where freeVars :: a -> [X] instance FreeVars Type where - freeVars (VarT v) = [v] - freeVars (LambdaT t1 t2) = freeVars t1 ++ freeVars t2 - freeVars (ADT _ ts) = concatMap freeVars ts - freeVars (RecordT fs t) = - freeVars (concat $ Map.elems fs) ++ freeVars t - freeVars EmptyRecord = [] - freeVars (Super _ ) = [] + freeVars t = + case t of + VarT v -> [v] + LambdaT t1 t2 -> freeVars t1 ++ freeVars t2 + ADT _ ts -> concatMap freeVars ts + RecordT fs t -> freeVars (concat $ Map.elems fs) ++ freeVars t + EmptyRecord -> [] + Super _ -> [] instance FreeVars Constraint where freeVars (t1 :=: t2) = freeVars t1 ++ freeVars t2 @@ -88,3 +90,47 @@ generalize :: [X] -> Scheme -> GuidCounter Scheme generalize exceptions (Forall xs cs t) = rescheme (Forall (xs ++ frees) cs t) where allFrees = Set.fromList $ freeVars t ++ concatMap freeVars cs frees = Set.toList $ Set.difference allFrees (Set.fromList exceptions) + +newtype Superize a = S { runSuper :: State ([X], [X], [X]) a } + deriving (Monad) + +superize :: String -> Type -> GuidCounter Scheme +superize name tipe = + do constraints <- liftM concat $ + sequence [ mapM (<: nmbr) (nub ns) + , mapM (<: apnd) (nub as) + , mapM (<: comp) (nub cs) ] + return (Forall (concat [ns,as,cs]) constraints tipe') + where + (tipe', (ns,as,cs)) = runState (runSuper (go tipe)) ([],[],[]) + t <: super = do x <- guid + return $ C (Just name) NoSpan (VarT t :<: super x) + + nmbr t = number + apnd t = appendable t + comp t = comparable t + + go :: Type -> Superize Type + go t = + case t of + EmptyRecord -> return t + Super _ -> return t + VarT _ -> return t + LambdaT t1 t2 -> liftM2 LambdaT (go t1) (go t2) + ADT "Number" [VarT t] -> addNumber t + ADT "Appendable" [VarT t] -> addAppendable t + ADT "Comparable" [VarT t] -> addComparable t + ADT name ts -> liftM (ADT name) (mapM go ts) + RecordT fs t -> liftM2 RecordT fs' (go t) + where pairs = Map.toList fs + fs' = do ps <- mapM (\(f,t) -> liftM ((,) f) (mapM go t)) pairs + return (Map.fromList ps) + + add :: (X -> ([X],[X],[X]) -> ([X],[X],[X])) -> X -> Superize Type + add f v = S $ do (ns, as, cs) <- get + put $ f v (ns, as, cs) + return (VarT v) + + addNumber = add (\n (ns,as,cs) -> (n:ns,as,cs)) + addAppendable = add (\a (ns,as,cs) -> (ns,a:as,cs)) + addComparable = add (\c (ns,as,cs) -> (ns,as,c:cs)) \ No newline at end of file diff --git a/compiler/Types/Types.hs b/compiler/Types/Types.hs new file mode 100644 index 0000000..655e32b --- /dev/null +++ b/compiler/Types/Types.hs @@ -0,0 +1,94 @@ + +module Types.Types where + +import Context +import Data.Char (isDigit) +import Data.List (intercalate,isPrefixOf) +import qualified Data.Set as Set +import qualified Data.Map as Map + +type X = Int + +data Type = LambdaT Type Type + | VarT X + | ADT String [Type] + | EmptyRecord + | RecordT (Map.Map String [Type]) Type + | Super (Set.Set Type) + deriving (Eq, Ord) + +data Scheme = Forall [X] [Context Constraint] Type deriving (Eq, Ord, Show) + +data Constraint = Type :=: Type + | Type :<: Type + | X :<<: Scheme + deriving (Eq, Ord, Show) + +recordT :: [(String,Type)] -> Map.Map String [Type] +recordT fields = + foldl (\r (x,t) -> Map.insertWith (++) x [t] r) Map.empty fields + +recordOf :: [(String,Type)] -> Type +recordOf fields = RecordT (recordT fields) EmptyRecord + +tipe t = ADT t [] + +int = tipe "Int" +float = tipe "Float" +time = tipe "Time" +date = tipe "Date" + +char = tipe "Char" +bool = tipe "Bool" +text = tipe "Text" +order = tipe "Order" +string = tipe "String" + +number = Super $ Set.fromList [ int, float, time ] +appendable t = Super $ Set.fromList [ string, text, listOf (VarT t) ] +comparable t = Super $ Set.fromList [ int, float, char, string, time, date ] + +element = tipe "Element" + +listOf t = ADT "List" [t] +signalOf t = ADT "Signal" [t] +tupleOf ts = ADT ("Tuple" ++ show (length ts)) ts +maybeOf t = ADT "Maybe" [t] +eitherOf a b = ADT "Either" [a,b] +pairOf t = tupleOf [t,t] +point = pairOf int + +infixr ==> +t1 ==> t2 = LambdaT t1 t2 + +infix 8 -: +name -: tipe = (,) name $ Forall [] [] tipe + +parens = ("("++) . (++")") + +instance Show Type where + show t = + let addParens (c:cs) = + if notElem ' ' cs || c == '(' then c:cs else parens (c:cs) + in case t of + LambdaT t1@(LambdaT _ _) t2 -> parens (show t1) ++ " -> " ++ show t2 + LambdaT t1 t2 -> show t1 ++ " -> " ++ show t2 + VarT x -> 't' : show x + ADT "List" [ADT "Char" []] -> "String" + ADT "List" [tipe] -> "[" ++ show tipe ++ "]" + ADT name cs -> + if isTupleString name + then parens . intercalate "," $ map show cs + else name ++ concatMap ((' ':) . addParens . show) cs + Super ts -> "{" ++ (intercalate "," . map show $ Set.toList ts) ++ "}" + EmptyRecord -> "{}" + RecordT fs t -> + start ++ intercalate ", " (concatMap fields $ Map.toList fs) ++ " }" + where field n s = n ++ " : " ++ show s + fields (n,ss) = map (field n) ss + start = case t of + EmptyRecord -> "{ " + _ -> "{ " ++ show t ++ " | " + + +isTupleString str = "Tuple" `isPrefixOf` str && all isDigit (drop 5 str) \ No newline at end of file diff --git a/compiler/Types/Unify.hs b/compiler/Types/Unify.hs new file mode 100644 index 0000000..f4002cb --- /dev/null +++ b/compiler/Types/Unify.hs @@ -0,0 +1,16 @@ + +module Types.Unify (unify) where + +import Control.Monad (liftM) +import qualified Data.Map as Map + +import Ast +import Guid +import Types.Constrain +import Types.Solver +import Types.Alias as Alias + +unify hints modul@(Module _ _ _ stmts) = run $ do + constraints <- constrain hints modul + either (return . Left) (solver (Alias.get stmts) Map.empty) constraints + diff --git a/core-js/Automaton.js b/core-js/Automaton.js deleted file mode 100644 index 1eb9d59..0000000 --- a/core-js/Automaton.js +++ /dev/null @@ -1,221 +0,0 @@ - -(function() { -try{ - -var $op={}; -for(this['i'] in Elm){eval('var '+this['i']+'=Elm[this.i];');} -if (Elm.Automaton) throw new Error("Module name collision, 'Automaton' is already defined."); -Elm.Automaton=function(){ - try{ - if (!(Elm.Prelude instanceof Object)) throw 'module not found'; - } catch(e) { - throw ("Module 'Prelude' is missing. Compile with --make flag or load missing module in a separate JavaScript file."); - } - var hiddenVars={}; - for (this['i'] in Elm.Prelude) { - if (hiddenVars[this['i']]) continue; - eval('var ' + this['i'] + ' = Elm.Prelude[this.i];');} - function Automaton_0(a1){ - return ["Automaton",a1];} - var Listen_8=["Listen"]; - var Ignore_9=["Ignore"]; - function DragFrom_10(a1){ - return ["DragFrom",a1];} - $op['>>>'] = function(a1_24){ - return function(a2_25){ - return function(){ - var Automaton$m1_26=a1_24; - var m1_27=function(){ - switch(Automaton$m1_26[0]){ - case "Automaton": - return Automaton$m1_26[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var Automaton$m2_28=a2_25; - var m2_29=function(){ - switch(Automaton$m2_28[0]){ - case "Automaton": - return Automaton$m2_28[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return Automaton_0(function(a_32){ - return function(){ - var Tuple2$bm1__33=m1_27(a_32); - var b_34=function(){ - switch(Tuple2$bm1__33[0]){ - case "Tuple2": - return Tuple2$bm1__33[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var m1__35=function(){ - switch(Tuple2$bm1__33[0]){ - case "Tuple2": - return Tuple2$bm1__33[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return function(){ - var Tuple2$cm2__40=m2_29(b_34); - var c_41=function(){ - switch(Tuple2$cm2__40[0]){ - case "Tuple2": - return Tuple2$cm2__40[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var m2__42=function(){ - switch(Tuple2$cm2__40[0]){ - case "Tuple2": - return Tuple2$cm2__40[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",c_41,$op['>>>'](m1__35)(m2__42)];}();}();});}();};}; - $op['<<<'] = function(a2_47){ - return function(a1_48){ - return $op['>>>'](a1_48)(a2_47);};}; - $op['^>>'] = function(f_49){ - return function(a_50){ - return $op['>>>'](pure_4(f_49))(a_50);};}; - $op['>>^'] = function(a_51){ - return function(f_52){ - return $op['>>>'](a_51)(pure_4(f_52));};}; - $op['^<<'] = function(f_53){ - return function(a_54){ - return $op['>>>'](a_54)(pure_4(f_53));};}; - $op['<<^'] = function(a_55){ - return function(f_56){ - return $op['>>>'](pure_4(f_56))(a_55);};}; - var count_7=init_5(0)(function(__84){ - return function(c_85){ - return (1+c_85);};}); - function run_1(Automaton$m0_14){ - return function(input_15){ - return function(){ - switch(Automaton$m0_14[0]){ - case "Automaton": - return lift(fst)(foldp$(function(a_17){ - return function(Tuple2$bAutomaton$m_18){ - return function(){ - switch(Tuple2$bAutomaton$m_18[0]){ - case "Tuple2": - switch(Tuple2$bAutomaton$m_18[2][0]){ - case "Automaton": - return Tuple2$bAutomaton$m_18[2][1](a_17); - }break; - } - throw new Error("Non-exhaustive pattern match in case");}();};})(Automaton$m0_14[1])(input_15)); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function step_2(Automaton$m_21){ - return function(a_22){ - return function(){ - switch(Automaton$m_21[0]){ - case "Automaton": - return Automaton$m_21[1](a_22); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function combine_3(autos_57){ - return Automaton_0(function(a_58){ - return function(){ - var Tuple2$bsautos__59=unzip(map(function(Automaton$m_62){ - return function(){ - switch(Automaton$m_62[0]){ - case "Automaton": - return Automaton$m_62[1](a_58); - } - throw new Error("Non-exhaustive pattern match in case");}();})(autos_57)); - var bs_60=function(){ - switch(Tuple2$bsautos__59[0]){ - case "Tuple2": - return Tuple2$bsautos__59[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var autos__61=function(){ - switch(Tuple2$bsautos__59[0]){ - case "Tuple2": - return Tuple2$bsautos__59[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",bs_60,combine_3(autos__61)];}();});} - function pure_4(f_68){ - return Automaton_0(function(x_69){ - return ["Tuple2",f_68(x_69),pure_4(f_68)];});} - function init_5(s_70){ - return function(step_71){ - return Automaton_0(function(a_72){ - return function(){ - var s__73=step_71(a_72)(s_70); - return ["Tuple2",s__73,init_5(s__73)(step_71)];}();});};} - function init__6(s_74){ - return function(step_75){ - return Automaton_0(function(a_76){ - return function(){ - var Tuple2$bs__77=step_75(a_76)(s_74); - var b_78=function(){ - switch(Tuple2$bs__77[0]){ - case "Tuple2": - return Tuple2$bs__77[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var s__79=function(){ - switch(Tuple2$bs__77[0]){ - case "Tuple2": - return Tuple2$bs__77[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",b_78,init__6(s__79)(step_75)];}();});};} - function vecSub_11(Tuple2$x1y1_86){ - return function(Tuple2$x2y2_87){ - return function(){ - switch(Tuple2$x1y1_86[0]){ - case "Tuple2": - return function(){ - switch(Tuple2$x2y2_87[0]){ - case "Tuple2": - return ["Tuple2",(Tuple2$x1y1_86[1]-Tuple2$x2y2_87[1]),(Tuple2$x1y1_86[2]-Tuple2$x2y2_87[2])]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function stepDrag_12(Tuple2$presspos_92){ - return function(Tuple2$dsform_93){ - return function(){ - switch(Tuple2$presspos_92[0]){ - case "Tuple2": - return function(){ - switch(Tuple2$dsform_93[0]){ - case "Tuple2": - return function(){ - function wrap_98(ds__99){ - return ["Tuple2",Tuple2$dsform_93[2],["Tuple2",ds__99,Tuple2$dsform_93[2]]];} - return function(){ - switch(Tuple2$dsform_93[1][0]){ - case "DragFrom": - return (Tuple2$presspos_92[1]?["Tuple2",uncurry(move)(vecSub_11(Tuple2$presspos_92[2])(Tuple2$dsform_93[1][1]))(Tuple2$dsform_93[2]),["Tuple2",DragFrom_10(Tuple2$dsform_93[1][1]),Tuple2$dsform_93[2]]]:function(){ - var form__101=uncurry(move)(vecSub_11(Tuple2$presspos_92[2])(Tuple2$dsform_93[1][1]))(Tuple2$dsform_93[2]); - return ["Tuple2",form__101,["Tuple2",Listen_8,form__101]];}()); - case "Ignore": - return wrap_98((Tuple2$presspos_92[1]?Ignore_9:Listen_8)); - case "Listen": - return wrap_98((not(Tuple2$presspos_92[1])?Listen_8:(isWithin(Tuple2$presspos_92[2])(Tuple2$dsform_93[2])?DragFrom_10(Tuple2$presspos_92[2]):Ignore_9))); - } - throw new Error("Non-exhaustive pattern match in case");}();}(); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function draggable_13(form_102){ - return init__6(["Tuple2",Listen_8,form_102])(stepDrag_12);} - return {$op : {'>>>' : $op['>>>'], '<<<' : $op['<<<'], '^>>' : $op['^>>'], '>>^' : $op['>>^'], '^<<' : $op['^<<'], '<<^' : $op['<<^']}, - run:run_1, - step:step_2, - combine:combine_3, - pure:pure_4, - init:init_5, - init$:init__6, - count:count_7, - draggable:draggable_13};}(); -Elm.main=function(){ - return Elm.Automaton.main;}; -} catch (e) { -Elm.main=function() { -var msg = ('<br/><h2>Your browser may not be supported. Are you using a modern browser?</h2>' + '<br/><span style="color:grey">Runtime Error in Automaton module:<br/>' + e + '</span>'); -document.body.innerHTML = Elm.Text.monospace(msg);throw e;};}}()); \ No newline at end of file diff --git a/core-js/Char.js b/core-js/Char.js deleted file mode 100644 index b313c3c..0000000 --- a/core-js/Char.js +++ /dev/null @@ -1,64 +0,0 @@ -/*! Char !*/ - -/*[Classification]*/ - -/** isUpper : Char -> Bool - Selects upper case letters. -**/ -/** isLower : Char -> Bool - Selects lower case letters. -**/ -/** isDigit : Char -> Bool - Selects ASCII digits (0..9). -**/ -/** isOctDigit : Char -> Bool - Selects ASCII octal digits (0..7). -**/ -/** isHexDigit : Char -> Bool - Selects ASCII hexadecimal digits (0..9a..fA..F). -**/ - -/*[Conversion]*/ - -/** toUpper : Char -> Char - Convert to upper case. -**/ -/** toLower : Char -> Char - Convert to lower case. -**/ -/** toLocaleUpper : Char -> Char - Convert to upper case, according to any locale-specific case mappings. -**/ -/** toLocaleLower : Char -> Char - Convert to lower case, according to any locale-specific case mappings. -**/ -/** toCode : Char -> Int - Convert to unicode. -**/ -/** fromCode : Int -> Char - Convert from unicode. -**/ - -Elm.Char = function() { - function isBetween(lo,hi) { return function(chr) { - var c = chr.charCodeAt(0); - return lo <= c && c <= hi; - }; - } - var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0)); - var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0)); - var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0)); - - return {fromCode : function(c) { return String.fromCharCode(c); }, - toCode : function(c) { return c.charCodeAt(0); }, - toUpper : function(c) { return c.toUpperCase(); }, - toLower : function(c) { return c.toLowerCase(); }, - toLocaleUpper : function(c) { return c.toLocaleUpperCase(); }, - toLocaleLower : function(c) { return c.toLocaleLowerCase(); }, - isLower : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)), - isUpper : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)), - isDigit : isDigit, - isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)), - isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); } - }; -}(); diff --git a/core-js/Date.js b/core-js/Date.js deleted file mode 100644 index c9c16e6..0000000 --- a/core-js/Date.js +++ /dev/null @@ -1,32 +0,0 @@ - -Elm.Date = function() { - - function dateNow() { return new window.Date; } - function readDate(str) { - var d = new window.Date(Elm.JavaScript.castStringToJSString(str)); - if (isNaN(d.getTime())) return ["Nothing"]; - return ["Just",d]; - } - - var dayTable = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - var monthTable = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - - return { - read : readDate, - year : function(d) { return d.getFullYear(); }, - month : function(d) { return [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(); }, - dayOfWeek : function(d) { return [dayTable[d.getDay()]]; }, - toTime : function(d) { return d.getTime(); }, - Mon : ["Mon"], Tue : ["Tue"], Wed : ["Wed"], - Thu : ["Thu"], Fri : ["Fri"], Sat : ["Sat"], Sun : ["Sun"], - Jan : ["Jan"], Feb : ["Feb"], Mar : ["Mar"], Apr : ["Apr"], - May : ["May"], Jun : ["Jun"], Jul : ["Jul"], Aug : ["Aug"], - Sep : ["Sep"], Oct : ["Oct"], Nov : ["Nov"], Dec : ["Dec"] - }; - -}(); diff --git a/core-js/Dict.js b/core-js/Dict.js deleted file mode 100644 index c7a234c..0000000 --- a/core-js/Dict.js +++ /dev/null @@ -1,485 +0,0 @@ - -Elm.Dict=function(){ - var compare = Elm.Prelude.compare; - var uncurry = Elm.Prelude.uncurry; - var Nothing = Elm.Prelude.Nothing; - var Just = Elm.Prelude.Just; - var not = Elm.Prelude.not; - var eq = Elm.Prelude.eq; - var isJust=Elm.Maybe.isJust; - var Red_0=['Red']; - var Black_1=['Black']; - function RBNode_2(a1){ - return function(a2){ - return function(a3){ - return function(a4){ - return function(a5){ - return ['RBNode',a1,a2,a3,a4,a5];};};};};} - var RBEmpty_3=['RBEmpty']; - function min_6(t_42){ - return function(){ - switch(t_42[0]){ - case 'RBEmpty': - throw '(min RBEmpty) is not defined'; - case 'RBNode': - switch(t_42[4][0]){ - case 'RBEmpty': - return ['Tuple2',t_42[2],t_42[3]]; - } - return min_6(t_42[4]); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function lookup_7(k_46){ - return function(t_47){ - return function(){ - switch(t_47[0]){ - case 'RBEmpty': - return Nothing; - case 'RBNode': - return function(){ - var case12=compare(k_46)(t_47[2]); - switch(case12[0]){ - case 'EQ': - return Just(t_47[3]); - case 'GT': - return lookup_7(k_46)(t_47[5]); - case 'LT': - return lookup_7(k_46)(t_47[4]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function findWithDefault_8(base_52){ - return function(k_53){ - return function(t_54){ - return function(){ - switch(t_54[0]){ - case 'RBEmpty': - return base_52; - case 'RBNode': - return function(){ - var case19=compare(k_53)(t_54[2]); - switch(case19[0]){ - case 'EQ': - return t_54[3]; - case 'GT': - return findWithDefault_8(base_52)(k_53)(t_54[5]); - case 'LT': - return findWithDefault_8(base_52)(k_53)(t_54[4]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function member_9(k_59){ - return function(t_60){ - return isJust(lookup_7(k_59)(t_60));};} - function rotateLeft_10(t_61){ - return function(){ - switch(t_61[0]){ - case 'RBNode': - switch(t_61[5][0]){ - case 'RBNode': - return RBNode_2(t_61[1])(t_61[5][2])(t_61[5][3])(RBNode_2(Red_0)(t_61[2])(t_61[3])(t_61[4])(t_61[5][4]))(t_61[5][5]); - }break; - } - throw 'rotateLeft of a node without enough children';}();} - function rotateRight_11(t_71){ - return function(){ - switch(t_71[0]){ - case 'RBNode': - switch(t_71[4][0]){ - case 'RBNode': - return RBNode_2(t_71[1])(t_71[4][2])(t_71[4][3])(t_71[4][4])(RBNode_2(Red_0)(t_71[2])(t_71[3])(t_71[4][5])(t_71[5])); - }break; - } - throw 'rotateRight of a node without enough children';}();} - function rotateLeftIfNeeded_12(t_81){ - return function(){ - switch(t_81[0]){ - case 'RBNode': - switch(t_81[5][0]){ - case 'RBNode': - switch(t_81[5][1][0]){ - case 'Red': - return rotateLeft_10(t_81); - }break; - }break; - } - return t_81;}();} - function rotateRightIfNeeded_13(t_82){ - return function(){ - switch(t_82[0]){ - case 'RBNode': - switch(t_82[4][0]){ - case 'RBNode': - switch(t_82[4][1][0]){ - case 'Red': - switch(t_82[4][4][0]){ - case 'RBNode': - switch(t_82[4][4][1][0]){ - case 'Red': - return rotateRight_11(t_82); - }break; - }break; - }break; - }break; - } - return t_82;}();} - function otherColor_14(c_83){ - return function(){ - switch(c_83[0]){ - case 'Black': - return Red_0; - case 'Red': - return Black_1; - } - throw new Error("Non-exhaustive pattern match in case");}();} - function color_flip_15(t_84){ - return function(){ - switch(t_84[0]){ - case 'RBNode': - switch(t_84[4][0]){ - case 'RBNode': - switch(t_84[5][0]){ - case 'RBNode': - return RBNode_2(otherColor_14(t_84[1]))(t_84[2])(t_84[3])(RBNode_2(otherColor_14(t_84[4][1]))(t_84[4][2])(t_84[4][3])(t_84[4][4])(t_84[4][5]))(RBNode_2(otherColor_14(t_84[5][1]))(t_84[5][2])(t_84[5][3])(t_84[5][4])(t_84[5][5])); - }break; - }break; - } - throw 'color_flip called on a RBEmpty or RBNode with a RBEmpty child';}();} - function color_flipIfNeeded_16(t_98){ - return function(){ - switch(t_98[0]){ - case 'RBNode': - switch(t_98[4][0]){ - case 'RBNode': - switch(t_98[4][1][0]){ - case 'Red': - switch(t_98[5][0]){ - case 'RBNode': - switch(t_98[5][1][0]){ - case 'Red': - return color_flip_15(t_98); - }break; - }break; - }break; - }break; - } - return t_98;}();} - function fixUp_17(t_99){ - return color_flipIfNeeded_16(rotateRightIfNeeded_13(rotateLeftIfNeeded_12(t_99)));} - function ensureBlackRoot_18(t_100){ - return function(){ - switch(t_100[0]){ - case 'RBNode': - switch(t_100[1][0]){ - case 'Red': - return RBNode_2(Black_1)(t_100[2])(t_100[3])(t_100[4])(t_100[5]); - }break; - } - return t_100;}();} - function insert_19(k_105){ - return function(v_106){ - return function(t_107){ - return function(){ - function ins_108(t_109){ - return function(){ - switch(t_109[0]){ - case 'RBEmpty': - return RBNode_2(Red_0)(k_105)(v_106)(RBEmpty_3)(RBEmpty_3); - case 'RBNode': - return function(){ - var h_115=function(){ - var case114=compare(k_105)(t_109[2]); - switch(case114[0]){ - case 'EQ': - return RBNode_2(t_109[1])(t_109[2])(v_106)(t_109[4])(t_109[5]); - case 'GT': - return RBNode_2(t_109[1])(t_109[2])(t_109[3])(t_109[4])(ins_108(t_109[5])); - case 'LT': - return RBNode_2(t_109[1])(t_109[2])(t_109[3])(ins_108(t_109[4]))(t_109[5]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - return fixUp_17(h_115);}(); - } - throw new Error("Non-exhaustive pattern match in case");}();} - return ensureBlackRoot_18(ins_108(t_107));}();};};} - function singleton_20(k_116){ - return function(v_117){ - return insert_19(k_116)(v_117)(RBEmpty_3);};} - function isRed_21(t_118){ - return function(){ - switch(t_118[0]){ - case 'RBNode': - switch(t_118[1][0]){ - case 'Red': - return true; - }break; - } - return false;}();} - function isRedLeft_22(t_119){ - return function(){ - switch(t_119[0]){ - case 'RBNode': - switch(t_119[4][0]){ - case 'RBNode': - switch(t_119[4][1][0]){ - case 'Red': - return true; - }break; - }break; - } - return false;}();} - function isRedLeftLeft_23(t_120){ - return function(){ - switch(t_120[0]){ - case 'RBNode': - switch(t_120[4][0]){ - case 'RBNode': - switch(t_120[4][4][0]){ - case 'RBNode': - switch(t_120[4][4][1][0]){ - case 'Red': - return true; - }break; - }break; - }break; - } - return false;}();} - function isRedRight_24(t_121){ - return function(){ - switch(t_121[0]){ - case 'RBNode': - switch(t_121[5][0]){ - case 'RBNode': - switch(t_121[5][1][0]){ - case 'Red': - return true; - }break; - }break; - } - return false;}();} - function isRedRightLeft_25(t_122){ - return function(){ - switch(t_122[0]){ - case 'RBNode': - switch(t_122[5][0]){ - case 'RBNode': - switch(t_122[5][4][0]){ - case 'RBNode': - switch(t_122[5][4][1][0]){ - case 'Red': - return true; - }break; - }break; - }break; - } - return false;}();} - function moveRedLeft_26(t_123){ - return function(){ - var t__124=color_flip_15(t_123); - return function(){ - switch(t__124[0]){ - case 'RBNode': - return function(){ - switch(t__124[5][0]){ - case 'RBNode': - switch(t__124[5][4][0]){ - case 'RBNode': - switch(t__124[5][4][1][0]){ - case 'Red': - return color_flip_15(rotateLeft_10(RBNode_2(t__124[1])(t__124[2])(t__124[3])(t__124[4])(rotateRight_11(t__124[5])))); - }break; - }break; - } - return t__124;}(); - } - return t__124;}();}();} - function moveRedRight_27(t_130){ - return function(){ - var t__131=color_flip_15(t_130); - return (isRedLeftLeft_23(t__131)?color_flip_15(rotateRight_11(t__131)):t__131);}();} - function moveRedLeftIfNeeded_28(t_132){ - return ((not(isRedLeft_22(t_132))&¬(isRedLeftLeft_23(t_132)))?moveRedLeft_26(t_132):t_132);} - function moveRedRightIfNeeded_29(t_133){ - return ((not(isRedRight_24(t_133))&¬(isRedRightLeft_25(t_133)))?moveRedRight_27(t_133):t_133);} - function deleteMin_30(t_134){ - return function(){ - function del_135(t_136){ - return function(){ - switch(t_136[0]){ - case 'RBNode': - switch(t_136[4][0]){ - case 'RBEmpty': - return RBEmpty_3; - }break; - } - return function(){ - var case198=moveRedLeftIfNeeded_28(t_136); - switch(case198[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return fixUp_17(RBNode_2(case198[1])(case198[2])(case198[3])(del_135(case198[4]))(case198[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();}();} - return ensureBlackRoot_18(del_135(t_134));}();} - function remove_31(k_142){ - return function(t_143){ - return function(){ - function eq_and_noRightNode_144(t_150){ - return function(){ - switch(t_150[0]){ - case 'RBNode': - switch(t_150[5][0]){ - case 'RBEmpty': - return eq(k_142,t_150[2]); - }break; - } - return false;}();} - function eq_145(t_152){ - return function(){ - switch(t_152[0]){ - case 'RBNode': - return eq(k_142,t_152[2]); - } - return false;}();} - function delLT_146(t_154){ - return function(){ - var case216=moveRedLeftIfNeeded_28(t_154); - switch(case216[0]){ - case 'RBEmpty': - throw 'delLT on RBEmpty'; - case 'RBNode': - return fixUp_17(RBNode_2(case216[1])(case216[2])(case216[3])(del_149(case216[4]))(case216[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function delEQ_147(t_160){ - return function(){ - switch(t_160[0]){ - case 'RBEmpty': - throw 'delEQ called on a RBEmpty'; - case 'RBNode': - return function(){ - var Tuple2$k_v__164=min_6(t_160[5]); - var k__165=function(){ - switch(Tuple2$k_v__164[0]){ - case 'Tuple2': - return Tuple2$k_v__164[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var v__166=function(){ - switch(Tuple2$k_v__164[0]){ - case 'Tuple2': - return Tuple2$k_v__164[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return fixUp_17(RBNode_2(t_160[1])(k__165)(v__166)(t_160[4])(deleteMin_30(t_160[5])));}(); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function delGT_148(t_171){ - return function(){ - switch(t_171[0]){ - case 'RBEmpty': - throw 'delGT called on a RBEmpty'; - case 'RBNode': - return fixUp_17(RBNode_2(t_171[1])(t_171[2])(t_171[3])(t_171[4])(del_149(t_171[5]))); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function del_149(t_177){ - return function(){ - switch(t_177[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return ((compare(k_142)(t_177[2])[0] === 'LT')?delLT_146(t_177):function(){ - var u_179=(isRedLeft_22(t_177)?rotateRight_11(t_177):t_177); - return (eq_and_noRightNode_144(u_179)?u_179[4]:function(){ - var t__180=moveRedRightIfNeeded_29(t_177); - return (eq_145(t__180)?delEQ_147(t__180):delGT_148(t__180));}());}()); - } - throw new Error("Non-exhaustive pattern match in case");}();} - return (member_9(k_142)(t_143)?ensureBlackRoot_18(del_149(t_143)):t_143);}();};} - function map_32(f_181){ - return function(t_182){ - return function(){ - switch(t_182[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return RBNode_2(t_182[1])(t_182[2])(f_181(t_182[3]))(map_32(f_181)(t_182[4]))(map_32(f_181)(t_182[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function foldl_33(f_188){ - return function(acc_189){ - return function(t_190){ - return function(){ - switch(t_190[0]){ - case 'RBEmpty': - return acc_189; - case 'RBNode': - return foldl_33(f_188)(f_188(t_190[2])(t_190[3])(foldl_33(f_188)(acc_189)(t_190[4])))(t_190[5]); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function foldr_34(f_195){ - return function(acc_196){ - return function(t_197){ - return function(){ - switch(t_197[0]){ - case 'RBEmpty': - return acc_196; - case 'RBNode': - return foldr_34(f_195)(f_195(t_197[2])(t_197[3])(foldr_34(f_195)(acc_196)(t_197[5])))(t_197[4]); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function union_35(t1_202){ - return function(t2_203){ - return foldl_33(insert_19)(t2_203)(t1_202);};} - function intersect_36(t1_204){ - return function(t2_205){ - return foldl_33(function(k_206){ - return function(v_207){ - return function(t_208){ - return (member_9(k_206)(t2_205)?insert_19(k_206)(v_207)(t_208):t_208);};};})(empty_4)(t1_204);};} - function diff_37(t1_209){ - return function(t2_210){ - return foldl_33(function(k_211){ - return function(v_212){ - return function(t_213){ - return remove_31(k_211)(t_213);};};})(t1_209)(t2_210);};} - function keys_38(t_214){ - return foldr_34(function(k_215){ - return function(v_216){ - return function(acc_217){ - return ['Cons',k_215,acc_217];};};})(['Nil'])(t_214);} - function values_39(t_218){ - return foldr_34(function(k_219){ - return function(v_220){ - return function(acc_221){ - return ['Cons',v_220,acc_221];};};})(['Nil'])(t_218);} - function toList_40(t_222){ - return foldr_34(function(k_223){ - return function(v_224){ - return function(acc_225){ - return ['Cons',['Tuple2',k_223,v_224],acc_225];};};})(['Nil'])(t_222);} - function fromList_41(assocs_226){ - return Elm.List.foldl(uncurry(insert_19))(empty_4)(assocs_226);} - var empty_4=RBEmpty_3; - return {$op : {}, - empty:empty_4, - lookup:lookup_7, - findWithDefault:findWithDefault_8, - member:member_9, - insert:insert_19, - singleton:singleton_20, - remove:remove_31, - map:map_32, - foldl:foldl_33, - foldr:foldr_34, - union:union_35, - intersect:intersect_36, - diff:diff_37, - keys:keys_38, - values:values_39, - toList:toList_40, - fromList:fromList_41};}(); diff --git a/core-js/Either.js b/core-js/Either.js deleted file mode 100644 index 9c5d71c..0000000 --- a/core-js/Either.js +++ /dev/null @@ -1,75 +0,0 @@ -/*! Either -!*/ - - -Elm.Either = function() { - /*[Definition]*/ - - /** data Either a b = Left a | Right b - Represents any data that can take two different types. - - This can also be used for error handling (`Either String a`) where - error messages are stored on the left, and the correct values - ("right" values) are stored on the right. - **/ - function Left(a1) { return ['Left',a1]; } - function Right(a1){ return ['Right',a1]; } - - /*[Basics]*/ - - /** either : (a -> c) -> (b -> c) -> Either a b -> c - Apply the first function to a `Left` and the second function to a `Right`. - This allows the extraction of a value from an `Either`. - **/ - function either(f){ return function(g){ return function(e){ - switch(e[0]){ - case 'Left': return f(e[1]); - case 'Right': return g(e[1]); - } - };};} - - /** isLeft : Either a b -> Bool - True if the value is a `Left`. - **/ - function isLeft(e) { return e[0] == 'Left'; } - - /** isRight : Either a b -> Bool - True if the value is a `Right`. - **/ - function isRight(e) { return e[0] == 'Right'; } - - /*[With Lists]*/ - - function get(es) { return Elm.List.map(function(x){return x[1];})(es); } - - /** lefts : [Either a b] -> [a] - Keep only the values held in `Left` values. - **/ - function lefts(es) { return get(Elm.List.filter(isLeft)(es)); } - - /** rights : [Either a b] -> [a] - Keep only the values held in `Right` values. - **/ - function rights(es) { return get(Elm.List.filter(isRight)(es)); } - - /** partition : [Either a b] -> ([a],[b]) - Split into two lists, lefts on the left and rights on the right. - So we have the equivalence: - - partition es == (lefts es, rights es) - **/ - function partition(es) { - var lrs = Elm.List.partition(isLeft)(es); - lrs[1] = get(lrs[1]); - lrs[2] = get(lrs[2]); - return lrs; - } - return {Left:Left, - Right:Right, - either:either, - isLeft:isLeft, - isRight:isRight, - lefts:lefts, - rights:rights, - partition:partition}; -}(); diff --git a/core-js/Graphics/Collage.js b/core-js/Graphics/Collage.js deleted file mode 100644 index 0e7a0d8..0000000 --- a/core-js/Graphics/Collage.js +++ /dev/null @@ -1,317 +0,0 @@ - -var Collage = function() { - -var JS = Elm.JavaScript; - -function tracePoints(ctx,points) { - var i = points.length - 1; - if (i <= 0) return; - ctx.moveTo(points[i][1], points[i][2]); - while (i--) { ctx.lineTo(points[i][1], points[i][2]); } -} - -function solid(ctx,color,points) { - tracePoints(ctx,points); - ctx.strokeStyle = Elm.Color.extract(color); - ctx.stroke(); -}; - -function filled(ctx,color,points) { - tracePoints(ctx,points); - ctx.fillStyle = Elm.Color.extract(color); - ctx.fill(); -} - -function textured(redo,ctx,src,points) { - var img = new Image(); - img.src = JS.castStringToJSString(src); - img.onload = redo; - - tracePoints(ctx,points); - ctx.fillStyle = ctx.createPattern(img,'repeat'); - ctx.fill(); -} - -function customLine(pattern,ctx,color,points) { - if (pattern.length === 0) { pattern = [8,4]; } - customLineHelp(ctx, pattern, points); - ctx.strokeStyle = Elm.Color.extract(color); - ctx.stroke(); -}; - -var customLineHelp = function(ctx, pattern, points) { - var i = points.length - 1; - if (i <= 0) return; - var x0 = points[i][1], y0 = points[i][2]; - var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0; - var pindex = 0, plen = pattern.length; - var draw = true, segmentLength = pattern[0]; - ctx.moveTo(x0,y0); - while (i--) { - x1 = points[i][1]; y1 = points[i][2]; - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - while (segmentLength <= remaining) { - x0 += dx * segmentLength / remaining; - y0 += dy * segmentLength / remaining; - ctx[draw ? 'lineTo' : 'moveTo'](x0, y0); - // update starting position - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - // update pattern - draw = !draw; - pindex = (pindex + 1) % plen; - segmentLength = pattern[pindex]; - } - if (remaining > 0) { - ctx[draw ? 'lineTo' : 'moveTo'](x1, y1); - segmentLength -= remaining; - } - x0 = x1; y0 = y1; - } -}; - -function drawLine(ctx,form) { - var points = form[3][1]; - switch(form[1][0]) { - case "Solid" : return solid(ctx,form[2],points); - case "Dotted": return customLine([3,3],ctx,form[2],points); - case "Dashed": return customLine([8,4],ctx,form[2],points); - case "Custom": return customLine(form[1][1],ctx,form[2],points); - } -}; - -function drawShape(redo,ctx,shapeStyle,color,points) { - switch(shapeStyle[0]) { - case "Filled": return filled(ctx,color,points); - case "Outlined": return solid(ctx,color,points); - case "Textured": return textured(redo,ctx,shapeStyle[1],points); - case "CustomOutline": - return customLine(shapeStyle[1],ctx,color,points); - } -}; - -function drawImage(redo,ctx,w,h,src) { - var img = new Image(); - img.onload = redo; - img.src = JS.castStringToJSString(src); - ctx.drawImage(img,-w/2,-h/2,w,h); -} - -function renderForm(redo,ctx,theta,scale,x,y,form) { - ctx.save(); - if (x !== 0 || y !== 0) ctx.translate(x,y); - if (theta !== ~~theta) ctx.rotate(2*Math.PI*theta); - if (scale !== 1) ctx.scale(scale,scale); - ctx.beginPath(); - switch(form[0]) { - case "FLine": drawLine(ctx,form); break; - case "FShape": drawShape(redo,ctx,form[1],form[2],form[3][1]); break; - case "FImage": drawImage(redo,ctx,form[1],form[2],form[3]); break; - } - ctx.restore(); -}; - -function renderForms(redo,ctx,w,h,forms) { - ctx.clearRect(0,0,w,h); - for (var i = forms.length; i--; ) { - var f = forms[i]; - renderForm(redo,ctx,f[1],f[2],f[3][1],f[3][2],f[4]); - } -} - -function collageForms(w,h,forms) { - var canvas = Render.newElement('canvas'); - w = ~~w; - h = ~~h; - canvas.style.width = w + 'px'; - canvas.style.height = h + 'px'; - canvas.style.display = "block"; - canvas.width = w; - canvas.height = h; - if (canvas.getContext) { - var ctx = canvas.getContext('2d'); - function redo() { renderForms(this,ctx,w,h,forms); } - renderForms(redo,ctx,w,h,forms); - return canvas; - } - canvas.innerHTML = "Your browser does not support the canvas element."; - return canvas; -}; - -function applyTransforms(theta,scale,x,y,w,h,e) { - var t = "translate(" + (x - w / 2) + "px,"+ (y - h / 2) + "px)"; - var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)"; - var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")"; - var transforms = t + " " + s + " " + r; - e.style.transform = transforms; - e.style.msTransform = transforms; - e.style.MozTransform = transforms; - e.style.webkitTransform = transforms; - e.style.OTransform = transforms; -} - -function collageElement(w,h,theta,scale,x,y,elem) { - var e = Render.render(elem); - applyTransforms(theta,scale,x,y,elem[3],elem[4],e); - var div = Render.newElement('div'); - Render.addTo(div,e); - div.style.width = (~~w) + "px"; - div.style.height = (~~h) + "px"; - div.style.overflow = "hidden"; - return div; -} - -function collage(w,h,formss) { - if (formss.length === 0) { return collageForms(w,h,[]); } - var elems = new Array(formss.length); - for (var i = formss.length; i--; ) { - var f = formss[i]; - if (typeof f[0] === "string") { - elems[i] = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]); - } else { - elems[i] = collageForms(w,h,f); - } - } - if (formss.length === 1) { return elems[0]; } - return Render.flowWith(Render.goIn,function(x){return x},elems); -} - -function updateFormSet(node,currSet,nextSet) { - if (Value.eq(nextSet,currSet)) return; - var w = node.style.width.slice(0,-2) - 0; - var h = node.style.height.slice(0,-2) - 0; - if (typeof nextSet[0] === "object") { - if (typeof currSet[0] === "object") { - if (node.getContext) { - var ctx = node.getContext('2d'); - function redo() { renderForms(this,ctx,w,h,nextSet); } - return renderForms(redo,ctx,w,h,nextSet); - } - } - var newNode = collageForms(w,h,nextSet); - newNode.style.position = 'absolute'; - return node.parentNode.replaceChild(newNode,node); - } - node.style.width = (~~w) + "px"; - node.style.height = (~~h) + "px"; - var f = nextSet; - var next = nextSet[4][1]; - Render.update(node.firstChild, currSet[4][1], next); - applyTransforms(f[1],f[2],f[3][1],f[3][2],next[3],next[4],node.firstChild); -} - -// assumes that the form sets are the same length. -function updateCollage(node,currs,nexts) { - if (nexts.length === 1) { - return updateFormSet(node,currs[0],nexts[0]); - } - var kids = node.childNodes; - var len = kids.length; - for (var i = len; i--; ) { - updateFormSet(kids[len-i-1], currs[i], nexts[i]); - } -} - -function style(clr,n,list) { - return ["Tuple2", - '<span style="font-size:100%;color:' + clr + ';">' + n + '</span>', - list]; -} - -function insideForm(point) { return function(form) { - if (!inBoundsOf(point[1],point[2],form)) return false; - var hw, hh; - switch (form[4][0]) { - case "FShape": return insideShape(point,form[1],form[2],form[3],form[4][3][1]); - case "FLine": return false; - case "FImage": - hw = form[4][1] / 2; - hh = form[4][2] / 2; - break; - case "FElement": - hw = form[4][1][3] / 2; - hh = form[4][1][4] / 2; - break; - } - return insideShape(point,form[1],form[2],form[3], - [ [null, hw, hh], - [null,-hw, hh], - [null,-hw,-hh], - [null, hw,-hh], - [null, hw, hh] ]); - }; -} - -function inBoundsOf(px,py,form) { - if (form.length < 6) { - var fx = form[3][1], fy = form[3][2]; - var radiusSquared = 0; - var scale = form[2]; - switch (form[4][0]) { - case "FShape": - var points = form[4][3][1]; - for (var i = points.length; --i; ) { - var p = points[i]; - radiusSquared = Math.max(radiusSquared, p[1]*p[1] + p[2]*p[2]); - } - radiusSquared *= scale * scale; - break; - case "FLine": - break; - case "FImage": - var x = scale * form[4][1] / 2; - var y = scale * form[4][2] / 2; - radiusSquared = x*x + y*y; - break; - case "FElement": - var x = scale * form[4][1][3] / 2; - var y = scale * form[4][1][4] / 2; - radiusSquared = x*x + y*y; - break; - } - form.push(function(px,py) { - var dx = px - fx; - var dy = py - fy; - return dx*dx + dy*dy < radiusSquared + 1; - }); - } - return form[5](px,py); -} - -function insideShape(point,theta,scale,pos,points) { - var counter = 0; - var list = ["Nil"]; - var p1,p2; - - var x = (point[1] - pos[1]) / scale; - var y = (point[2] - pos[2]) / scale; - if (theta !== 0) { - var t = -2 * Math.PI * theta; - var nx = x * Math.cos(t) - y * Math.sin(t); - y = x * Math.sin(t) + y * Math.cos(t); - x = nx; - } - - if (points.length === 0) { return false; } - p1 = points[0]; - for (var i = points.length - 1; i--; ) { - p2 = points[i]; - var p1x = p1[1], p1y = p1[2], p2x = p2[1], p2y = p2[2]; - - if (p1y < p2y) {var ymin=p1y, ymax=p2y;} else {var ymin=p2y, ymax=p1y;} - if (p1x < p2x) {var xmin=p1x, xmax=p2x;} else {var xmin=p2x, xmax=p1x;} - - if (ymin < y && y <= ymax && x <= xmax) { - if (x <= xmin || x <= ((y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x)) { - ++counter; - } - } - p1 = p2; - } - return (counter % 2) === 1; -} - -return {collage:collage, updateCollage:updateCollage, insideForm:insideForm}; - -}(); \ No newline at end of file diff --git a/core-js/Graphics/Color.js b/core-js/Graphics/Color.js deleted file mode 100644 index 0ee4d94..0000000 --- a/core-js/Graphics/Color.js +++ /dev/null @@ -1,86 +0,0 @@ -Elm.Color = function() { - -function Color_0(a1) { - return function(a2) { - return function(a3) { - return function(a4) { - return["Color", a1, a2, a3, a4] - } - } - } -} -var rgba_1 = Color_0; -var red_3 = ["Color",255,0,0,1]; -var green_4 = ["Color",0,255,0,1]; -var blue_5 = ["Color",0,0,255,1]; -var yellow_6 = ["Color",255,255,0,1]; -var cyan_7 = ["Color",0,255,255,1]; -var magenta_8 = ["Color",255,0,255,1]; -var black_9 = ["Color",0,0,0,1]; -var white_10 = ["Color",255,255,255,1]; -var gray_11 = ["Color",128,128,128,1]; -var grey_12 = ["Color",128,128,128,1]; -function rgb_2(r_13) { - return function(g_14) { - return function(b_15) { - return ["Color",r_13,g_14,b_15,1] - } - } -} -function extract(c) { - if (c[4] === 1) { return 'rgb(' + c[1] + ',' + c[2] + ',' + c[3] + ')'; } - return 'rgba(' + c[1] + ',' + c[2] + ',' + c[3] + ',' + c[4] + ')'; -} -function complement(rgb) { - var hsv = toHSV(rgb); - hsv.hue = (hsv.hue + 180) % 360; - return toRGB(hsv); -} - -function hsva(h) { return function(s) { return function(v) { return function(a) { - var clr = toRGB({hue:h, saturation:s, value:v}); - clr[4] = a; - return clr; - }; }; }; -} - -function hsv(h) { return function(s) { return function(v) { - return toRGB({hue:h, saturation:s, value:v}); }; }; } - -function toHSV(rgb) { - var hsv = {}; - var r = rgb[1] / 255.0, g = rgb[2] / 255.0, b = rgb[3] / 255.0; - var M = Math.max(r,g,b); - var m = Math.min(r,g,b); - var c = M - m; - - var h = 0; - if (c === 0) { h = 0; } - else if (M === r) { h = ((g - b) / c) % 6; } - else if (M === g) { h = ((b - r) / c) + 2; } - else if (M === b) { h = ((r - g) / c) + 4; } - h *= 60; - - return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) }; -} - -function between(lo,hi,x) { return lo <= x && x < hi; } -function norm(n) { return Math.round(n*255); } - -function toRGB(hsv) { - var c = hsv.value * hsv.saturation; - var hue = hsv.hue / 60; - var x = c * (1 - Math.abs((hue % 2) - 1)); - var r = 0, g = 0, b = 0; - if (between(0,1,hue)) { r = c; g = x; b = 0; } - else if (between(1,2,hue)) { r = x; g = c; b = 0; } - else if (between(2,3,hue)) { r = 0; g = c; b = x; } - else if (between(3,4,hue)) { r = 0; g = x; b = c; } - else if (between(4,5,hue)) { r = x; g = 0; b = c; } - else if (between(5,6,hue)) { r = c; g = 0; b = x; } - - var m = hsv.value - c; - return ["Color", norm(r+m), norm(g+m), norm(b+m), 1 ]; -} - return{rgba:rgba_1, rgb:rgb_2, hsva:hsva, hsv:hsv, red:red_3, green:green_4, blue:blue_5, yellow:yellow_6, cyan:cyan_7, magenta:magenta_8, black:black_9, white:white_10, gray:gray_11, grey:grey_12,complement:complement,extract:extract} -}(); \ No newline at end of file diff --git a/core-js/Graphics/Element.js b/core-js/Graphics/Element.js deleted file mode 100644 index 1b103fe..0000000 --- a/core-js/Graphics/Element.js +++ /dev/null @@ -1,517 +0,0 @@ -Elm.Graphics = function() { - for (this['i'] in Elm.List) { - eval('var ' + this['i'] + ' = Elm.List[this.i];'); - } - var JS = Elm.JavaScript; - var DLeft_0 = ["DLeft"]; - var DRight_1 = ["DRight"]; - var DUp_2 = ["DUp"]; - var DDown_3 = ["DDown"]; - var DIn_4 = ["DIn"]; - var DOut_5 = ["DOut"]; - function Absolute_12(a1) { - return["Absolute", a1] - } - function Relative_13(a1) { - return["Relative", a1] - } - var Near_14 = ["Near"]; - var Mid_15 = ["Mid"]; - var Far_16 = ["Far"]; - function Position_17(a1) { - return function(a2) { - return["Position", a1, a2] - } - } - function PositionTL_18(a1) { - return function(a2) { - return["PositionTL", a1, a2] - } - } - function PositionTR_19(a1) { - return function(a2) { - return["PositionTR", a1, a2] - } - } - function PositionBL_20(a1) { - return function(a2) { - return["PositionBL", a1, a2] - } - } - function PositionBR_21(a1) { - return function(a2) { - return["PositionBR", a1, a2] - } - } - function Element_37(id,e,w,h,o,c,l) { - return["Element", id, e, w, h, o, c, l ] - } - function EText_39(a1) { - return function(a2) { - return["EText", a1, a2] - } - } - function EImage_40(a1) { - return["EImage", JS.castStringToJSString(a1)] - } - function EVideo_41(a1) { - return["EVideo", JS.castStringToJSString(a1)] - } - function EFittedImage_42(a1) { - return["EFittedImage", JS.castStringToJSString(a1)] - } - function EFlow_43(a1) { - return function(a2) { - return["EFlow", a1, JS.castListToJSArray(a2)] - } - } - function ECollage_44(a1) { - return function(a2) { - return function(a3) { - return["ECollage", a1, a2, Value.groupForms(a3)] - } - } - } - var EEmpty_45 = ["EEmpty"]; - function EContainer_46(a1) { - return function(a2) { - return["EContainer", a1, a2] - } - } - var Solid_68 = ["Solid"]; - var Dotted_69 = ["Dotted"]; - var Dashed_70 = ["Dashed"]; - function Custom_71(a1) { - return["Custom", JS.castListToJSArray(a1)] - } - var Filled_72 = ["Filled"]; - var Outlined_73 = ["Outlined"]; - function CustomOutline_74(a1) { - return["CustomOutline", JS.castListToJSArray(a1)] - } - function Line_75(a1) { - return["Line", JS.castListToJSArray(a1)] - } - function Shape_78(a1) { - return function(a2) { - var points = JS.castListToJSArray(a1); - if (points.length > 0) { points.push(points[0]); } - return["Shape", points, a2]; - } - } - function Form_84(a1) { - return function(a2) { - return function(a3) { - return function(a4) { - return["Form", a1, a2, a3, a4] - } - } - } - } - function FLine_85(a1) { - return function(a2) { - return function(a3) { - return["FLine", a1, a2, a3] - } - } - } - function FShape_86(a1) { - return function(a2) { - return function(a3) { - return["FShape", a1, a2, a3] - } - } - } - function FImage_87(a1) { - return function(a2) { - return function(a3) { - return["FImage", a1, a2, JS.castStringToJSString(a3)] - } - } - } - function FElement_88(a1) { - return["FElement", a1] - } - var left_6 = DLeft_0; - var right_7 = DRight_1; - var down_8 = DDown_3; - var up_9 = DUp_2; - var inward_10 = DIn_4; - var outward_11 = DOut_5; - var topLeft_22 = Position_17(Near_14)(Near_14); - var topRight_23 = Position_17(Far_16)(Near_14); - var bottomLeft_24 = Position_17(Near_14)(Far_16); - var bottomRight_25 = Position_17(Far_16)(Far_16); - var midLeft_26 = Position_17(Near_14)(Mid_15); - var midRight_27 = Position_17(Far_16)(Mid_15); - var midTop_28 = Position_17(Mid_15)(Near_14); - var midBottom_29 = Position_17(Mid_15)(Far_16); - var middle_30 = Position_17(Mid_15)(Mid_15); - function middleAt(a1) { - return function(a2) { - return["PositionAt", a1, a2] - } - } - var topLeftAt_31 = PositionTL_18; - var topRightAt_32 = PositionTR_19; - var bottomLeftAt_33 = PositionBL_20; - var bottomRightAt_34 = PositionBR_21; - var absolute_35 = Absolute_12; - var relative_36 = Relative_13; - function newElement_38(e,w,h,o,c,l) { return Element_37(Guid.guid(),e,w,h,o,c,l); } - function basicNewElement(e,w,h) { return Element_37(Guid.guid(),e,w,h,1,["Nothing"],["Nothing"]); } - var line_76 = Line_75; - var polygon_79 = Shape_78; - function sprite_96(src) { - return function(w) { - return function(h) { - return function(pos) { - return Form_84(0)(1)(pos)(FImage_87(w)(h)(src)) - } - } - } - } - function toForm_97(pos) { - return function(e) { - return Form_84(0)(1)(pos)(FElement_88(e)) - } - } - function width_47(w__101) { - return function(e) { - var be = e[2]; - switch(be[0]) { - case "EImage": - case "EVideo": - return newElement_38(e[2],w__101,e[4] * w__101 / e[3], e[5], e[6], e[7]); - case "EText": - var p = Value.getTextSize(w__101,e[4],be[2]); - return newElement_38(e[2], w__101, p[1], e[5], e[6], e[7]); - } - return newElement_38(e[2], w__101, e[4], e[5], e[6], e[7]); - } - } - function height_48(h__108) { - return function(e) { - var be = e[2]; - switch(be[0]) { - case "EImage": - case "EVideo": - return newElement_38(e[2], e[3] * h__108 / e[4], h__108, e[5], e[6], e[7]); - } - return newElement_38(e[2], e[3], h__108, e[5], e[6], e[7]); - } - } - function size_49(w) { - return function(h) { - return function(e) { - return newElement_38(e[2], w, h, e[5], e[6], e[7]); - } - } - } - function opacity_50(o) { - return function(e) { - return newElement_38(e[2], e[3], e[4], o, e[6], e[7]); - } - } - function color_51(c) { - return function(e) { - return newElement_38(e[2], e[3], e[4], e[5], ["Just",c], e[7]); - } - } - function link(lnk) { - return function(e) { - return newElement_38(e[2], e[3], e[4], e[5], e[6], ["Just", JS.castStringToJSString(lnk)]); - } - } - function widthOf_52(e) { return ~~e[3]; } - function heightOf_53(e) { return ~~e[4]; } - function sizeOf_54(e) { return["Tuple2", ~~e[3], ~~e[4]] } - function text_56(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt), p[0], p[1]) - } - function plainText(str) { - var txt = Value.toText(str); - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt),p[0],p[1]) - } - function asText(v) { - var txt = Elm.Text.monospace(Value.toText(Value.show(v))); - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt),p[0],p[1]) - } - function centeredText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("center")(txt),p[0],p[1]) - } - function justifiedText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("justify")(txt),p[0],p[1]) - } - function rightedText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("right")(txt),p[0],p[1]) - } - function image_57(w) { - return function(h) { - return function(src) { - return basicNewElement(EImage_40(src),w,h) - } - } - } - function images(srcs) { - var pics = Elm.Signal.constant(spacer_66(0)(0)); - var update = Elm.Signal.lift(function(src) { - src = JS.castStringToJSString(src); - var img = new Image(); - img.onload = function() { - Dispatcher.notify(pics.id, - image_57(this.width)(this.height)(src)); - }; - img.src = src; - })(srcs); - function f(x) { return function(y) { return x; } } - var combine = Elm.Signal.lift2(f)(pics)(update); - return combine; - } - function video_58(w) { - return function(h) { - return function(src) { - return basicNewElement(EVideo_41(src),w,h) - } - } - } - function fittedImage_59(w_147) { - return function(h_148) { - return function(s_149) { - return basicNewElement(EFittedImage_42(s_149),w_147,h_148) - } - } - } - function flow_60(dir_150) { - return function(es_151) { - return function() { - var w_152 = function() { - var ws_154 = map(widthOf_52)(es_151); - return function(case1) { - var case0 = case1; - switch(case0[0]) { - case "DLeft": - return sum(ws_154); - case "DRight": - return sum(ws_154) - } - return maximum(ws_154) - }(dir_150) - }(); - var h_153 = function() { - var hs_155 = map(heightOf_53)(es_151); - return function(case3) { - var case2 = case3; - switch(case2[0]) { - case "DDown": - return sum(hs_155); - case "DUp": - return sum(hs_155) - } - return maximum(hs_155) - }(dir_150) - }(); - return basicNewElement(EFlow_43(dir_150)(es_151), w_152, h_153) - }() - } - } - function above_61(e1_156) { - return function(e2_157) { - return basicNewElement(EFlow_43(DDown_3)(["Cons", e1_156, ["Cons", e2_157, ["Nil"]]]), Math.max(widthOf_52(e1_156),widthOf_52(e2_157)), heightOf_53(e1_156) + heightOf_53(e2_157)); - } - } - function below_62(e1_158) { - return function(e2_159) { - return basicNewElement(EFlow_43(DDown_3)(["Cons", e2_159, ["Cons", e1_158, ["Nil"]]]), Math.max(widthOf_52(e1_158),widthOf_52(e2_159)), heightOf_53(e1_158) + heightOf_53(e2_159)); - } - } - function beside_63(e1_160) { - return function(e2_161) { - return basicNewElement(EFlow_43(DRight_1)(["Cons", e1_160, ["Cons", e2_161, ["Nil"]]]), widthOf_52(e1_160) + widthOf_52(e2_161), Math.max(heightOf_53(e1_160),heightOf_53(e2_161))); - } - } - function layers_64(es_162) { - return basicNewElement(EFlow_43(DOut_5)(es_162), maximum(map(widthOf_52)(es_162)), maximum(map(heightOf_53)(es_162))) - } - function collage_65(w_163) { - return function(h_164) { - return function(forms_165) { - return basicNewElement(ECollage_44(w_163)(h_164)(forms_165),w_163,h_164) - } - } - } - function spacer_66(w_166) { - return function(h_167) { - return basicNewElement(EEmpty_45,w_166,h_167) - } - } - function container_67(w_169) { - return function(h_170) { - return function(pos_168) { - return function(e_171) { - return basicNewElement(EContainer_46(pos_168)(e_171),w_169,h_170) - } - } - } - } - function segment_77(p1_172) { - return function(p2_173) { - return Line_75(["Cons", p1_172, ["Cons", p2_173, ["Nil"]]]) - } - } - function rect_80(w_174) { - return function(h_175) { - return function(pos_176) { - return Shape_78(["Cons", ["Tuple2", 0 - w_174 / 2, 0 - h_175 / 2], - ["Cons", ["Tuple2", 0 - w_174 / 2, h_175 / 2], - ["Cons", ["Tuple2", w_174 / 2, h_175 / 2], - ["Cons", ["Tuple2", w_174 / 2, 0 - h_175 / 2], ["Nil"]]]]])(pos_176) - } - } - } - function oval_81(w_177) { - return function(h_178) { - return function(pos_179) { - return function() { - var n_180 = 50; - return function() { - function f_181(i_182) { - return["Tuple2", w_177 / 2 * Math.cos(2 * (Math.PI / n_180) * i_182), h_178 / 2 * Math.sin(2 * (Math.PI / n_180) * i_182)]; - } - return Shape_78(map(f_181)(function() { - var lo = 0; - var hi = n_180 - 1; - var lst = ["Nil"]; - if(lo <= hi) { - do { - lst = ["Cons", hi, lst] - }while(hi-- > lo) - } - return lst - }()))(pos_179) - }() - }() - } - } - } - function circle_82(r_183) { - return oval_81(2 * r_183)(2 * r_183) - } - function ngon_83(n_184) { - return function(r_185) { - return function(pos_186) { - return function() { - var m_187 = n_184; - return function() { - function f_188(i_189) { - return["Tuple2", r_185 * Math.cos(2 * (Math.PI / m_187) * i_189), r_185 * Math.sin(2 * (Math.PI / m_187) * i_189)]; - } - return Shape_78(map(f_188)(function() { - var lo = 0; - var hi = n_184 - 1; - var lst = ["Nil"]; - if(lo <= hi) { - do { - lst = ["Cons", hi, lst] - }while(hi-- > lo) - } - return lst - }()))(pos_186) - }() - }() - } - } - } - function solid_89(clr_190) { - return function(ln_191) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Solid_68)(clr_190)(ln_191)) - } - } - function dotted_90(clr_192) { - return function(ln_193) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Dotted_69)(clr_192)(ln_193)) - } - } - function dashed_91(clr_194) { - return function(ln_195) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Dashed_70)(clr_194)(ln_195)) - } - } - function customLine_92(pattern_196) { - return function(clr_197) { - return function(ln_198) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Custom_71(pattern_196))(clr_197)(ln_198)) - } - } - } - function filled_93(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(Filled_72)(clr)(shape)); - } - } - function outlined_94(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(Outlined_73)(clr)(shape)); - } - } - function customOutline_95(pattern) { - return function(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(CustomOutline_74(pattern))(clr)(shape)); - } - } - } - function textured(src) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(["Textured",src])(null)(shape)); - } - } - function rotate_98(t_212) { - return function(Form$thetascaleposform_213) { - return function(case5) { - var case0 = case5; - switch(case0[0]) { - case "Form": - var case1 = case0[1], case2 = case0[2], case3 = case0[3], case4 = case0[4]; - return Form_84(t_212 + case1)(case2)(case3)(case4) - } - throw new Error("Non-exhaustive pattern match in case"); - }(Form$thetascaleposform_213) - } - } - function scale_99(s) { - return function(form) { - return Form_84(form[1])(s * form[2])(form[3])(form[4]) - } - } - function move_100(x_224) { - return function(y_225) { - return function(Form$thetascaleTuple2$pxpyform_226) { - return function(case7) { - var case0 = case7; - switch(case0[0]) { - case "Form": - var case1 = case0[1], case2 = case0[2], case3 = case0[3], case4 = case0[4]; - switch(case3[0]) { - case "Tuple2": - var case5 = case3[1], case6 = case3[2]; - return Form_84(case1)(case2)(["Tuple2", x_224 + case5, y_225 + case6])(case4) - } - break - } - throw new Error("Non-exhaustive pattern match in case"); - }(Form$thetascaleTuple2$pxpyform_226) - } - } - } - return{left:left_6, right:right_7, down:down_8, up:up_9, inward:inward_10, outward:outward_11, topLeft:topLeft_22, topRight:topRight_23, bottomLeft:bottomLeft_24, bottomRight:bottomRight_25, midLeft:midLeft_26, midRight:midRight_27, midTop:midTop_28, midBottom:midBottom_29, middle:middle_30, middleAt:middleAt, topLeftAt:topLeftAt_31, topRightAt:topRightAt_32, bottomLeftAt:bottomLeftAt_33, bottomRightAt:bottomRightAt_34, absolute:absolute_35, relative:relative_36, width:width_47, height:height_48, size:size_49, opacity:opacity_50, - color:color_51, link:link, widthOf:widthOf_52, heightOf:heightOf_53, sizeOf:sizeOf_54, text:text_56, asText:asText, plainText:plainText, centeredText:centeredText, justifiedText:justifiedText, rightedText:rightedText, image:image_57, images:images, video:video_58, fittedImage:fittedImage_59, flow:flow_60, above:above_61, below:below_62, beside:beside_63, layers:layers_64, collage:collage_65, spacer:spacer_66, container:container_67, line:line_76, segment:segment_77, polygon:polygon_79, rect:rect_80, oval:oval_81, circle:circle_82, ngon:ngon_83, solid:solid_89, dotted:dotted_90, dashed:dashed_91, customLine:customLine_92, filled:filled_93, - outlined:outlined_94, customOutline:customOutline_95, textured:textured, sprite:sprite_96, toForm:toForm_97, rotate:rotate_98, scale:scale_99, move:move_100, - isWithin: Collage.insideForm} -}(); \ No newline at end of file diff --git a/core-js/Graphics/Render.js b/core-js/Graphics/Render.js deleted file mode 100644 index f661ae1..0000000 --- a/core-js/Graphics/Render.js +++ /dev/null @@ -1,277 +0,0 @@ - -var Render = function(){ - -function newElement(elementType) { - var e = document.createElement(elementType); - e.style.padding = "0"; - e.style.margin = "0"; - return e; -}; - -function addTo(container, elem) { - container.appendChild(elem); -}; - -function makeText(pos,txt) { - var e = newElement('div'); - e.innerHTML = txt; - e.style.textAlign = pos; - return e; -}; - -function image(src) { - var img = newElement('img'); - img.src = src; - img.name = src; - img.style.display = "block"; - return img; -} - -function fittedImage(w,h,src) { - var e = newElement('div'); - e.style.width = w + 'px'; - e.style.height = h + 'px'; - e.style.position = "relative"; - e.style.overflow = "hidden"; - - var img = newElement('img'); - img.onload = function() { - img.style.position = 'absolute'; - img.style.margin = 'auto'; - - var sw = w, sh = h; - if (w / h > this.width / this.height) { - sh = Math.round(this.height * w / this.width); - } else { - sw = Math.round(this.width * h / this.height); - } - img.style.width = sw + 'px'; - img.style.height = sh + 'px'; - img.style.left = ((w - sw) / 2) + 'px'; - img.style.top = ((h - sh) / 2) + 'px'; - }; - img.src = src; - img.name = src; - addTo(e,img); - return e; -}; - -var video = function(src) { - var e = newElement('video'); - e.controls = "controls"; - var source = newElement('source'); - source.src = src; - var segs = src.split('.'); - source.type = "video/" + segs[segs.length-1]; - addTo(e, source); - e.style.display = "block"; - return e; -}; - -function divify(e) { - var div = newElement('div'); - addTo(div, e); - return div; -}; -function goDown(e) { - return e //.tagName === "DIV" ? e : divify(e); -}; -function goRight(e) { - e.style.styleFloat = "left"; - e.style.cssFloat = "left"; - return e; -}; -function goIn(e) { - e.style.position = 'absolute'; - return e; -}; -function flowWith(f, prep, elist) { - var container = newElement('div'); - for (var i = elist.length; i--; ) { - addTo(container, f(prep(elist[i]))); - } - return container; -}; - -function flow(dir,elist) { - switch(dir) { - case "DDown": elist = elist.slice(0).reverse(); - case "DUp": return flowWith(goDown,render,elist); - case "DRight": elist = elist.slice(0).reverse(); - case "DLeft": return flowWith(goRight,render,elist); - case "DOut": elist = elist.slice(0).reverse(); - case "DIn": return flowWith(goIn,render,elist); - }; -}; - -function toPos(pos) { - switch(pos[0]) { - case "Absolute": return pos[1] + "px"; - case "Relative": return (pos[1] * 100) + "%"; - } -} - -function setPos(pos,e) { - e.style.position = 'absolute'; - e.style.margin = 'auto'; - switch(pos[0]) { - case "Position": - if (pos[1][0] !== "Far") e.style.left = 0; - if (pos[1][0] !== "Near") e.style.right = 0; - if (pos[2][0] !== "Far") e.style.top = 0; - if (pos[2][0] !== "Near") e.style.bottom = 0; - break; - case "PositionAt": - e.style.top = toPos(pos[2]); - e.style.left = toPos(pos[1]); - var shift = "translate(" + ~~(-e.style.width.slice(0,-2) / 2) + "px," + ~~(-e.style.height.slice(0,-2) / 2) + "px)"; - e.style.transform = shift; - e.style.msTransform = shift; - e.style.MozTransform = shift; - e.style.webkitTransform = shift; - e.style.OTransform = shift; - break; - default: - var p = pos[0].slice(-2); - e.style[p[0] === "T" ? 'top' : 'bottom'] = toPos(pos[2]); - e.style[p[1] === "L" ? 'left' : 'right'] = toPos(pos[1]); - } -} - -function container(pos,elem) { - var e = render(elem); - setPos(pos,e); - var div = newElement('div'); - div.style.position = "relative"; - div.style.overflow = "hidden"; - addTo(div,e); - return div; -}; - -function render(elem) { - var e = {}; - switch(elem[2][0]) { - case "EText": e = makeText(elem[2][1],elem[2][2]); break; - case "EImage": e = image(elem[2][1]); break; - case "EVideo": e = video(elem[2][1]); break; - case "EFittedImage": e = fittedImage(elem[3],elem[4],elem[2][1]); break; - case "EFlow": e = flow(elem[2][1][0],elem[2][2]); break; - case "ECollage": e = Collage.collage(elem[2][1],elem[2][2],elem[2][3]); break; - case "EEmpty": e = newElement('div'); break; - case "EContainer": e = container(elem[2][1],elem[2][2]); break; - case "EHtml": - e = elem[2][1]; - if (e.type !== 'button') { - var p = Value.getExcess(e); - elem[3] -= p[0]; - elem[4] -= p[1]; - } - break; - case "EExternalHtml": - e = newElement('div'); - addTo(e, elem[2][1]); - break; - } - e.id = elem[1]; - e.style.width = (~~elem[3]) + 'px'; - e.style.height = (~~elem[4]) + 'px'; - if (elem[5] !== 1) { e.style.opacity = elem[5]; } - if (elem[6][0] === "Just") { - e.style.backgroundColor = Elm.Color.extract(elem[6][1]); - } - if (elem[7][0] === "Just") { - var a = newElement('a'); - a.href = elem[7][1]; - addTo(a,e); - return a; - } - return e; -}; - -function update(node,curr,next) { - if (node.tagName === 'A') { node = node.firstChild; } - if (curr[1] === next[1]) return; - if (curr[2][0] !== next[2][0]) { - return node.parentNode.replaceChild(render(next),node); - } - var nextE = next[2], currE = curr[2]; - switch(nextE[0]) { - case "EText": - if (nextE[1] !== currE[1]) node.style.textAlign = nextE[1]; - if (nextE[2] !== currE[2]) node.innerHTML = nextE[2]; - break; - case "EImage": - if (nextE[1] !== currE[1]) node.src = nextE[1]; - break; - case "EVideo": - case "EFittedImage": - if (!Value.eq(nextE,currE) || next[3]!==curr[3] || next[4]!==curr[4]) { - return node.parentNode.replaceChild(render(next),node); - } - break; - case "ECollage": - if (nextE[1] !== currE[1] || nextE[2] !== currE[2] || nextE[3].length !== currE[3].length) { - return node.parentNode.replaceChild(render(next),node); - } - Collage.updateCollage(node,currE[3],nextE[3]); - break; - case "EFlow": - if (nextE[1] !== currE[1]) { - return node.parentNode.replaceChild(render(next),node); - } - var nexts = nextE[2]; - var kids = node.childNodes; - if (nexts.length !== kids.length) { - return node.parentNode.replaceChild(render(next),node); - } - var currs = currE[2]; - var goDir = function(x) { return x; }; - switch(nextE[1][0]) { - case "DDown": case "DUp": goDir = goDown; break; - case "DRight": case "DLeft": goDir = goRight; break; - case "DOut": case "DIn": goDir = goIn; break; - } - for (var i = kids.length; i-- ;) { - update(kids[i],currs[i],nexts[i]); - goDir(kids[i]); - } - break; - case "EContainer": - update(node.childNodes[0],currE[2],nextE[2]); - setPos(nextE[1],node.childNodes[0]); - break; - case "EEmpty": - break; - case "EHtml": - if (next[1] !== curr[1]) { - var e = render(next); - node.parentNode.replaceChild(e,node); - node = e; - } - if (e.type !== 'button') { - var p = Value.getExcess(node); - next[3] -= p[0]; - next[4] -= p[1]; - } - break; - case "EExternalHtml": - if (next[1] !== curr[1]) - node.parentNode.replaceChild(render(next),node); - break; - } - if (next[3] !== curr[3]) node.style.width = (~~next[3]) + 'px'; - if (next[4] !== curr[4]) node.style.height = (~~next[4]) + 'px'; - if (next[5] !== curr[5]) node.style.opacity = next[5]; - if (next[6].length === 2) { - var clr = Elm.Color.extract(next[6][1]); - if (clr !== node.style.backgroundColor) node.style.backgroundColor = clr; - } - if (next[7].length === 2) { - if (curr[7].length === 1 || next[7][1] !== curr[7][1]) node.parentNode.href = next[7][1]; - } - next[1] = curr[1]; -} - -return {render:render,update:update,addTo:addTo,newElement:newElement,flowWith:flowWith,goIn:goIn}; - -}(); \ No newline at end of file diff --git a/core-js/Guid.js b/core-js/Guid.js deleted file mode 100644 index 8fb83b9..0000000 --- a/core-js/Guid.js +++ /dev/null @@ -1,8 +0,0 @@ - -Elm = {}; - -var Guid = function() { - var counter = 0; - var guid = function() { counter += 1; return counter; }; - return {guid : guid}; -}(); \ No newline at end of file diff --git a/core-js/List.js b/core-js/List.js deleted file mode 100644 index eba129e..0000000 --- a/core-js/List.js +++ /dev/null @@ -1,482 +0,0 @@ -Elm.List = function() { - - var throwError = function(f) { - throw new Error("Function '" + f + "' expecting a list!"); - } - - function length(xs) { - var out = 0; - while (xs[0] === "Cons") { - out += 1; - xs = xs[2]; - } - return out; - }; - var reverse = foldl(function(x_72) { - return function(y_73) { - return["Cons", x_72, y_73] - } - })(["Nil"]); - var concat = foldr(function(x_74) { - return function(y_75) { - return Value.append(x_74, y_75) - } - })(["Nil"]); - var and = foldl(function(x_77) { - return function(y_78) { - return x_77 && y_78 - } - })(true); - var or = foldl(function(x_79) { - return function(y_80) { - return x_79 || y_80 - } - })(false); - var sum = foldl(function(x_89) { - return function(y_90) { - return x_89 + y_90 - } - })(0); - var product = foldl(function(x_91) { - return function(y_92) { - return x_91 * y_92 - } - })(1); - var maximum = foldl1(function(x) { return function(y) { return Math.max(x,y) } }); - var minimum = foldl1(function(x) { return function(y) { return Math.min(x,y) } }); - function head(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'head' only accepts lists of length greater than one."); - } - return v[1]; - } - function tail(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'tail' only accepts lists of length greater than one."); - } - return v[2]; - } - function last(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'last' only accepts lists of length greater than one."); - } - var out = v[1]; - while (v[0] === "Cons") { - out = v[1]; - v = v[2]; - } - return out; - } - function map(f) { - return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('map'); } - var root = ["Cons", f(xs[1]), ["Nil"]]; - var curr = root; - xs = xs[2]; - while (xs[0]==="Cons") { - curr[2] = ["Cons", f(xs[1]), ["Nil"]]; - xs = xs[2]; - curr = curr[2]; - } - return root; - } - } - function foldl(f) { - return function(b) { - return function(xs) { - var acc = b; - if (xs[0] === "Nil") { return acc; } - if (xs[0] !== "Cons") { throwError('foldl'); } - while (xs[0] === "Cons") { - acc = f(xs[1])(acc); - xs = xs[2]; - } - return acc; - } - } - } - function foldr(f) { - return function(b) { - return function(xs) { - var acc = b; - if (xs[0] === "Nil") { return acc; } - if (xs[0] !== "Cons") { throwError('foldr'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - } - function foldl1(f_49) { - return function(_temp_50) { - return function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var x_51 = v[1]; - var xs_52 = v[2]; - return foldl(f_49)(x_51)(xs_52) - } - }(_temp_50) - } - } - function foldr1(f) { - return function(xs) { - if (xs[0] === "Nil") { throw new Error("'foldr1' requires an non-empty list.") } - if (xs[0] !== "Cons") { throwError('foldr1'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - var acc = arr.pop(); - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - function scanl(f) { - return function(b) { - return function(xs) { - if (xs[0] === "Nil") { return ["Cons",b,["Nil"]]; } - if (xs[0] !== "Cons") { throwError('scanl'); } - var arr = [b]; - while (xs[0] === "Cons") { - b = f(xs[1])(b); - arr.push(b); - xs = xs[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - } - function scanl1(f) { - return function(xs) { - if (xs[0] !== "Cons") { - throw new Error("Error: 'scanl1' requires a list of at least length 1."); - } - return scanl(f)(xs[1])(xs[2]); - } - } - function filter(pred) { - return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('filter'); } - var arr = []; - while (xs[0] === "Cons") { - if (pred(xs[1])) { arr.push(xs[1]); } - xs = xs[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - function concatMap(f_76) { - return function(x) { - return concat(map(f_76)(x)) - } - } - function all(pred) { - return foldl(function(x) { return function(acc) { - return acc && pred(x); - };})(true); - } - function any(pred) { - return foldl(function(x) { return function(acc) { - return acc || pred(x); - };})(false); - } - function partition(pred_93) { - return function(lst_94) { - return function() { - var v = lst_94; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Tuple2", ["Nil"], ["Nil"]] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var x_95 = v[1]; - var xs_96 = v[2]; - return function(v) { - if("Tuple2" !== v[0]) { - return undefined - }else { - var as_97 = v[1]; - var bs_98 = v[2]; - return pred_93(x_95) ? ["Tuple2", ["Cons", x_95, as_97], bs_98] : ["Tuple2", as_97, ["Cons", x_95, bs_98]] - } - }(partition(pred_93)(xs_96)) - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function zipWith(f) { - return function(listA) { - return function(listB) { - if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; } - if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zipWith'); } - var arr = []; - while (listA[0] === "Cons" && listB[0] === "Cons") { - arr.push(f(listA[1])(listB[1])); - listA = listA[2]; - listB = listB[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - } - function zip(listA) { - return function(listB) { - if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; } - if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zip'); } - var arr = []; - while (listA[0] === "Cons" && listB[0] === "Cons") { - arr.push(["Tuple2", listA[1], listB[1]]); - listA = listA[2]; - listB = listB[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - function unzip(pairs_112) { - return function() { - var v = pairs_112; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Tuple2", ["Nil"], ["Nil"]] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var p_113 = v[1]; - var ps_114 = v[2]; - return function(v) { - if("Tuple2" !== v[0]) { - return undefined - }else { - if("Tuple2" !== v[1][0]) { - return undefined - }else { - var x_115 = v[1][1]; - var y_116 = v[1][2]; - if("Tuple2" !== v[2][0]) { - return undefined - }else { - var xs_117 = v[2][1]; - var ys_118 = v[2][2]; - return["Tuple2", ["Cons", x_115, xs_117], ["Cons", y_116, ys_118]] - } - } - } - }(["Tuple2", p_113, unzip(ps_114)]) - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - function intersperse(sep_119) { - return function(xs_120) { - return function() { - var v = xs_120; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Nil"] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_124 = v[1]; - if("Nil" !== v[2][0]) { - return undefined - }else { - return["Cons", a_124, ["Nil"]] - } - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_121 = v[1]; - if("Cons" !== v[2][0]) { - return undefined - }else { - var b_122 = v[2][1]; - var cs_123 = v[2][2]; - return["Cons", a_121, ["Cons", sep_119, intersperse(sep_119)(["Cons", b_122, cs_123])]] - } - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function intercalate(sep_125) { - return function(xs_126) { - return function() { - var v = xs_126; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Nil"] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_130 = v[1]; - if("Nil" !== v[2][0]) { - return undefined - }else { - return a_130 - } - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_127 = v[1]; - if("Cons" !== v[2][0]) { - return undefined - }else { - var b_128 = v[2][1]; - var cs_129 = v[2][2]; - return Value.append(a_127, Value.append(sep_125, intercalate(sep_125)(["Cons", b_128, cs_129]))) - } - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function sort(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('sort'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - arr.sort(function(a,b) { return a - b}); - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = [ "Cons", arr[i], out ]; - } - return out; - } - function take(n) { return function(xs) { - if (n <= 0) { return ["Nil"]; } - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('take'); } - var out = [ "Cons", xs[1], ["Nil"] ]; - var temp = out; - xs = xs[2]; - --n; - while (xs[0] === "Cons" && n > 0) { - temp[2] = [ "Cons", xs[1], ["Nil"] ]; - temp = temp[2]; - xs = xs[2]; - --n; - } - return out; - }; - } - function drop(n) { return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('drop'); } - while (xs[0] === "Cons" && n > 0) { - xs = xs[2]; - --n; - } - return xs; - }; - } - return {head:head, - tail:tail, - last:last, - map:map, - foldl:foldl, - foldr:foldr, - foldl1:foldl1, - foldr1:foldr1, - scanl:scanl, - scanl1:scanl1, - filter:filter, - length:length, - reverse:reverse, - concat:concat, - concatMap:concatMap, - and:and, - or:or, - all:all, - any:any, - sum:sum, - product:product, - maximum:maximum, - minimum:minimum, - partition:partition, - zipWith:zipWith, - zip:zip, - unzip:unzip, - intersperse:intersperse, - intercalate:intercalate, - sort:sort, - take:take, - drop:drop}; -}(); \ No newline at end of file diff --git a/core-js/Maybe.js b/core-js/Maybe.js deleted file mode 100644 index dd17a34..0000000 --- a/core-js/Maybe.js +++ /dev/null @@ -1,62 +0,0 @@ -/*! Maybe -!*/ - -/*[Definition]*/ - -/** data Maybe a = Just a | Nothing - The Maybe datatype. Useful when a computation may or may not - result in a value (e.g. logarithm is defined only for positive numbers). -**/ - -/*[Basic Utilities]*/ - -/** maybe : b -> (a -> b) -> Maybe a -> b - Apply a function to the contents of a `Maybe`. - Return default when given `Nothing`. -**/ -/** isJust : Maybe a -> Bool - Check if constructed with `Just`. -**/ -/** isNothing : Maybe a -> Bool - Check if constructed with `Nothing`. -**/ - -/*[Maybe with Lists]*/ - -/** cons : Maybe a -> [a] -> [a] - If `Just`, adds the value to the front of the list. - If `Nothing`, list is unchanged. -**/ -/** justs : [Maybe a] -> [a] - Filters out Nothings and extracts the remaining values. -**/ - -Elm.Maybe = function() { - function consMaybe(x) { return function(xs) { - if (x[0] === "Just") return ["Cons", x[1], xs]; - return xs; - }; - } - function mapCons(f) { return function(y) { return function(xs) { - var x = f(y); - if (x[0] === "Just") return ["Cons", x[1], xs]; - return xs; - }; - }; - } - function maybe(b) { return function(f) { return function(m) { - if (m[0] === "Just") return f(m[1]); - return b; - }; - }; - } - - return {Just : function(x) { return ["Just",x]; }, - Nothing : ["Nothing"], - justs : Elm.List.foldr(consMaybe)(["Nil"]), - isJust : function(m) { return m[0] === "Just"; }, - isNothing : function(m) { return m[0] === "Nothing"; }, - cons : consMaybe, - maybe : maybe - }; -}(); diff --git a/core-js/Prelude.js b/core-js/Prelude.js deleted file mode 100644 index e645f8a..0000000 --- a/core-js/Prelude.js +++ /dev/null @@ -1,243 +0,0 @@ -function elmRecordCopy(r) { - var o = {}; - for (var i in r) { o[i] = r[i]; } - return o; -} - -function elmRecordRemove(x,r) { - var o = elmRecordCopy(r); - if (x in o._) { - o[x] = o._[x][0]; - o._[x] = o._[x].slice(1); - if (o._[x].length === 0) { delete o._[x]; } - } else { - delete o[x]; - } - return o; -} - -function elmRecordReplace(kvs,r) { - var o = elmRecordCopy(r); - for (var i = kvs.length; i--; ) { - kvsi = kvs[i]; - o[kvsi[0]] = kvsi[1]; - } - return o; -} - -function elmRecordInsert(x,v,r) { - var o = elmRecordCopy(r); - if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []); - o[x] = v; - return o; -} - -Value.addListener(document, 'elm_log', function(e) { console.log(e.value); }); -Value.addListener(document, 'elm_title', function(e) {document.title = e.value;}); -Value.addListener(document, 'elm_redirect', function(e) { - if (e.value.length > 0) { window.location = e.value; } - }); -Value.addListener(document, 'elm_viewport', function(e) { - var node = document.getElementById('elm_viewport'); - if (!node) { - node = document.createElement('meta'); - node.id = 'elm_viewport'; - node.name = 'viewport'; - document.head.appendChild(node); - } - node.content = e.value; - Dispatcher.notify(Elm.Window.dimensions.id, - Value.Tuple(window.innerWidth, window.innerHeight)); - }); - -Elm.Prelude = function() { - var mod = function(x) { return function(y) { - var r = x % y; - var m = x==0 ? 0 : (y>0 ? (x>=0 ? r : r+y) : -mod(-x)(-y)); - return m == y ? 0 : m; - }; }; - - var min = function(x) { return function(y) { return Math.min(x,y); }; }; - var max = function(x) { return function(y) { return Math.max(x,y); }; }; - - var flip=function(f){return function(x){return function(y){return f(y)(x);};};}; - var clamp = function(lo) { return function(hi) { - return function(x) { return Math.min(hi, Math.max(lo, x)); }; - }; - }; - var curry = function(f) { return function(x) { return function(y) { - return f(["Tuple2",x,y]); }; }; - }; - var uncurry = function(f) { return function(p) { - if (p[0] !== "Tuple2") { - throw new Error("Function was uncurry'd but was not given a pair."); - } - return f(p[1])(p[2]); }; - }; - - var logBase=function(b){return function(x){return Math.log(x)/Math.log(b);};}; - - function readInt(str) { - var s = Elm.JavaScript.castStringToJSString(str); - var len = s.length; - if (len === 0) { return ["Nothing"]; } - var start = 0; - if (s[0] == '-') { - if (len === 1) { return ["Nothing"]; } - start = 1; - } - for (var i = start; i < len; ++i) { - if (!Elm.Char.isDigit(s[i])) { return ["Nothing"]; } - } - return ["Just", parseInt(s)]; - } - - function readFloat(str) { - var s = Elm.JavaScript.castStringToJSString(str); - var len = s.length; - if (len === 0) { return ["Nothing"]; } - var start = 0; - if (s[0] == '-') { - if (len === 1) { return ["Nothing"]; } - start = 1; - } - var dotCount = 0; - for (var i = start; i < len; ++i) { - if (Elm.Char.isDigit(s[i])) { continue; } - if (s[i] === '.') { - dotCount += 1; - if (dotCount <= 1) { continue; } - } - return ["Nothing"]; - } - return ["Just", parseFloat(s)]; - } - - function compare(x) { return function (y) { - if (x instanceof Array && y instanceof Array) { - var len = x.length; - if (len == y.length) { - for (var i = 1; i < len; ++i) { - var cmp = compare(x[i])(y[i]); - if (cmp[0] === 'EQ') continue; - return cmp; - } - return ['EQ']; - } - return [ y.length == 1 ? 'GT' : 'LT' ]; - } - return [ x === y ? 'EQ' : (x < y ? 'LT' : 'GT') ]; - }; - } - return {eq : Value.eq, - id : function(x) { return x; }, - not : function(b) { return !b; }, - xor : function(x) { return function(y) { return x != y; }; }, - fst : function(p) { return p[1]; }, - snd : function(p) { return p[2]; }, - rem : function(x) { return function(y) { return x % y; }; }, - div : function(x) { return function(y) { return ~~(x / y); }; }, - otherwise : true, - compare : compare, - toFloat : function(x) { return x; }, - round : function(n) { return Math.round(n); }, - floor : function(n) { return Math.floor(n); }, - ceiling : function(n) { return Math.ceil(n); }, - truncate : function(n) { return ~~n; }, - readInt : readInt, - readFloat : readFloat, - sqrt : Math.sqrt, - abs : Math.abs, - pi : Math.PI, - e : Math.E, - sin : Math.sin, - cos : Math.cos, - tan : Math.tan, - asin : Math.asin, - acos : Math.acos, - atan : Math.atan, - atan2 : function(y) { return function(x) { return Math.atan2(y,x); }; }, - mod : mod, - min : min, - max : max, - flip : flip, - clamp : clamp, - curry : curry, - uncurry : uncurry, - logBase : logBase, - Just : Elm.Maybe.Just, - Nothing : Elm.Maybe.Nothing, - maybe : Elm.Maybe.maybe, - map : Elm.List.map, - zip : Elm.List.zip, - zipWith : Elm.List.zipWith, - filter : Elm.List.filter, - head : Elm.List.head, - tail : Elm.List.tail, - last : Elm.List.last, - length : Elm.List.length, - reverse : Elm.List.reverse, - foldr : Elm.List.foldr, - foldr1 : Elm.List.foldr1, - foldl : Elm.List.foldl, - foldl1 : Elm.List.foldl1, - and : Elm.List.and, - or : Elm.List.or, - all : Elm.List.all, - any : Elm.List.any, - sum : Elm.List.sum, - product : Elm.List.product, - concat : Elm.List.concat, - concatMap : Elm.List.concatMap, - maximum : Elm.List.maximum, - minimum : Elm.List.minimum, - scanl : Elm.List.scanl, - scanl1 : Elm.List.scanl1, - take : Elm.List.take, - drop : Elm.List.drop, - zip : Elm.List.zip, - unzip : Elm.List.unzip, - lift : Elm.Signal.lift, - lift2 : Elm.Signal.lift2, - lift3 : Elm.Signal.lift3, - lift4 : Elm.Signal.lift4, - lift5 : Elm.Signal.lift5, - lift6 : Elm.Signal.lift6, - lift7 : Elm.Signal.lift7, - lift8 : Elm.Signal.lift8, - foldp : Elm.Signal.foldp, - foldp1 : Elm.Signal.foldp1, - foldp$ : Elm.Signal.foldp$, - constant : Elm.Signal.constant, - merge : Elm.Signal.merge, - merges : Elm.Signal.merges, - mergeEither : Elm.Signal.mergeEither, - count : Elm.Signal.count, - countIf : Elm.Signal.countIf, - average : Elm.Signal.average, - keepIf : Elm.Signal.keepIf, - dropIf : Elm.Signal.dropIf, - keepWhen : Elm.Signal.keepWhen, - dropWhen : Elm.Signal.dropWhen, - dropRepeats : Elm.Signal.dropRepeats, - sampleOn : Elm.Signal.sampleOn, - timestamp : Elm.Signal.timestamp, - timeOf : Elm.Signal.timeOf - }; - -}(); - -(function() { - var include = function(library) { - for (var i in library) { - Elm.Prelude[i] = library[i]; - } - }; - include (Elm.Color); - include (Elm.Text); - include (Elm.Graphics); - include (Elm.Time); - - show = Value.show; - -}()); diff --git a/core-js/Set.js b/core-js/Set.js deleted file mode 100644 index faf3b87..0000000 --- a/core-js/Set.js +++ /dev/null @@ -1,31 +0,0 @@ - -Elm.Set=function(){ - var empty_0=Elm.Dict.empty; - var remove_3=Elm.Dict.remove; - var member_4=Elm.Dict.member; - var union_5=Elm.Dict.union; - var intersect_6=Elm.Dict.intersect; - var diff_7=Elm.Dict.diff; - var toList_8=Elm.Dict.keys; - var fromList_9=Elm.List.foldl(function(k_15){ - return function(t_16){ - return Elm.Dict.insert(k_15)(["Tuple0"])(t_16);};})(empty_0); - function singleton_1(k_13){ - return Elm.Dict.singleton(k_13)(["Tuple0"]);}; - function insert_2(k_14){ - return Elm.Dict.insert(k_14)(["Tuple0"]);}; - function foldl_10(f_17){ - return Elm.Dict.foldl(function(k_18){ - return function(v_19){ - return function(b_20){ - return f_17(k_18)(b_20);};};});}; - function foldr_11(f_21){ - return Elm.Dict.foldr(function(k_22){ - return function(v_23){ - return function(b_24){ - return f_21(k_22)(b_24);};};});}; - function map_12(f_25){ - return function(t_26){ - return function(x){ - return fromList_9(Elm.List.map(f_25)(x));}(toList_8(t_26));};}; - return {empty:empty_0,singleton:singleton_1,insert:insert_2,remove:remove_3,member:member_4,union:union_5,intersect:intersect_6,diff:diff_7,toList:toList_8,fromList:fromList_9,foldl:foldl_10,foldr:foldr_11,map:map_12};}(); diff --git a/core-js/Signal/HTTP.js b/core-js/Signal/HTTP.js deleted file mode 100644 index 9aa702c..0000000 --- a/core-js/Signal/HTTP.js +++ /dev/null @@ -1,111 +0,0 @@ - -/*! HTTP -A library for asynchronous HTTP requests (AJAX). See the -[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if -you have very strict latency requirements. -!*/ - -Elm.HTTP = function() { - var JS = Elm.JavaScript; - var toElmString = Elm.JavaScript.castJSStringToString; - - /*[Creating Requests]*/ - - /** get : String -> Request String - Create a GET request to the given url. - **/ - function get(url) { return request("GET")(url)(null)(["Nil"]); } - - /** post : String -> String -> Request String - Create a POST request to the given url, carrying the given data. - **/ - function post(url) { return function(data) { - return request("POST")(url)(data)(["Nil"]); }; } - - /** request : String -> String -> String -> [(String,String)] -> Request String - Create a customized request. Arguments are request type (get, post, put, - delete, etc.), target url, data, and a list of additional headers. - **/ - function request(verb) { return function(url) { return function(data) { - return function(headers) { - return {0 : "Request", - length : 1, - verb : JS.castStringToJSString(verb), - url : JS.castStringToJSString(url), - data : data === null ? null : JS.castStringToJSString(data), - headers : headers }; }; }; }; - } - - function registerReq(queue,responses) { return function(req) { - if (req.url !== "") { sendReq(queue,responses,req); } - }; - } - - function updateQueue(queue,responses) { - if (queue.length > 0) { - Dispatcher.notify(responses.id, queue[0].value); - if (queue[0].value[0] !== "Waiting") { - queue.shift(); - setTimeout(function() { updateQueue(queue,responses); }, 0); - } - } - } - - function sendReq(queue,responses,req) { - var response = { value: ["Waiting"] }; - queue.push(response); - - var request = null; - if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } - if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } - request.onreadystatechange = function(e) { - if (request.readyState === 4) { - response.value = (request.status === 200 - ? ["Success", toElmString(request.responseText)] - : ["Failure", request.status, - toElmString(request.statusText)]); - setTimeout(function() { updateQueue(queue,responses); }, 0); - } - }; - request.open(req.verb, req.url, true); - Elm.List.map(function(pair) { - request.setRequestHeader( - JS.castStringToJSString(pair[1]), - JS.castStringToJSString(pair[2])); - })(req.headers); - request.send(req.data); - return null; - } - - /*[Responses]*/ - - /** data Response a = Waiting | Success a | Failure Int String - The datatype for responses. Success contains only the returned message. - Failures contain both an error code and an error message. - **/ - - /*[Sending Requests]*/ - - /** send : Signal (Request a) -> Signal (Response String) - Performs an HTTP request with the given requests. Produces a signal - that carries the responses. - **/ - function send(requests) { - var responses = Elm.Signal.constant(["Waiting"]); - var sender = Elm.Signal.lift(registerReq([],responses))(requests); - function f(x) { return function(y) { return x; } } - return Elm.Signal.lift2(f)(responses)(sender); - } - - /** sendGet : Signal String -> Signal (Response String) - Performs an HTTP GET request with the given urls. Produces a signal - that carries the responses. - **/ - - return {get : get, - post : post, - request : request, - send : send, - sendGet : function(urls){return send(Elm.Signal.lift(get)(urls));} - }; -}(); diff --git a/core-js/Signal/Input.js b/core-js/Signal/Input.js deleted file mode 100644 index daa02f4..0000000 --- a/core-js/Signal/Input.js +++ /dev/null @@ -1,84 +0,0 @@ - -Elm.Input = function() { - var JS = Elm.JavaScript; - var toElmString = Elm.JavaScript.castJSStringToString; - var newTextInput = function(elem, ghostText) { - elem.placeholder = JS.castStringToJSString(ghostText); - var str = Elm.Signal.constant(["Nil"]); - Value.addListener(elem, 'keyup', function(e) { - Dispatcher.notify(str.id, toElmString(elem.value)); - elem.focus(); - }); - elem.style.padding = "1px"; - return Value.Tuple(Value.wrap(elem), str); - }; - var newElement = function(name) { - var e = document.createElement(name); - e.style.padding = "0"; - e.style.margin = "0"; - return e; - }; - var textArea = function(cols) { return function(rows) { - var textarea = newElement('textarea'); - textarea.rows = rows; - textarea.cols = cols; - return newTextInput(textarea, ""); - }; - }; - var textField = function(ghostText) { - var field = newElement('input'); - field.type = 'text'; - return newTextInput(field, ghostText); - }; - var password = function(ghostText) { - var field = newElement('input'); - field.type = 'password'; - return newTextInput(field, ghostText); - }; - var checkbox = function(checked) { - var box = newElement('input'); - box.type = 'checkbox'; - box.checked = checked; - var status = Elm.Signal.constant(checked); - Value.addListener(box, 'change', function(e) { - Dispatcher.notify(status.id, box.checked); - }); - return Value.Tuple(Value.wrap(box), status); - }; - var dropDown = function(options) { - var slct = newElement('select'); - var opts = []; - while (options[0] === "Cons") { - var opt = newElement('option'); - var str = Value.toText(options[1][1]); - opt.value = str; - opt.innerHTML = str; - slct.appendChild(opt); - opts.push(options[1][2]); - options = options[2]; - } - var status = Elm.Signal.constant(opts[0]); - Value.addListener(slct, 'change', function(e) { - Dispatcher.notify(status.id, opts[slct.selectedIndex]); - }); - return Value.Tuple(Value.wrap(slct), status); - }; - var stringDropDown = function(opts) { - return dropDown(Elm.List.map (function(x) {return Value.Tuple(x,x);}) (opts)); - }; - var button = function(name) { - var b = newElement('button'); - b.type = "button"; - b.innerText = JS.castStringToJSString(name); - var press = Elm.Signal.constant(false); - Value.addListener(b, 'click', function(e) { - Dispatcher.notify(press.id, true); - Dispatcher.notify(press.id, false); - }); - return Value.Tuple(Value.wrap(b),press); - }; - return {textArea:textArea, textField:textField, - password:password, checkbox:checkbox, - dropDown:dropDown, stringDropDown:stringDropDown, - button:button}; -}(); diff --git a/core-js/Signal/Keyboard.js b/core-js/Signal/Keyboard.js deleted file mode 100644 index 082d91f..0000000 --- a/core-js/Signal/Keyboard.js +++ /dev/null @@ -1,123 +0,0 @@ - -Elm.Keyboard = { Raw : function() { - var keysDown = Elm.Signal.constant(["Nil"]); - var charPressed = Elm.Signal.constant(["Nothing"]); - - function remove(x,xs) { - if (xs[0] === "Nil") return xs; - if (xs[1] === x) return xs[2]; - return ["Cons", xs[1], remove(x,xs[2])]; - } - function has(x,xs) { - while (xs[0] !== "Nil") { - if (xs[1] === x) return true; - xs = xs[2]; - } - return false; - } - Value.addListener(document, 'keydown', function(e) { - if (has(e.keyCode, keysDown.value)) return; - var hasListener = Dispatcher.notify(keysDown.id, ["Cons", e.keyCode, keysDown.value]); - if (!hasListener) - this.removeEventListener('keydown',arguments.callee,false); - }); - Value.addListener(document, 'keyup', function(e) { - var codes = remove(e.keyCode, keysDown.value); - var hasListener = Dispatcher.notify(keysDown.id, codes); - if (!hasListener) - this.removeEventListener('keyup',arguments.callee,false); - }); - Value.addListener(window, 'blur', function(e) { - var hasListener = Dispatcher.notify(keysDown.id, ["Nil"]); - if (!hasListener) - this.removeEventListener('blur',arguments.callee,false); - }); - Value.addListener(document, 'keypress', function(e) { - var hasListener = Dispatcher.notify(charPressed.id, ["Just",e.charCode || e.keyCode]); - Dispatcher.notify(charPressed.id, ["Nothing"]); - if (!hasListener) - this.removeEventListener('keypress',arguments.callee,false); - }); - return {keysDown:keysDown, - charPressed:charPressed}; - }() -}; - -/*! Keyboard -These are nicely curated inputs from the keyboard. See the -[Keyboard.Raw library](/docs/Signal/KeyboardRaw.elm) for a -lower-level interface that will let you define more complicated behavior. -!*/ - -(function() { - function keySignal(f) { - var signal = Elm.Signal.lift(f)(Elm.Keyboard.Raw.keysDown); - Elm.Keyboard.Raw.keysDown.defaultNumberOfKids += 1; - signal.defaultNumberOfKids = 0; - return signal; - } - - function dir(left,right,up,down) { - function f(ks) { - var x = 0, y = 0; - while (ks[0] == "Cons") { - switch (ks[1]) { - case left : --x; break; - case right: ++x; break; - case up : ++y; break; - case down : --y; break; - } - ks = ks[2]; - } - return { _:[true], x:[x], y:[y] }; - } - return keySignal(f); - } - - function is(key) { - function f(ks) { - while (ks[0] == "Cons") { - if (key == ks[1]) return true; - ks = ks[2]; - } - return false; - } - return keySignal(f); - } - - /*[Directions]*/ - - /** arrows : Signal { x:Int, y:Int } - A signal of records indicating which arrow keys are pressed. - - `{ x = 0, y = 0 }` when pressing no arrows. - `{ x =-1, y = 0 }` when pressing the left arrow. - `{ x = 1, y = 1 }` when pressing the up and right arrows. - `{ x = 0, y =-1 }` when pressing the down, left, and right arrows. - **/ - Elm.Keyboard.arrows = dir(37,39,38,40); - - /** wasd : Signal { x:Int, y:Int } - Just like the arrows signal, but this uses keys w, a, s, and d, - which are common controls for many computer games. - **/ - Elm.Keyboard.wasd = dir(65,68,87,83); - - /*[Modifiers]*/ - - /** shift : Signal Bool - Whether the shift key is pressed. - **/ - Elm.Keyboard.shift = is(16); - - /** ctrl : Signal Bool - Whether the control key is pressed. - **/ - Elm.Keyboard.ctrl = is(17); - - /** space : Signal Bool - Whether the space key is pressed. - **/ - Elm.Keyboard.space = is(32); - -}()); diff --git a/core-js/Signal/Mouse.js b/core-js/Signal/Mouse.js deleted file mode 100644 index 2645ea9..0000000 --- a/core-js/Signal/Mouse.js +++ /dev/null @@ -1,106 +0,0 @@ -/*! Mouse - !*/ - -Elm.Mouse = function() { - /*[Position]*/ - - /** position : Signal (Int,Int) - The current mouse position. - **/ - var position = Elm.Signal.constant(Value.Tuple(0,0)); - position.defaultNumberOfKids = 2; - - /** x : Signal Int - The current x-coordinate of the mouse. - **/ - var x = Elm.Signal.lift(function(p){return p[1];})(position); - x.defaultNumberOfKids = 0; - - /** y : Signal Int - The current y-coordinate of the mouse. - **/ - var y = Elm.Signal.lift(function(p){return p[2];})(position); - y.defaultNumberOfKids = 0; - - /*[Button Status]*/ - - /** isDown : Signal Bool - The current state of the left mouse-button. - True when the button is down, and false otherwise. - **/ - var isDown = Elm.Signal.constant(false); - - /** isClicked : Signal Bool - True immediately after the left mouse-button has been clicked, - and false otherwise. - **/ - var isClicked = Elm.Signal.constant(false); - - /** clicks : Signal () - Always equal to unit. Event triggers on every mouse click. - **/ - var clicks = Elm.Signal.constant(Value.Tuple()); - - function getXY(e) { - var posx = 0; - var posy = 0; - if (!e) e = window.event; - if (e.pageX || e.pageY) { - posx = e.pageX; - posy = e.pageY; - } else if (e.clientX || e.clientY) { - posx = e.clientX + document.body.scrollLeft + - document.documentElement.scrollLeft; - posy = e.clientY + document.body.scrollTop + - document.documentElement.scrollTop; - } - return Value.Tuple(posx, posy); - } - - Value.addListener(document, 'click', function(e) { - var hasListener1 = Dispatcher.notify(isClicked.id, true); - var hasListener2 = Dispatcher.notify(clicks.id, Value.Tuple()); - Dispatcher.notify(isClicked.id, false); - if (!hasListener1 && !hasListener2) - this.removeEventListener('click',arguments.callee,false); - }); - Value.addListener(document, 'mousedown', function(e) { - var hasListener = Dispatcher.notify(isDown.id, true); - if (!hasListener) - this.removeEventListener('mousedown',arguments.callee,false); - }); - Value.addListener(document, 'mouseup', function(e) { - var hasListener = Dispatcher.notify(isDown.id, false); - if (!hasListener) - this.removeEventListener('mouseup',arguments.callee,false); - }); - Value.addListener(document, 'mousemove', function(e) { - var hasListener = Dispatcher.notify(position.id, getXY(e)); - if (!hasListener) - this.removeEventListener('mousemove',arguments.callee,false); - }); - - /** isClickedOn : Element -> (Element, Signal Bool) - Determine whether an element has been clicked. The resulting pair - is a signal of booleans that is true when its paired element has - been clicked. The signal is True immediately after the left - mouse-button has been clicked, and false otherwise. - **/ - var clickedOn = function(elem) { - var node = Render.render(elem); - var click = Elm.Signal.constant(false); - Value.addListener(node, 'click', function(e) { - Dispatcher.notify(click.id, true); - Dispatcher.notify(click.id, false); - }); - return Value.Tuple(Value.wrap(node), click); - }; - return {position: position, - x:x, - y:y, - isClicked: isClicked, - isDown: isDown, - clicks: clicks, - isClickedOn: clickedOn - }; - }(); \ No newline at end of file diff --git a/core-js/Signal/Random.js b/core-js/Signal/Random.js deleted file mode 100644 index 81b084f..0000000 --- a/core-js/Signal/Random.js +++ /dev/null @@ -1,29 +0,0 @@ -/*! Random - !*/ - -Elm.Random = function() { - /*[In a Range]*/ - - /** inRange : Int -> Int -> Signal Int - Given a range from low to high, this produces a random number - between 'low' and 'high' inclusive. The value in the signal does - not change after the page has loaded. - **/ - var inRange = function(min) { return function(max) { - return Elm.Signal.constant(Math.floor(Math.random() * (max-min+1)) + min); - }; - }; - - /** randomize : Int -> Int -> Signal a -> Signal Int - Given a range from low to high and a signal of values, this produces - a new signal that changes whenever the input signal changes. The new - values are random number between 'low' and 'high' inclusive. - **/ - var randomize = function(min) { return function(max) { return function(signal) { - function f(x) { return Math.floor(Math.random() * (max-min+1)) + min; } - return Elm.Signal.lift(f)(signal); - }; - }; - }; - return { inRange:inRange, randomize:randomize }; -}(); \ No newline at end of file diff --git a/core-js/Signal/Time.js b/core-js/Signal/Time.js deleted file mode 100644 index 5d68643..0000000 --- a/core-js/Signal/Time.js +++ /dev/null @@ -1,112 +0,0 @@ -/*! Time -Library for working with time. Type `Time` represents some number of -milliseconds. -!*/ - -Elm.Time = function() { - - /*[Times]*/ - - /** hour, minute, second, ms : Time - Units of time, making it easier to specify things like a - half-second `(second / 2)`. - **/ - - function timeNow() { return (new window.Date).getTime(); } - - /*[Tickers]*/ - - /** fps : Number -> Signal Time - Takes desired number of frames per second (fps). The resulting signal - gives a sequence of time deltas as quickly as possible until it reaches - the desired FPS. A time delta is the time between the last frame and the - current frame. - **/ - - /** fpsWhen : Number -> Signal Bool -> Signal Time - Same as the fps function, but you can turn it on and off. Allows you - to do brief animations based on user input without major ineffeciencies. - The first time delta after a pause is always zero, no matter how long - the pause was. This way summing the deltas will actually give the amount - of time that the output signal has been running. - **/ - function fpsWhen(desiredFPS) { return function (isOn) { - var msPerFrame = 1000 / desiredFPS; - var prev = timeNow(), curr = prev, diff = 0, wasOn = true; - var ticker = Elm.Signal.constant(diff); - function tick(zero) { return function() { - curr = timeNow(); - diff = zero ? 0 : curr - prev; - prev = curr; - Dispatcher.notify(ticker.id, diff); - }; - } - var timeoutID = 0; - function f(isOn) { return function(t) { - if (isOn) { - timeoutID = setTimeout(tick(!wasOn && isOn), msPerFrame); - } else if (wasOn) { - clearTimeout(timeoutID); - } - wasOn = isOn; - return t; - }; - } - return Elm.Signal.lift2(f)(isOn)(ticker); - }; - } - - /** every : Time -> Signal Time - Takes a time interval t. The resulting signal is the current time, - updated every t. - **/ - function everyWhen(isOn) { return function(t) { - var clock = Elm.Signal.constant(timeNow()); - function tellTime() { Dispatcher.notify(clock.id, timeNow()); } - setInterval(tellTime, t); - return clock; - }; - } - - function since(t) { return function(s) { - function cmp(a) { return function(b) { return !Value.eq(a,b); }; } - var dcount = Elm.Signal.count(Elm.Signal.delay(t)(s)); - return Elm.Signal.lift2(cmp)(Elm.Signal.count(s))(dcount); - }; - } - function after(t) { - t *= 1000; - var thread = Elm.Signal.constant(false); - setTimeout(function() { Dispatcher.notify(thread.id, true); }, t); - return thread; - } - function before(t) { - t *= 1000; - var thread = Elm.Signal.constant(true); - setTimeout(function() { Dispatcher.notify(thread.id, false); }, t); - return thread; - } - function read(s) { - var t = window.Date.parse(s); - return isNaN(t) ? ["Nothing"] : ["Just",t]; - } - return {fpsWhen : fpsWhen, - fps : function(t) { return fpsWhen(t)(Elm.Signal.constant(true)); }, - every : everyWhen(Elm.Signal.constant(true)), - delay : Elm.Signal.delay, - since : since, - after : after, - before : before, - hour : 3600000, - minute : 60000, - second : 1000, - ms : 1, - inHours : function(t) { return t / 3600000; }, - inMinutes : function(t) { return t / 60000; }, - inSeconds : function(t) { return t / 1000; }, - inMss : function(t) { return t; }, - toDate : function(t) { return new window.Date(t); }, - read : read - }; - -}(); \ No newline at end of file diff --git a/core-js/Signal/Touch.js b/core-js/Signal/Touch.js deleted file mode 100644 index 81a29b0..0000000 --- a/core-js/Signal/Touch.js +++ /dev/null @@ -1,109 +0,0 @@ -/*! Touch -This is an early version of the touch library. It will likely grow to -include gestures that would be useful for both games and web-pages. -!*/ - -Elm.Touch = function() { - - function Dict() { - this.keys = []; - this.values = []; - - this.insert = function(key,value) { - this.keys.push(key); - this.values.push(value); - }; - this.lookup = function(key) { - var i = this.keys.indexOf(key) - return i >= 0 ? this.values[i] : {x:0,y:0,t:0}; - }; - this.remove = function(key) { - var i = this.keys.indexOf(key); - if (i < 0) return; - var t = this.values[i]; - this.keys.splice(i,1); - this.values.splice(i,1); - return t; - }; - } - - var root = Elm.Signal.constant([]), - tapTime = 500, - hasTap = false, - tap = {_:[true],x:[0],y:[0]}, - dict = new Dict(); - - function touch(t) { - var r = dict.lookup(t.identifier); - return {_ : [true], id: [t.identifier], - x: [t.pageX], y: [t.pageY], - x0: [r.x], y0: [r.y], - t0: [r.t] }; - } - - function start(e) { - dict.insert(e.identifier,{x:e.pageX,y:e.pageY,t:Date.now()}); - } - function end(e) { - var t = dict.remove(e.identifier); - if (Date.now() - t.t < tapTime) { - hasTap = true; - tap = {_:[true], x:[t.x], y:[t.y]}; - } - } - - function listen(name, f) { - function update(e) { - for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); } - var ts = new Array(e.touches.length); - for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); } - var hasListener = Dispatcher.notify(root.id, ts); - if (!hasListener) return document.removeEventListener(name, update); - e.preventDefault(); - } - Value.addListener(document, name, update); - } - - listen("touchstart", start); - listen("touchmove", function(_){}); - listen("touchend", end); - listen("touchcancel", end); - listen("touchleave", end); - - function dependency(f) { - var sig = Elm.Signal.lift(f)(root); - root.defaultNumberOfKids += 1; - sig.defaultNumberOfKids = 0; - return sig; - } - - /*[Touches]*/ - - /** touches : Signal [{ x:Int, y:Int, id:Int, x0:Int, y0:Int, t0:Time }] - A list of touches. Each ongoing touch is represented by a set of - coordinates and an identifier id that allows you to distinguish - between different touches. Each touch also contains the coordinates and - time of the initial contact (x0, y0, and t0) which helps compute more - complicated gestures. - **/ - var touches = dependency(function(ts) { - return Elm.JavaScript.castJSArrayToList(ts); - }); - - /*[Gestures]*/ - - /** taps : Signal { x:Int, y:Int } - The last position that was tapped. Default value is `{x=0,y=0}`. - Updates whenever the user taps the screen. - **/ - var taps = function() { - var sig = dependency(function(_) { return tap; }); - sig.defaultNumberOfKids = 1; - function pred(_) { var b = hasTap; hasTap = false; return b; } - var sig2 = Elm.Signal.keepIf(pred)({_:[true],x:[0],y:[0]})(sig); - sig2.defaultNumberOfKids = 0; - return sig2; - }(); - - return { touches: touches, taps: taps }; -}(); \ No newline at end of file diff --git a/core-js/Signal/WebSocket.js b/core-js/Signal/WebSocket.js deleted file mode 100644 index 48e8671..0000000 --- a/core-js/Signal/WebSocket.js +++ /dev/null @@ -1,41 +0,0 @@ -/*! WebSocket -A library for low latency HTTP communication. See the HTTP library for standard -requests like GET, POST, etc. -!*/ - -Elm.WebSocket = function() { - var JS = Elm.JavaScript; - - /** open : String -> Signal String -> Signal String - Create a web-socket. The first argument is the URL of the desired - web-socket server. The input signal holds the outgoing messages, - and the resulting signal contains the incoming ones. - **/ - function open(url) { return function(outgoing) { - var incoming = Elm.Signal.constant(["Nil"]); - var ws = new window.WebSocket(JS.castStringToJSString(url)); - - var pending = []; - var ready = false; - - ws.onopen = function(e) { - var len = pending.length; - for (var i = 0; i < len; ++i) { ws.send(pending[i]); } - ready = true; - }; - ws.onmessage = function(event) { - Dispatcher.notify(incoming.id, JS.castJSStringToString(event.data)); - }; - - function send(msg) { - var s = JS.castStringToJSString(msg); - ready ? ws.send(s) : pending.push(s); - } - - function take1(x) { return function(y) { return x; } } - return Elm.Signal.lift2(take1)(incoming)(Elm.Signal.lift(send)(outgoing)); - }; - } - - return {open:open}; -}(); diff --git a/core-js/Signal/Window.js b/core-js/Signal/Window.js deleted file mode 100644 index ada6f50..0000000 --- a/core-js/Signal/Window.js +++ /dev/null @@ -1,35 +0,0 @@ -/*! Window !*/ - -Elm.Window = function() { - - /*[Dimensions]*/ - - /** dimensions : Signal (Int,Int) - The current dimensions of the window (i.e. the area viewable to the - user, not including scroll bars). - **/ - var dimensions = Elm.Signal.constant(Value.Tuple(window.innerWidth, - window.innerHeight)); - dimensions.defaultNumberOfKids = 2; - - /** width : Signal Int - The current width of the window. - **/ - var width = Elm.Signal.lift(function(p){return p[1];})(dimensions); - width.defaultNumberOfKids = 0; - - /** height : Signal Int - The current height of the window. - **/ - var height = Elm.Signal.lift(function(p){return p[2];})(dimensions); - height.defaultNumberOfKids = 0; - - Value.addListener(window, 'resize', function(e) { - var w = document.getElementById('widthChecker').offsetWidth; - var hasListener = Dispatcher.notify(dimensions.id, - Value.Tuple(w, window.innerHeight)); - if (!hasListener) - this.removeEventListener('resize',arguments.callee,false); - }); - return {dimensions:dimensions,width:width,height:height}; -}(); diff --git a/core-js/String.js b/core-js/String.js deleted file mode 100644 index 0202723..0000000 --- a/core-js/String.js +++ /dev/null @@ -1,81 +0,0 @@ - -/* -var String = function() { - - function append(s1) { return function(s2) { - return s1.concat(s2); - }; - } - function map(f) { return function(s) { - for (var i = s.length; i--; ) { s[i] = f(s[i]); } - }; - } - - function intercalate(sep) { return function(ss) { - return Value.listToArray(ss).join(sep); - }; - } - function intersperse(sep) { return function(s) { - return s.split("").join(sep); - }; - } - - function foldl(f) { return function(b) { return function(s) { - var acc = b; - for (var i = 0, len = s.length; i < len; ++i) { acc = f(s[i])(acc); } - return acc; - }; - }; - } - function foldr(f) { return function(b) { return function(s) { - var acc = b; - for (var i = s.length; i--; ) { acc = f(s[i])(acc); } - return acc; - }; - }; - } - - function concatMap(f) { return function(s) { - var a = s.split(""); - for (var i = a.length; i--; ) { a[i] = f(a[i]); } - return a.join(""); - }; - } - - function forall(pred) { return function(s) { - for (var i = s.length; i--; ) { if (!pred(s[i])) {return false}; } - return true; - }; - } - function exists(pred) { return function(s) { - for (var i = s.length; i--; ) { if (pred(s[i])) {return true}; } - return false; - }; - } - - return {cons : append, - snoc : append, - head : function(s) { return s[0]; }, - last : function(s) { return s[s.length-1]; }, - tail : function(s) { return s.slice(1); }, - length : function(s) { return s.length; }, - map : map, - intercalate : intercalate, - intersperse : intersperse, - reverse : function(s) { return s.split("").reverse().join(""); }, - toLower : function(s) { return s.toLowerCase(); }, - toUpper : function(s) { return s.toUpperCase(); }, - foldl : foldl, - foldr : foldr, - concat : function(ss) { return Value.listToArray(ss).join(""); }, - concatMap : concatMap, - forall : forall, - exists : exists, - //filter : filter, - //take:, - //drop:, - toText : Value.toText, - properEscape : Value.properEscape - }; -}(); -*/ diff --git a/core-js/Text.js b/core-js/Text.js deleted file mode 100644 index 11fd6e3..0000000 --- a/core-js/Text.js +++ /dev/null @@ -1,49 +0,0 @@ - -Elm.Text = function() { - function fromString(s) { return Value.toText(s); } - - var addTag = function(tag) { return function(text) { - return '<' + tag + ' style="padding:0;margin:0">' + text + '</' + tag + '>'; - }; - }; - var addStyle = function(style, value) { return function(text) { - return "<span style='" + style + ":" + value + "'>" + text + "</span>"; - }; - }; - - var typeface = function(name) { - name = Elm.JavaScript.castStringToJSString(name); - return addStyle('font-family', name); - }; - var size = function(px) { - return addStyle('font-size', px + 'px'); - }; - var header = addTag('h1'); - var height = function(h) { return addStyle('font-size', h+'em'); } - var italic = addStyle('font-style', 'italic'); - var bold = addTag('b'); - var color = function(c) { - return addStyle('color', Elm.Color.extract(c)); - }; - var underline = addStyle('text-decoration', 'underline'); - var overline = addStyle('text-decoration', 'overline'); - var strikeThrough = addStyle('text-decoration', 'line-through'); - var link = function(href) { return function(text) { - return "<a href='" + fromString(href) + "'>" + text + "</a>"; - }; - }; - - return {fromString : fromString, - toText: fromString, - header : header, - height : height, - italic : italic, - bold : bold, - underline : underline, - overline : overline, - strikeThrough : strikeThrough, - monospace : typeface('monospace'), - typeface : typeface, - color : color, - link : link }; -}(); diff --git a/core-js/Value.js b/core-js/Value.js deleted file mode 100644 index 716632a..0000000 --- a/core-js/Value.js +++ /dev/null @@ -1,291 +0,0 @@ - -var Value = function(){ - - var eq = function(x,y) { - if (typeof x === "object") { - if (x !== null && '_' in x) { - for (var i in x) { if (x[i] != y[i]) return false; } - for (var i in y) { if (!(i in x)) return false; } - return true; - } - if (x === y) return true; - if (x.length !== y.length) return false; - for (var i = x.length; i--; ) { - if (!eq(x[i],y[i])) return false; - } - return true; - } - return x === y; - }; - - var Tuple = function() { - var len = arguments.length; - var arr = new Array(len+1); - arr[0] = "Tuple" + arguments.length; - for (var i = len; i--; ) { - arr[i+1] = arguments[i]; - } - return arr; - }; - - var listToArray = function(list) { - var arr = []; - while (list[0] === "Cons") { - arr.push(list[1]); - list = list[2]; - } - return arr; - }; - - function makeSpaces(s) { - if (s.length == 0) { return s; } - var arr = s.split(''); - if (arr[0] == ' ') { arr[0] = " " } - for (var i = arr.length; --i; ) { - if (arr[i][0] == ' ' && arr[i-1] == ' ') { - arr[i-1] = arr[i-1] + arr[i]; - arr[i] = ''; - } - } - for (var i = arr.length; i--; ) { - if (arr[i].length > 1 && arr[i][0] == ' ') { - var spaces = arr[i].split(''); - for (var j = spaces.length - 2; j >= 0; j -= 2) { - spaces[j] = ' '; - } - arr[i] = spaces.join(''); - } - } - arr = arr.join(''); - if (arr[arr.length-1] === " ") { - return arr.slice(0,-1) + ' '; - } - return arr; - } - - function properEscape(str) { - if (str.length == 0) return str; - str = str //.replace(/&/g, "&") - .replace(/"/g, /*"*/ """) - .replace(/'/g, /*'*/ "'") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/\n/g, "<br/>"); - var arr = str.split('<br/>'); - for (var i = arr.length; i--; ) { - arr[i] = makeSpaces(arr[i]); - } - return arr.join('<br/>'); - } - - var toText = function(elmList) { - if (typeof elmList === "string") return properEscape(elmList); - var a = []; - while (elmList[0] === "Cons") { - a.push(elmList[1]); - elmList = elmList[2]; - } - return properEscape(a.join('')); - }; - - function getTextSize(w,h,txt) { - var t = document.createElement('div'); - t.innerHTML = txt; - t.style.textAlign = 'left'; - if (w > 0) { t.style.width = w + "px"; } - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var cStyle = window.getComputedStyle(t,null); - var realW = cStyle.getPropertyValue("width").slice(0,-2) - 0; - var realH = cStyle.getPropertyValue("height").slice(0,-2) - 0; - document.body.removeChild(t); - //delete t; - return [Math.ceil(realW),Math.ceil(Math.max(h,realH))]; - } - - function getSize(e) { - var t = e.cloneNode(true); - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var w = t.offsetWidth; - var h = t.offsetHeight; - document.body.removeChild(t); - //delete t; - return [w,h]; - } - - function getExcess(e) { - var t = e.cloneNode(true); - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var ow = t.offsetWidth; - var oh = t.offsetHeight; - var cStyle = window.getComputedStyle(t,null); - var w = cStyle.getPropertyValue("width").slice(0,-2) - 0; - var h = cStyle.getPropertyValue("height").slice(0,-2) - 0; - document.body.removeChild(t); - //delete t; - return [ow-w,oh-h]; - } - - - function groupForms(forms) { - forms = Elm.JavaScript.castListToJSArray(forms); - var groups = []; - var arr = []; - for (var i = forms.length; i--; ) { - var f = forms[i]; - switch(f[4][0]) { - case "FElement": - if (arr.length > 0) { - groups.push(arr); - arr = []; - } - groups.push(f); - break; - default: - arr.push(f); - } - } - if (arr.length > 0) groups.push(arr); - return groups; - } - - var toString = function(v) { - if (typeof v === "function") { - return "<function>"; - } else if (typeof v === "boolean") { - return v ? "True" : "False"; - } else if (typeof v === "number") { - return v+""; - } else if (typeof v === "string" && v.length < 2) { - return "'"+v+"'"; - } else if (typeof v === "object" && ('_' in v)) { - var output = []; - for (var k in v._) { - console.log(k,v._[k]); - for (var i = v._[k].length; i--; ) { - output.push(k + " = " + toString(v._[k][i])); - } - } - for (var k in v) { - if (k === '_') continue; - output.push(k + " = " + toString(v[k])); - } - if (output.length === 0) return "{}"; - return "{ " + output.join(", ") + " }"; - } else if (v[0]) { - if (v[0].substring(0,5) === "Tuple") { - var output = new Array(v.length-1); - for (var i = v.length; --i; ) { output[i-1] = toString(v[i]); } - return "(" + output.join(",") + ")"; - } else if (v[0] === "Cons") { - var start = (typeof v[1] === "string") ? '"' : "["; - var end = (typeof v[1] === "string") ? '"' : "]"; - var div = (typeof v[1] === "string") ? "" : ","; - var f = (typeof v[1] === "string") ? function(x){return x} : toString; - var output = start + f(v[1]); - v = v[2]; - while (true) { - if (v[0] === "Cons") { - output += div + f(v[1]); - v = v[2]; - } else { - return output + end; - } - } - } else if (v[0] === "Nil") { - return "[]"; - } else if (v[0] === "JSON") { - return "(JSON.fromList " + toString(Elm.JSON.toList(v)) + ")"; - } else if (v[0] === "RBNode" || v[0] === "RBEmpty") { - function cons(k){ return function(v) { return function(acc) { return ["Cons",["Tuple2",k,v],acc]; }; }; } - var list = Elm.Dict.foldr(cons)(["Nil"])(v); - var name = "Dict"; - if (list[0] === "Cons" && list[1][2][0] === "Tuple0") { - name = "Set"; - list = Elm.List.map(function(x) { return x[1]; })(list); - } - return "(" + name + ".fromList " + toString(list) + ")"; - } else { - var output = ""; - for (var i = v.length; --i; ) { output = ' ' + toString(v[i]) + output; } - output = v[0] + output; - return (v.length > 1) ? "(" + output + ")" : output; - } - } - return v+""; - }; - var show = function(v) { return str(toString(v)); }; - var append = function(xs,ys) { - if (typeof xs === "string" && typeof ys === "string") { - return xs.concat(ys); - } - if (xs[0] === "Nil") { - return ys; - } - var root = ["Cons", xs[1], ["Nil"]]; - var curr = root; - xs = xs[2]; - while (xs[0]==="Cons") { - curr[2] = ["Cons", xs[1], ["Nil"]]; - xs = xs[2]; - curr = curr[2]; - } - curr[2] = ys; - return root; - }; - - var str = function(s) { - var out = ["Nil"]; - for (var i = s.length; i--; ) { - out = ["Cons", s[i], out]; - } - return out; - }; - - function wrap(elem) { - var p = Value.getSize(elem); - return ["Element", Guid.guid(), ["EHtml",elem], - p[0], p[1], 1, ["Nothing"], ["Nothing"]]; - } - var addListener = function() { - if(document.addEventListener) { - return function(element, event, handler) { - element.addEventListener(event, handler, false); - }; - } else { - return function(element, event, handler) { - element.attachEvent('on' + event, handler); - }; - } - }(); - - return {eq:eq, - str:str, - show:show, - Tuple:Tuple, - append:append, - listToArray:listToArray, - toText : toText, - properEscape : properEscape, - getTextSize : getTextSize, - getSize : getSize, - getExcess : getExcess, - groupForms : groupForms, - wrap : wrap, - addListener : addListener - }; -}(); \ No newline at end of file diff --git a/core-js/cat.bat b/core-js/cat.bat deleted file mode 100644 index ebd8280..0000000 --- a/core-js/cat.bat +++ /dev/null @@ -1,5 +0,0 @@ -copy /B Guid.js+foreign\JavaScript.js+foreign\JSON.js+Value.js+List.js+Maybe.js+Either.js+Char.js+Graphics\Color.js+Graphics\Collage.js+Graphics\Element.js+Text.js+Graphics\Render.js+runtime\Signal.js+runtime\Dispatcher.js+Signal\HTTP.js+Signal\WebSocket.js+Signal\Input.js+Signal\Keyboard.js+Signal\Mouse.js+Signal\Random.js+Signal\Time.js+Signal\Window.js+Date.js+Prelude.js+Signal\Touch.js+Dict.js+Set.js+Automaton.js ..\elm-mini.js - -cd ..\elm - -copy /B ..\elm-mini.js elm-runtime-0.7.2.js diff --git a/core-js/cat.sh b/core-js/cat.sh deleted file mode 100755 index bd7f823..0000000 --- a/core-js/cat.sh +++ /dev/null @@ -1,33 +0,0 @@ -# I do not use this script, so it may be out of date. -# Please make sure that this matches with cat.bat to -# avoid confusing "errors". - -cat \ - Guid.js\ - foreign/JavaScript.js\ - List.js\ - Maybe.js\ - foreign/JSON.js\ - Value.js\ - Char.js\ - Graphics/Color.js\ - Graphics/Collage.js\ - Graphics/Element.js\ - Text.js\ - Graphics/Render.js\ - runtime/Signal.js\ - runtime/Dispatcher.js\ - Signal/HTTP.js\ - Signal/Input.js\ - Signal/Keyboard.js\ - Signal/Mouse.js\ - Signal/Random.js\ - Signal/Time.js\ - Signal/Window.js\ - Date.js\ - Prelude.js\ - Dict.js\ - Set.js\ - Automaton.js\ - Signal/WebSocket.js\ - > ../elm/elm-runtime.js diff --git a/core-js/collage/Color.js b/core-js/collage/Color.js deleted file mode 100644 index 001c7e1..0000000 --- a/core-js/collage/Color.js +++ /dev/null @@ -1,42 +0,0 @@ - -var Color = function() { - - var create = function(r,g,b,a) { - return { r: r, - g: g, - b: b, - a: a }; - }; - - var extract = function(c) { - if (c.a === 1) { - return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')'; - } - return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')'; - }; - - var rgba = function(r) { return function(g) { return function(b) { - return function(a) { return create(r,g,b,a); }; }; }; - }; - - var rgb = function(r) { return function(g) { return function(b) { - return create(r,g,b,1); }; }; - }; - return {black: create( 0, 0, 0,1), - white: create(255,255,255,1), - red : create(255, 0, 0,1), - green: create( 0,255, 0,1), - blue : create( 0, 0,255,1), - - gray : create(128,128,128,1), - grey : create(128,128,128,1), - - yellow : create(255,255, 0,1), - cyan : create( 0,255,255,1), - magenta : create(255, 0,255,1), - - rgba : rgba, - rgb : rgb, - Internal : { extract:extract } - }; -}(); \ No newline at end of file diff --git a/core-js/collage/Form.js b/core-js/collage/Form.js deleted file mode 100644 index 7e7ba03..0000000 --- a/core-js/collage/Form.js +++ /dev/null @@ -1,33 +0,0 @@ - -var Form = function() { - var move = function(x) { return function(y) { return function(form) { - var t = form[1]; - return [form[0], [[x + t[0][0], y + t[0][1]], t[1], t[2]]]; - }; - }; - }; - var rotate = function(theta) { return function(form) { - var t = form[1]; - return [form[0], [t[0], t[1] + 2* Math.PI*theta, t[2]]]; - }; - }; - var scale = function(s) { return function(form) { - var t = form[1]; - return [form[0], [t[0], t[1], t[2] * s]]; - }; - }; - var create = function(howToDraw, center) { - return [howToDraw, Transforms.create(center, 0, 1)]; - }; - var draw = function(form) { - ctx.save(); - var trans = form[1]; - ctx.translate(trans[0][0], trans[0][1]); - ctx.rotate(trans[1]); - ctx.scale(trans[2], trans[2]); - form[0](ctx); - ctx.restore(); - return ctx; - }; - return {create:create, move:move, rotate:rotate, scale:scale, draw:draw}; -}(); \ No newline at end of file diff --git a/core-js/collage/Image.js b/core-js/collage/Image.js deleted file mode 100644 index 22db368..0000000 --- a/core-js/collage/Image.js +++ /dev/null @@ -1,9 +0,0 @@ - -var Image = function() { - var image = function(src) { - var img = new Image(src); - img.onload = function() { - - }; - }; -}(); diff --git a/core-js/collage/Line.js b/core-js/collage/Line.js deleted file mode 100644 index 334fdb2..0000000 --- a/core-js/collage/Line.js +++ /dev/null @@ -1,103 +0,0 @@ - -var Line = function() { - - var pair = function(a,b) { return [a,b]; }; - - var create = function(center, ps, theta, s) { - return { center: center, points: ps, theta: theta, scale: s }; - }; - - - //// Construction //// - - var line = function(ps) { - var parr = []; - while (ps[0] === "Cons") { - parr.push(pair(ps[1][1], ps[1][2])); - ps = ps[2]; - } - return create(pair(0,0), parr, 0, 1); - }; - - //// Atomize //// - - var solid = function(color) { return function(line) { return function(ctx) { - ctx.save(); - ctx.beginPath(); - ctx.translate(line.center[0], line.center[1]); - ctx.rotate(line.theta); - ctx.scale(line.scale, line.scale); - var points = line.points; - var i = points.length; - ctx.moveTo(points[i-1][0], points[i-1][1]); - while (i--) { - ctx.lineTo(points[i][0], points[i][1]); - } - ctx.strokeStyle = Color.Internal.extract(color); - ctx.stroke(); - ctx.restore(); - return ctx; - }; - }; - }; - - var customLine = function(pattern) { - return function(color) { return function(line) { - if (typeof pattern[0] === "string") { - var temp = []; - while (pattern[0] === "Cons") { - temp.push(pattern[1]); - pattern = pattern[2]; - } - pattern = temp; - } - if (pattern.length === 0) { pattern = [8,4]; } - return function(ctx) { - ctx.save(); - ctx.beginPath(); - ctx.translate(line.center[0], line.center[1]); - ctx.rotate(line.theta); - ctx.scale(line.scale, line.scale); - customLineHelp(ctx, pattern, line.points); - ctx.strokeStyle = Color.Internal.extract(color); - ctx.stroke(); - ctx.restore(); - return ctx; - }; - }; - }; - }; - var customLineHelp = function(ctx, pattern, points) { - var i = points.length - 1; - var x0 = points[i][0], y0 = points[i][1]; - var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0; - var pindex = 0, plen = pattern.length; - var draw = true, segmentLength = pattern[0]; - ctx.moveTo(x0,y0); - while (i--) { - x1 = points[i][0]; y1 = points[i][1]; - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - while (segmentLength <= remaining) { - x0 += dx * segmentLength / remaining; - y0 += dy * segmentLength / remaining; - ctx[draw ? 'lineTo' : 'moveTo'](x0, y0); - // update starting position - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - // update pattern - draw = !draw; - pindex = (pindex + 1) % plen; - segmentLength = pattern[pindex]; - } - if (remaining > 0) { - ctx[draw ? 'lineTo' : 'moveTo'](x1, y1); - segmentLength -= remaining; - } - x0 = x1; y0 = y1; - } - }; - - return {line:line, customLine:customLine, solid:solid, - dashed: customLine([8,4]), dotted: customLine([3,3]) }; -}(); diff --git a/core-js/collage/Shape.js b/core-js/collage/Shape.js deleted file mode 100644 index 8d748b7..0000000 --- a/core-js/collage/Shape.js +++ /dev/null @@ -1,110 +0,0 @@ - -var Shape = function() { - - var create = function(center, ps, theta, s) { - return { center: center, points: ps, theta: theta, scale: s }; - }; - - //// Construction //// - - var polygon = function(ps) { return function(center) { - var parr = []; - while (ps[0] === "Cons") { - parr.push([ps[1][1], ps[1][2]]); - ps = ps[2]; - } - center = [center[1], center[2]]; - return create(center, parr, 0, 1); - }; -}; - var ngon = function(n) { return function(r) { return function(center) { - var ps = []; - for (var i = n; i--;) { - ps.push([r * Math.cos(Math.PI * 2 * i/n), - r * Math.sin(Math.PI * 2 * i/n)]); - } - center = [center[1], center[2]]; - return create(center, ps, 0, 1); - }; - }; -}; - var rect = function(w) { return function(h) { return function(center) { - var ps = [[- w/2, - h/2], - [ w/2, - h/2], - [ w/2, h/2], - [- w/2, h/2]]; - center = [center[1], center[2]]; - return create(center, ps, 0, 1); - }; - }; - }; - var oval = function(w) { return function(h) { return function(center) { - var ps = []; - for (var theta = 2 * Math.PI; theta > 0; theta -= Math.PI /50) { - ps.push([w/2 * Math.cos(theta), h/2 * Math.sin(theta)]); - } - center = [center[1], center[2]]; - return create(center, ps, 0, 1); - }; - }; - }; - -//// Transforms //// - - var move = function(x) { return function(y) { return function(shape) { - var newCenter = [x + shape.center[0],y + shape.center[1]]; - return create(newCenter, shape.points, shape.theta, shape.scale); - }; - }; - }; - var rotate = function(theta) { return function(shape) { - var newTheta = shape.theta + 2 * Math.PI * theta; - return create(shape.center, shape.points, newTheta, shape.scale); - }; - }; - var scale = function(s) { return function(shape) { - return create(shape.center, shape.points, shape.theta, shape.scale * s); - }; - }; - - - //// Atomize //// - - var draw = function(fill) { - return function(color) { return function(shape) { return function(ctx) { - ctx.save(); - ctx.translate(shape.center[0], shape.center[1]); - ctx.rotate(shape.theta); - ctx.scale(shape.scale, shape.scale); - ctx.beginPath(); - var points = shape.points; - ctx.moveTo(points[0][0], points[0][1]); - for (var i = points.length; i--; ) { - ctx.lineTo(points[i][0], points[i][1]); - } - ctx.closePath(); - if (fill) { - ctx.fillStyle = Color.Internal.extract(color); - ctx.fill(); - } else { - ctx.strokeStyle = Color.Internal.extract(color); - ctx.stroke(); - } - ctx.restore(); - return ctx; - }; - }; - }; - }; - - var customOutline = function(p) { - return function(c) { return function(shape) { - shape.points.push(shape.points[0]); - return Line.customLine(p)(c)(shape); - }; - }; - }; - return {polygon:polygon, ngon:ngon, rect:rect, oval:oval, - move:move, rotate:rotate, scale:scale, - filled:draw(true), outlined:draw(false), customOutline:customOutline }; -}(); \ No newline at end of file diff --git a/core-js/foreign/JSON.js b/core-js/foreign/JSON.js deleted file mode 100644 index dd87d00..0000000 --- a/core-js/foreign/JSON.js +++ /dev/null @@ -1,158 +0,0 @@ - -var JSjson = window.JSON; -Elm.JSON = function() { - var JS = Elm.JavaScript; - var empty = ['JSON',{}]; - function singleton(k) { return function(v) { - var obj = {}; - obj[JS.castStringToJSString(k)] = v; - return ['JSON', obj ]; - }; - } - function insert(k) { return function(v) { return function(inObj) { - var obj = inObj[1]; - var outObj = {}; - for (var i in obj) { - outObj[i] = obj[i]; - } - outObj[JS.castStringToJSString(k)] = v; - return ['JSON', outObj ]; - }; - }; - } - - function lookup(key) { return function(obj) { - var k = JS.castStringToJSString(key); - return (k in obj[1]) ? ["Just", obj[1][k]] : ["Nothing"] ; - }; - } - function find(tipe,base) { return function (key) { return function(obj) { - var k = JS.castStringToJSString(key); - if (k in obj[1]) { - var v = obj[1][k]; - if (v[0] === tipe) { return v[1]; } - } - return base; - }; - } - } - function lookupWithDefault(base) { return function(key) { return function(obj) { - var k = JS.castStringToJSString(key); - return (k in obj[1]) ? obj[1][k] : base ; - }; - }; - } - - function remove(k) { return function(inObj) { - var obj = inObj[1]; - var outObj = {}; - for (var i in obj) { - outObj[i] = obj[i]; - } - delete outObj[JS.castStringToJSString(k)]; - return ['JSON', outObj]; - }; - } - - function JsonString(v) { return [ "JsonString", v ]; } - function JsonNumber(v) { return [ "JsonNumber", v ]; } - function JsonBool(v) { return [ "JsonBool", v ]; } - var JsonNull = [ "JsonNull" ]; - function JsonArray(v) { return [ "JsonArray", v ]; } - function JsonObject(v) { return [ "JsonObject", v ]; } - - function toList(json) { - var obj = json[1]; - var arr = []; - for (var i in obj) { - arr.push(Value.Tuple(JS.castJSStringToString(i), obj[i])); - } - return JS.castJSArrayToList(arr); - } - function fromList(list) { - var arr = JS.castListToJSArray(list); - var obj = {}; - for (var i = arr.length; i--; ) { - obj[JS.castStringToJSString(arr[i][1])] = arr[i][2]; - } - return [ "JSON", obj ]; - } - - function toPrettyJSString(sep) { return function (obj) { - function fromValue(v) { - switch (v[0]) { - case 'JsonNull' : return null; - case 'JsonString' : return JS.castStringToJSString(v[1]); - case 'JsonObject' : - var o = {}; - var from = v[1][1]; - for (var i in from) { - o[i] = fromValue(from[i]); - } - return o; - case 'JsonArray' : - var a = JS.castListToJSArray(v[1]); - for (var i = a.length; i--; ) { - a[i] = fromValue(a[i]); - } - return a; - default : - return v[1]; - } - } - return JSjson.stringify(fromValue([ 'JsonObject', obj ]), null, JS.castStringToJSString(sep)); - }; - } - function fromJSString(str) { - var obj; - try { - obj = JSjson.parse(str); - } catch (e) { - return Elm.Maybe.Nothing; - } - function toValue(v) { - switch (typeof v) { - case 'string' : return [ "JsonString", JS.castJSStringToString(v) ]; - case 'number' : return [ "JsonNumber", JS.castJSNumberToFloat(v) ]; - case 'boolean' : return [ "JsonBool", JS.castJSBoolToBool(v) ]; - case 'object' : - if (v === null) return [ "JsonNull" ]; - for (var i in v) { - v[i] = toValue(v[i]); - } - if (v instanceof Array) return [ "JsonArray", JS.castJSArrayToList(v) ]; - return [ "JsonObject", [ "JSON", v ] ]; - } - } - for (var i in obj) { - obj[i] = toValue(obj[i]); - } - return Elm.Maybe.Just( ['JSON',obj] ); - } - return {empty : empty, - singleton : singleton, - insert : insert, - lookup : lookup, - findNumber : find("JsonNumber",0), - findString : find("JsonString",["Nil"]), - findObject : find("JsonObject", empty ), - findArray : find("JsonArray" ,["Nil"]), - findWithDefault : lookupWithDefault, - remove : remove, - toPrettyJSString : toPrettyJSString, - toJSString : toPrettyJSString(''), - fromJSString : fromJSString, - toPrettyString : function(sep) { return function(v) { - return JS.castJSStringToString(toPrettyJSString(sep)(v)); }; }, - toString : function(v) { return JS.castJSStringToString(toPrettyJSString('')(v)); }, - fromString : function(v) { return fromJSString(JS.castStringToJSString(v)); }, - toList : toList, - fromList : fromList, - JsonString : JsonString, - JsonNumber : JsonNumber, - JsonBool : JsonBool, - JsonNull : JsonNull, - JsonArray : JsonArray, - JsonObject : JsonObject - }; -}(); diff --git a/core-js/foreign/JavaScript.js b/core-js/foreign/JavaScript.js deleted file mode 100644 index 5291a75..0000000 --- a/core-js/foreign/JavaScript.js +++ /dev/null @@ -1,69 +0,0 @@ - -Elm.JavaScript = function() { - function castJSBoolToBool(b) { return b; } - function castBoolToJSBool(b) { return b; } - - function castJSNumberToFloat(n) { return n; } - function castFloatToJSNumber(n) { return n; } - - function castJSNumberToInt(n) { return ~~n; } - function castIntToJSNumber(n) { return n; } - - function castJSElementToElement(w) { - return function(h) { - return function(node) { - return ["Element",Guid.guid(), - ["EExternalHtml",node], - w,h,1,["Nothing"],["Nothing"]]; - } - } - } - function castElementToJSElement(elem) { return Render.render(elem); } - - function castJSArrayToList(arr) { - var list = ["Nil"]; - for (var i = arr.length; i--; ) { - list = [ "Cons", arr[i], list ]; - } - return list; - } - function castListToJSArray(list) { - var a = []; - while (list[0] === "Cons") { - a.push(list[1]); - list = list[2]; - } - return a; - } - - var castJSStringToString = castJSArrayToList; - function castStringToJSString(str) { - if (typeof str === "string") return str; - return castListToJSArray(str).join(''); - } - - function fromTuple(t) { return t.slice(1); } - function toTuple(a) { return ["Tuple" + a.length].concat(a); } - - return {castJSBoolToBool:castJSBoolToBool, - castBoolToJSBool:castBoolToJSBool, - castJSNumberToFloat:castJSNumberToFloat, - castFloatToJSNumber:castFloatToJSNumber, - castJSNumberToInt:castJSNumberToInt, - castIntToJSNumber:castIntToJSNumber, - Experimental : {castJSElementToElement:castJSElementToElement, - castElementToJSElement:castElementToJSElement}, - castJSArrayToList:castJSArrayToList, - castListToJSArray:castListToJSArray, - castJSStringToString:castJSStringToString, - castStringToJSString:castStringToJSString, - castTupleToJSTuple2:fromTuple, - castTupleToJSTuple3:fromTuple, - castTupleToJSTuple4:fromTuple, - castTupleToJSTuple5:fromTuple, - castJSTupleToTuple2:toTuple, - castJSTupleToTuple3:toTuple, - castJSTupleToTuple4:toTuple, - castJSTupleToTuple5:toTuple - }; -}(); diff --git a/core-js/runtime/Dispatcher.js b/core-js/runtime/Dispatcher.js deleted file mode 100644 index 1562407..0000000 --- a/core-js/runtime/Dispatcher.js +++ /dev/null @@ -1,58 +0,0 @@ - -var Dispatcher = function() { - var program = null; - var inputs = []; - var currentElement = null; - - var initialize = function() { - program = Elm.main(); - if (!('recv' in program)) { - program = Elm.Signal.constant(program); - } - - currentElement = program.value; - filterDeadInputs(); - - var content = document.getElementById('content'); - content.appendChild(Render.render(currentElement)); - var w = document.getElementById('widthChecker').offsetWidth; - if (w !== window.innerWidth) { - Dispatcher.notify(Elm.Window.dimensions.id, Value.Tuple(w, window.innerHeight)); - } - program = Elm.Signal.lift(function(value) { - var content = document.getElementById('content'); - Render.update(content.firstChild,currentElement,value); - currentElement = value; - return value; - })(program); - }; - var notify = function(id, v) { - var timestep = (new window.Date).getTime(); - var hasListener = false; - for (var i = inputs.length; i--; ) { - hasListener = inputs[i].recv(timestep, id, v) || hasListener; - } - return hasListener; - }; - - function isAlive(input) { - if (!('defaultNumberOfKids' in input)) return true; - var len = input.kids.length; - if (len == 0) return false; - if (len > input.defaultNumberOfKids) return true; - var alive = false; - for (var i = len; i--; ) { - alive = alive || isAlive(input.kids[i]); - } - return alive; - } - function filterDeadInputs() { - var temp = []; - for (var i = inputs.length; i--; ) { - if (isAlive(inputs[i])) temp.push(inputs[i]); - } - inputs = temp; - } - - return {initialize:initialize, notify:notify, inputs:inputs}; -}(); \ No newline at end of file diff --git a/core-js/runtime/Signal.js b/core-js/runtime/Signal.js deleted file mode 100644 index 3b17beb..0000000 --- a/core-js/runtime/Signal.js +++ /dev/null @@ -1,260 +0,0 @@ - -Elm.Signal = function() { - var send = function(node, timestep, changed) { - var kids = node.kids; - for (var i = kids.length; i--; ) { - kids[i].recv(timestep, changed, node.id); - } - }; - function input(base) { - this.id = Guid.guid(); - this.value = base; - this.kids = []; - this.defaultNumberOfKids = 0; - this.recv = function(timestep, eid, v) { - var changed = eid === this.id; - if (changed) { this.value = v; } - send(this, timestep, changed); - return changed; - }; - Dispatcher.inputs.push(this); - }; - function lift(func,args) { - this.id = Guid.guid(); - this.value = null; - this.kids = []; - this.count = 0; - this.changed = false; - - args.reverse(); - this.recalc = function() { - var f = func; - for (var i = args.length; i--; ) { - f = f(args[i].value); - } - this.value = f; - }; - this.recalc(); - - this.recv = function(timestep, changed, parentID) { - this.count += 1; - if (changed) { this.changed = true; } - if (this.count == args.length) { - if (this.changed) { this.recalc() } - send(this, timestep, this.changed); - this.changed = false; - this.count = 0; - } - }; - for (var i = args.length; i--; ) { - args[i].kids.push(this); - } - }; - function fold(func,base,baseIsFunc,input) { - this.id = Guid.guid(); - this.value = baseIsFunc ? base(input.value) : base; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - if (changed) { this.value = func(input.value)(this.value); } - send(this, timestep, changed); - }; - input.kids.push(this); - }; - - function dropIf(pred,base,input) { - this.id = Guid.guid(); - this.value = pred(input.value) ? base : input.value; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - var chng = changed && !pred(input.value); - if (chng) { this.value = input.value; } - send(this, timestep, chng); - }; - input.kids.push(this); - }; - - function dropRepeats(input) { - this.id = Guid.guid(); - this.value = input.value; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - var chng = changed && !Value.eq(this.value,input.value); - if (chng) { this.value = input.value; } - send(this, timestep, chng); - }; - input.kids.push(this); - }; - - var dropWhen = function(s1) { return function(b) { return function(s2) { - var pairs = new lift(function(x){return function(y){return [x,y];};},[s1,s2]); - var dropped = new dropIf(function(p){return p[0];},[true,b],pairs); - return new lift(function(p){return p[1];},[dropped]); }; }; - }; - - function timeIndex(pair,s) { - this.id = Guid.guid(); - var t = (new window.Date).getTime(); - this.value = pair ? Value.Tuple(t,s.value) : t; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - if (changed) this.value = pair ? Value.Tuple(timestep, s.value) : timestep; - send(this, timestep, changed); - }; - s.kids.push(this); - } - - function sampleOn(s1,s2) { - this.id = Guid.guid(); - this.value = s2.value; - this.kids = []; - this.count = 0; - this.changed = false; - - this.recv = function(timestep, changed, parentID) { - if (parentID === s1.id) this.changed = changed; - this.count += 1; - if (this.count == 2) { - if (this.changed) { this.value = s2.value; } - send(this, timestep, this.changed); - this.count = 0; - this.changed = false; - } - }; - s1.kids.push(this); - s2.kids.push(this); - }; - - function delay(t) { return function(s) { - var delayed = new input(s.value); - var firstEvent = true; - function update(v) { - if (firstEvent) return; - setTimeout(function() { Dispatcher.notify(delayed.id,v); },t); - } - function first(a) { return function(b) { return a; }; } - var out = new sampleOn(delayed,new lift(first, [delayed, new lift(update,[s])])); - firstEvent = false; - return out; - }; - } - - function merge(s1,s2) { - this.id = Guid.guid(); - this.value = s1.value; - this.kids = []; - this.next = null; - this.count = 0; - this.changed = false; - - this.recv = function(timestep, changed, parentID) { - this.count += 1; - if (changed) { - this.changed = true; - if (parentID == s2.id && this.next === null) { this.next = s2.value; } - if (parentID == s1.id) { this.next = s1.value; } - } - - if (this.count == 2) { - if (this.changed) { - this.value = this.next; - this.next = null; - } - send(this, timestep, this.changed); - this.changed = false; - this.count = 0; - } - }; - s1.kids.push(this); - s2.kids.push(this); - }; - - function merges(ss) { - function mrg(x) { return function(y) { return new merge(x,y); }; } - return Elm.List.foldl1(mrg)(ss); - } - - function mergeEither(s1) { return function(s2) { - function f(s) { return function(x) { return [s,x]; }; } - return new merge(new lift(f('Left'),[s1]), new lift(f('Right'),[s2])); - }; - } - - function average(sampleSize) { return function(s) { - var sample = new Array(sampleSize); - var i = sampleSize; - while (i--) sample[i] = 0; - i = 0; - var full = false; - var total = 0; - function f(n) { - total += n - sample[i]; - sample[i] = n; - var avg = total / Math.max(1, full ? sampleSize : i); - if (++i == sampleSize) { full = true; i = 0; } - return avg; - } - return new lift(f, [s]); - }; - } - - return { - constant : function(v) { return new input(v); }, - lift : function(f){return function(e){return new lift(f,[e]);};}, - lift2 : function(f) { - return function(e1) { return function(e2) { - return new lift(f, [e1,e2]); };};}, - lift3 : function(f) { - return function(e1) { return function(e2) { - return function(e3){return new lift(f,[e1,e2,e3]);};};};}, - lift4 : function(f) { - return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return new lift(f, [e1,e2,e3,e4]);};};};};}, - lift5 : function(f) { - return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { - return new lift(f, [e1,e2,e3,e4,e5]);};};};};};}, - lift6 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return new lift(f, [e1,e2,e3,e4,e5,e6]); };};};};};};}, - lift7 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return function(e7) { - return new lift(f, [e1,e2,e3,e4,e5,e6,e7]);};};};};};};};}, - lift8 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return function(e7) { return function(e8) { - return new lift(f, [e1,e2,e3,e4,e5,e6,e7,e8]);};};};};};};};};}, - foldp : function(f) { return function(b) { return function(e) { - return new fold(f,b,false,e); }; }; }, - foldp$ : function(f) { return function(b) { return function(e) { - return new fold(f,b,true,e); }; }; }, - foldp1 : function(f) { return function(e) { - return new fold(f,function(x){return x;},true,e); }; }, - delay : delay, - merge : function(s1) { return function(s2) { return new merge(s1,s2)}; }, - merges : merges, - mergeEither : mergeEither, - average : average, - count : function(sig) { - var incr = function(_){return function(c){return c+1;};}; - return new fold(incr,0,false,sig) }, - countIf : function(pred) { return function(sig) { - var incr = function(x){return function(c){return pred(x) ? c+1 : c;};}; - return new fold(incr,0,false,sig) }; }, - keepIf : function(pred) { return function(base) { return function(sig) { - return new dropIf(function(x) { return !pred(x)},base,sig); }; }; }, - dropIf : function(pred) { return function(base) { return function(sig) { - return new dropIf(pred,base,sig); }; }; }, - keepWhen : function(s) { return dropWhen(new lift(function(b){return !b;},[s])); }, - dropWhen : dropWhen, - dropRepeats : function(s) { return new dropRepeats(s);}, - sampleOn : function(s1){return function(s2){return new sampleOn(s1,s2);};}, - timestamp : function(s) { return new timeIndex(true, s); }, - timeOf : function(s) { return new timeIndex(false, s); } - }; -}(); \ No newline at end of file diff --git a/core/Automaton.elm b/core/Automaton.elm deleted file mode 100644 index 879a522..0000000 --- a/core/Automaton.elm +++ /dev/null @@ -1,79 +0,0 @@ - -module Automaton where - -data Automaton a b = Automaton (a -> (b, Automaton a b)) - -{--- API possibilies: All names and types are up for debate! -(^>>) :: (a -> b) -> Automaton b c -> Automaton a c -(>>^) :: Automaton a b -> (b -> c) -> Automaton a c -(^<<) :: (b -> c) -> Automaton a b -> Automaton a c -(<<^) :: Automaton b c -> (a -> b) -> Automaton a c ---} - - -run : Automaton a b -> Signal a -> Signal b -run (Automaton m0) input = - lift fst $ foldp' (\a (b, Automaton m) -> m a) m0 input - -step : Automaton a b -> a -> (b, Automaton a b) -step (Automaton m) a = m a - - -(>>>) : Automaton a b -> Automaton b c -> Automaton a c -a1 >>> a2 = - let Automaton m1 = a1 - Automaton m2 = a2 - in Automaton (\a -> let (b,m1') = m1 a - (c,m2') = m2 b - in (c, m1' >>> m2')) - -(<<<) : Automaton b c -> Automaton a b -> Automaton a c -a2 <<< a1 = a1 >>> a2 - -combine : [Automaton a b] -> Automaton a [b] -combine autos = - Automaton (\a -> let (bs,autos') = unzip $ map (\(Automaton m) -> m a) autos in - (bs, combine autos')) - -pure : (a -> b) -> Automaton a b -pure f = Automaton (\x -> (f x, pure f)) - -init : b -> (a -> b -> b) -> Automaton a b -init s step = Automaton (\a -> let s' = step a s in (s', init s' step)) - -init' : s -> (a -> s -> (b,s)) -> Automaton a b -init' s step = Automaton (\a -> let (b,s') = step a s in (b , init' s' step)) - -count : Automaton a Int -count = init 0 (\_ c -> c + 1) - - -data DragState = Listen | Ignore | DragFrom (Int,Int) - -vecSub (x1,y1) (x2,y2) = (x1-x2,y1-y2) - -stepDrag (press,pos) (ds,form) = - let wrap ds' = (form, (ds',form)) in - case ds of - Listen -> wrap (if | not press -> Listen - | pos `isWithin` form -> DragFrom pos - | otherwise -> Ignore) - Ignore -> wrap (if press then Ignore else Listen) - DragFrom p0 -> - if press then (uncurry move (vecSub pos p0) form, (DragFrom p0, form)) - else (let form' = uncurry move (vecSub pos p0) form in - (form', (Listen,form'))) - -draggable : Form -> Automaton (Bool,(Int,Int)) Form -draggable form = init' (Listen,form) stepDrag - - -{--- See the following papers for ideas on how to make this faster: - -- Functional Reactive Programming, Continued -- Causal commutative arrows and their optimization - -Speeding things up is a really low priority. Language features and -libraries with nice APIs and are way more important! - ---} \ No newline at end of file diff --git a/core/Color.elm b/core/Color.elm deleted file mode 100644 index 3e1f6e3..0000000 --- a/core/Color.elm +++ /dev/null @@ -1,44 +0,0 @@ - -module Graphics.Color (rgba,rgb,hsva,hsv, - complement, - red,lime,blue, - yellow,cyan,magenta, - maroon,navy,green, - teal,purple, - violet,forestGreen, - black,white,gray,grey) where - -import Native.Color as Native - -data Color = Color Int Int Int Float - -rgba = Color -rgb r g b = Color r g b 1 - -red = Color 255 0 0 1 -lime = Color 0 255 0 1 -blue = Color 0 0 255 1 - -yellow = Color 255 255 0 1 -cyan = Color 0 255 255 1 -magenta = Color 255 0 255 1 - -black = Color 0 0 0 1 -white = Color 255 255 255 1 - -gray = Color 128 128 128 1 -grey = Color 128 128 128 1 - -maroon = Color 128 0 0 1 -navy = Color 0 0 128 1 -green = Color 0 128 0 1 - -teal = Color 0 128 128 1 -purple = Color 128 0 128 1 - -forestGreen = Color 34 139 34 1 -violet = Color 238 130 238 1 - -complement = Native.complement -hsva = Native.hsva -hsv = Native.hsv \ No newline at end of file diff --git a/core/Date.elm b/core/Date.elm deleted file mode 100644 index 7dc13f8..0000000 --- a/core/Date.elm +++ /dev/null @@ -1,8 +0,0 @@ - -module Date where - -data Weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun - -data Month = Jan | Feb | Mar | Apr - | May | Jun | Jul | Aug - | Sep | Oct | Nov | Dec diff --git a/core/Either.elm b/core/Either.elm deleted file mode 100644 index 8b5bee3..0000000 --- a/core/Either.elm +++ /dev/null @@ -1,22 +0,0 @@ - -data Either a b = Left a | Right b - -either : (a -> c) -> (b -> c) -> Either a b -> c -either f g e = case e of { Left x -> f x ; Right y -> g y } - - -isLeft : Either a b -> Bool -isLeft e = case e of { Left _ -> True ; _ -> False } - -isRight : Either a b -> Bool -isRight e = case e of { Right _ -> True ; _ -> False } - - -lefts : [Either a b] -> [a] -lefts = Elm.List.filter isLeft - -rights : [Either a b] -> [b] -rights = Elm.List.filter isRight - -partition : [Either a b] -> ([a],[b]) -partition = Elm.List.partition isLeft \ No newline at end of file diff --git a/core/Element.elm b/core/Element.elm deleted file mode 100644 index 11b0797..0000000 --- a/core/Element.elm +++ /dev/null @@ -1,195 +0,0 @@ - -module Graphics.Element - (left,right,down,up,inward,outward - ,topLeft,topRight,bottomLeft,bottomRight - ,midLeft,midRight,midTop,midBottom - ,middle,absolute,relative - ,topLeftAt,topRightAt,bottomLeftAt,bottomRightAt - ,width,height,size,widthOf,heightOf,sizeOf - ,color,opacity - ,text,image,fittedImage,video - ,flow,above,below,beside,layers - ,collage,spacer,container - ,line,segment - ,polygon,ngon,rect,oval,circle - ,solid,dotted,dashed,customLine - ,filled,outlined,customOutline,textured - ,sprite,toForm - ,rotate,scale,move - ) where - -import Graphics.Color - -data Direction = DLeft | DRight | DUp | DDown | DIn | DOut - -left = DLeft -right = DRight -down = DDown -up = DUp -inward = DIn -outward = DOut - -data Pos1 = Absolute Int | Relative Float -data Pos2 = Near | Mid | Far - -data Position - = Position Pos2 Pos2 - | PositionAt Pos1 Pos1 - | PositionTL Pos1 Pos1 - | PositionTR Pos1 Pos1 - | PositionBL Pos1 Pos1 - | PositionBR Pos1 Pos1 - -topLeft = Position Near Near -topRight = Position Far Near -bottomLeft = Position Near Far -bottomRight = Position Far Far - -midLeft = Position Near Mid -midRight = Position Far Mid -midTop = Position Mid Near -midBottom = Position Mid Far - -middle = Position Mid Mid - -middleAt = PositionAt -topLeftAt = PositionTL -topRightAt = PositionTR -bottomLeftAt = PositionBL -bottomRightAt = PositionBR - -absolute = Absolute -relative = Relative - -data Element = Element Int BasicElement Int Int Float (Maybe Color) (Just String) - -newElement = Element 0 -basicNewElement e w h = Element 0 e w h 1 Nothing Nothing - -data BasicElement - = EText Text Text - | EImage String - | EVideo String - | EFittedImage String - | EFlow Direction [Element] - | ECollage Int Int [Form] - | EEmpty - | EContainer Position Element - -width w' (Element _ e w h o c l) = - case e of - { EText _ -> newElement e w' h o c l - ; EImage _ -> newElement e w' h o c l - ; EVideo _ -> newElement e w' h o c l - ; _ -> newElement e w' h o c l } -height h' (Element _ e w h o c l) = - case e of - { EText _ -> newElement e w h' o c l - ; EImage _ -> newElement e w h' o c l - ; EVideo _ -> newElement e w h' o c l - ; _ -> newElement e w h' o c l } -size w' h' (Element _ e w h o c l) = newElement e w' h' o c l -opacity o' (Element _ e w h o c l) = newElement e w h o' c l -color c' (Element _ e w h o c l) = newElement e w h o (Just c') l -link l' (Element _ e w h o c l) = newElement e w h o c (Just l') - -widthOf (Element _ _ w _ _ _ _) = w -heightOf (Element _ _ _ h _ _ _) = h -sizeOf (Element _ _ w h _ _ _) = (w,h) - -n1 = 0-1 - -text t = basicNewElement (EText t) n1 n1 -image w h s = basicNewElement (EImage s) w h -video w h s = basicNewElement (EVideo s) w h -fittedImage w h s = basicNewElement (EFittedImage s) w h - -flow dir es = - let { w = let ws = map widthOf es in - case dir of { DLeft -> sum ws - ; DRight -> sum ws - ; _ -> maximum ws } - ; h = let hs = map heightOf es in - case dir of { DDown -> sum hs - ; DUp -> sum hs - ; _ -> maximum hs } - } in basicNewElement (EFlow dir es) w h - -above e1 e2 = - newElement - (EFlow DDown [e1,e2]) - (max (widthOf e1) (widthOf e2)) - (heightOf e1 + heightOf e2) 1 Nothing Nothing - -below e1 e2 = - basicNewElement (EFlow DDown [e2,e1]) - (max (widthOf e1) (widthOf e2)) - (heightOf e1 + heightOf e2) - -beside e1 e2 = - basicNewElement (EFlow DRight [e1,e2]) - (widthOf e1 + widthOf e2) - (max (heightOf e1) (heightOf e2)) - -layers es = - basicNewElement (EFlow DIn es) - (maximum (map widthOf es)) - (maximum (map heightOf es)) - -collage w h forms = basicNewElement (ECollage w h forms) w h - -spacer w h = basicNewElement EEmpty w h - -container w h pos e = - basicNewElement (EContainer pos e) w h - - - -data LineStyle = Solid | Dotted | Dashed | Custom [Int] -data ShapeStyle = Filled | Outlined | CustomOutline [Int] | Textured String - -data Line = Line [(Float,Float)] - -line = Line -segment p1 p2 = Line [p1,p2] - -data Shape = Shape [(Float,Float)] (Float,Float) - -polygon = Shape -rect w h pos = Shape [(0-w/2,0-h/2),(0-w/2,h/2),(w/2,h/2),(w/2,0-h/2)] pos -oval w h pos = - let n = 50 in - let f i = ( w/2 * cos (2*pi/n * i), h/2 * sin (2*pi/n * i)) in - Shape (map f [0..n-1]) pos -circle r = oval (2*r) (2*r) -ngon n r pos = - let m = toFloat n in - let f i = ( r * cos (2*pi/m * i), r * sin (2*pi/m * i)) in - Shape (map f [0..n-1]) pos - -data Form = Form Float Float (Float,Float) BasicForm - -data BasicForm - = FLine LineStyle Color Line - | FShape ShapeStyle Color Shape - | FImage Int Int String - | FElement Element - -solid clr ln = Form 0 1 (0,0) (FLine Solid clr ln) -dotted clr ln = Form 0 1 (0,0) (FLine Dotted clr ln) -dashed clr ln = Form 0 1 (0,0) (FLine Dashed clr ln) -customLine pattern clr ln = - Form 0 1 (0,0) (FLine (Custom pattern) clr ln) - -filled clr (Shape ps pos) = Form 0 1 pos (FShape Filled clr (Shape ps pos)) -outlined clr (Shape ps pos) = Form 0 1 pos (FShape Outlined clr (Shape ps pos)) -customOutline pattern clr (Shape ps pos) = - Form 0 1 pos (FShape (CustomOutline pattern) clr (Shape ps pos)) -textured src (Shape ps pos) = Form 0 1 pos (FShape (Textured src) black (Shape ps pos)) - -sprite w h pos src = Form 0 1 pos (FImage w h src) -toForm pos e = Form 0 1 pos (FElement e) - -rotate t (Form theta scale pos form) = Form (t+theta) scale pos form -scale s (Form theta scale pos form) = Form theta (s*scale) pos form -move x y (Form theta scale (px,py) form) = Form theta scale (x+px,y+py) form \ No newline at end of file diff --git a/core/Form.elm b/core/Form.elm deleted file mode 100644 index be061ae..0000000 --- a/core/Form.elm +++ /dev/null @@ -1,114 +0,0 @@ - -module Collage where - -data Line - = Start (Float,Float) - | Arc (Float,Float) Float (Float,Float) Path - | Line (Float,Float) Path - | Bezier (Float,Float) (Float,Float) (Float,Float) Path - | Quadratic (Float,Float) (Float,Float) Path - -path ps = case ps of - [] -> Start (0,0) - hd:tl -> foldl Line (Start hd) tl - -segment p1 p2 = Line p1 (Start p2) - -start = Start -arcTo = Arc -lineTo = Line -bezierTo = Bezier -quadraticTo = Quadratic - -data Shape = Shape Line - -polygon ps = Shape (case ps of - [] -> Start (0,0) - hd:tl -> Line hd $ foldl Line (Start hd) tl) - -rect w h = polygon [ (0-w/2,0-h/2), (0-w/2,h/2), (w/2,h/2), (w/2,0-h/2) ] -oval w h = - let n = 50 - f i = ( w/2 * cos (2*pi/n * i), h/2 * sin (2*pi/n * i)) - in Shape $ map f [0..n-1] -circle r = oval (2*r) (2*r) -ngon n r = - let m = toFloat n - f i = ( r * cos (2*pi/m * i), r * sin (2*pi/m * i)) - in Shape $ map f [0..n-1] - -data Transform - = Rotate Float - | Move Float Float - | Scale Float Float - | Transform Float Float Float Float Float Float - -data Form = Form [Transform] BasicForm - - -data LineCap = Butt | Round | Square -data LineJoin = Round | Bevel | Miter - -data FillStyle - = NoFill - | Solid Color - | Texture String - | LinearGradient [(Float,Color)] (Float,Float) (Float,Float) - | RadialGradient [(Float,Color)] (Float,Float) Float (Float,Float) Float - -data LineStyle = NoLine | Line [Int] Int Float LineCap LineJoin Float FillStyle - -data BasicForm - = FLine LineStyle FillStyle Line - | FShape LineStyle FillStyle Shape - | FImage Int Int String - | FElement Element - | FGroup [Form] - -setFillStyle fs form = - case form of - FLine ls _ ln -> FLine ls fs ln - FShape ls _ shp -> FLine ls fs shp - _ -> form - -noFill = setFillStyle NoFill -fillColor clr = setFillStyle (Solid clr) -texture src = setFillStyle (Texture src) -linearGradient stops start end = setFillStyle (LinearGradient stops start end) -radialGradient stops innerP innerR outerP outerR = - setFillStyle (RadialGradient stops innerP innerR outerP outerR) - -solid clr ln = Form [] (FLine ln) -dotted clr ln = Form [] (FLine ln) -dashed clr ln = Form [] (FLine ln) -customLine pattern clr ln = Form [] (FLine (Custom pattern) clr ln) - - -filled clr shp = Form [] (FShape shp) -outlined clr shp = Form [] (FShape shp) -customOutline pattern clr (Shape ps pos) = - Form [] (FShape (CustomOutline pattern) clr (Shape ps pos)) -textured src (Shape ps pos) = Form [] (FShape (Textured src) black (Shape ps pos)) - -fromLine = FLine -fromShape = FShape -fromElement = FElement - -sprite w h pos src = Form 0 1 pos (FImage w h src) -toForm pos e = Form 0 1 pos (FElement e) - -addTransform t (Form ts form) = Form (t:ts) form - -rotateRad rad = addTransform $ Rotate rad -rotateDeg deg = addTransform $ Rotate (pi * deg / 180) -rotate rot = addTransform $ Rotate (2 * pi * rot) - -scale s = addTransform (Scale s s) -scaleX s = addTransform (Scale s 1) -scaleY s = addTransform (Scale 1 s) - -move x y = addTransform (Move x y) -moveX x = addTransform (Move x 0) -moveY y = addTransform (Move 0 y) - -transform a b c d e f = addTransform (Transform a b c d e f) \ No newline at end of file diff --git a/core/List.elm b/core/List.elm deleted file mode 100644 index 6336143..0000000 --- a/core/List.elm +++ /dev/null @@ -1,97 +0,0 @@ - -module List where - -import Native.List as Native - -head : [a] -> a -head = Native.head - -tail : [a] -> [a] -tail = Native.tail - -last : [a] -> a -last = Native.last - -map : (a -> b) -> [a] -> [b] -map = Native.map - -foldl : (a -> b -> b) -> b -> [a] -> b -foldl = Native.foldl - -foldr : (a -> b -> b) -> b -> [a] -> b -foldr = Native.foldr - -foldl1 : (a -> a -> a) -> [a] -> a -foldl1 = Native.foldl1 - -foldr1 : (a -> a -> a) -> [a] -> a -foldr1 = Native.foldr1 - -scanl : (a -> b -> b) -> b -> [a] -> [b] -scanl = Native.scanl - -scanl1 : (a -> a -> a) -> [a] -> [a] -scanl1 = Native.scanl1 - -filter : (a -> Bool) -> [a] -> [a] -filter = Native.filter - -length : [a] -> Int -length = Native.length - -reverse : [a] -> [a] -reverse = Native.reverse - -concat : [[a]] -> [a] -concat = Native.foldr (++) [] - -concatMap : (a -> [b]) -> [a] -> [b] -concatMap f = concat . Native.map f - -all : (a -> Bool) -> [a] -> Bool -all pred = Native.all - -any : (a -> Bool) -> [a] -> Bool -any = Native.any - -and : [Bool] -> Bool -and = Native.all id - -or : [Bool] -> Bool -or = Native.any id - -sum = foldl (+) 0 -product = foldl (*) 1 -maximum = foldl1 max -minimum = foldl1 min - -partition : (a -> Bool) -> [a] -> ([a],[a]) -partition pred lst = - case lst of - [] -> ([],[]) - x::xs -> let (as,bs) = partition pred xs in - if pred x then (x::as,bs) else (as,x::bs) - -zipWith : (a -> b -> c) -> [a] -> [b] -> [c] -zipWith = Native.zipWith - -zip : [a] -> [b] -> [(a,b)] -zip = Native.zip - -unzip : [(a,b)] -> ([a],[b]) -unzip pairs = - case pairs of - [] -> ([],[]) - (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys) - -intersperse sep xs = - case xs of - a::b::cs -> a :: sep :: intersperse sep (b::cs) - [a] -> [a] - [] -> [] - -intercalate sep xs = - case xs of - a::b::cs -> a ++ sep ++ intercalate sep (b::cs) - [a] -> a - [] -> [] diff --git a/core/Native/Color.js b/core/Native/Color.js deleted file mode 100644 index 00a0693..0000000 --- a/core/Native/Color.js +++ /dev/null @@ -1,64 +0,0 @@ -function nativeColor(elm) { - -function extract(c) { - if (c[4] === 1) { return 'rgb(' + c[1] + ',' + c[2] + ',' + c[3] + ')'; } - return 'rgba(' + c[1] + ',' + c[2] + ',' + c[3] + ',' + c[4] + ')'; -} -function complement(rgb) { - var hsv = toHSV(rgb); - hsv.hue = (hsv.hue + 180) % 360; - return toRGB(hsv); -} - -function hsva(h) { return function(s) { return function(v) { return function(a) { - var clr = toRGB({hue:h, saturation:s, value:v}); - clr[4] = a; - return clr; - }; }; }; -} - -function hsv(h) { return function(s) { return function(v) { - return toRGB({hue:h, saturation:s, value:v}); }; }; } - -function toHSV(rgb) { - var hsv = {}; - var r = rgb[1] / 255.0, g = rgb[2] / 255.0, b = rgb[3] / 255.0; - var M = Math.max(r,g,b); - var m = Math.min(r,g,b); - var c = M - m; - - var h = 0; - if (c === 0) { h = 0; } - else if (M === r) { h = ((g - b) / c) % 6; } - else if (M === g) { h = ((b - r) / c) + 2; } - else if (M === b) { h = ((r - g) / c) + 4; } - h *= 60; - - return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) }; -} - -function between(lo,hi,x) { return lo <= x && x < hi; } -function norm(n) { return Math.round(n*255); } - -function toRGB(hsv) { - var c = hsv.value * hsv.saturation; - var hue = hsv.hue / 60; - var x = c * (1 - Math.abs((hue % 2) - 1)); - var r = 0, g = 0, b = 0; - if (between(0,1,hue)) { r = c; g = x; b = 0; } - else if (between(1,2,hue)) { r = x; g = c; b = 0; } - else if (between(2,3,hue)) { r = 0; g = c; b = x; } - else if (between(3,4,hue)) { r = 0; g = x; b = c; } - else if (between(4,5,hue)) { r = x; g = 0; b = c; } - else if (between(5,6,hue)) { r = c; g = 0; b = x; } - - var m = hsv.value - c; - return [ "Color", norm(r+m), norm(g+m), norm(b+m), 1 ]; -} - -elm.Native.Color = { - hsva:hsva, - hsv:hsv, - complement:complement, - extract:extract}; -} \ No newline at end of file diff --git a/core/Native/List.js b/core/Native/List.js deleted file mode 100644 index 96b0fd9..0000000 --- a/core/Native/List.js +++ /dev/null @@ -1,214 +0,0 @@ -function nativeList(elm) { - - function throwError(f) { - throw new Error("Function '" + f + "' expects a non-empty list!"); - } - - function toArray(xs) { - var out = []; - while (xs[0] === "Cons") { - out.push(xs[1]); - xs = xs[2]; - } - return out; - } - - function fromArray(arr) { - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - - function head(v) { v[0] === "Nil" ? throwError('head') : return v[1]; } - function tail(v) { v[0] === "Nil" ? throwError('tail') : return v[2]; } - - function last(xs) { - if (xs[0] === "Nil") { throwError('last'); } - var out = xs[1]; - while (xs[0] === "Cons") { - out = xs[1]; - xs = xs[2]; - } - return out; - } - - function map(f) { return function(xs) { - var arr = []; - while (xs[0] === "Cons") { - arr.push(f(xs[1])); - xs = xs[2]; - } - return fromArray(arr); - } - } - - function foldl(f) { return function(b) { return function(xs) { - var acc = b; - while (xs[0] === "Cons") { - acc = f(xs[1])(acc); - xs = xs[2]; - } - return acc; - } - } - } - - function foldr(f) { return function(b) { return function(xs) { - var arr = toArray(xs); - var acc = b; - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - } - - function foldl1(f) { return function(xs) { - xs[0] === "Nil" ? throwError('foldl1') : return foldl(f)(xs[1])(xs[2]); - } - } - - function foldr1(f) { return function(xs) { - if (xs[0] === "Nil") { throwError('foldr1'); } - var arr = toArray(xs); - var acc = arr.pop(); - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - - function scanl(f) { return function(b) { return function(xs) { - var arr = toArray(xs); - arr.unshift(b); - var len = arr.length; - for (var i = 1; i < len; ++i) { - arr[i] = f(arr[i])(arr[i-1]); - } - return fromArray(arr); - } - } - } - - function scanl1(f) { return function(xs) { - xs[0] === "Nil" ? throwError('scanl1') : return scanl(f)(xs[1])(xs[2]); - } - } - - function filter(pred) { return function(xs) { - var arr = []; - while (xs[0] === "Cons") { - if (pred(xs[1])) { arr.push(xs[1]); } - xs = xs[2]; - } - return fromArray(arr); - } - } - - function length(xs) { - var out = 0; - while (xs[0] === "Cons") { - out += 1; - xs = xs[2]; - } - return out; - } - - function reverse(xs) { return fromArray(toArray(xs).reverse()); } - - function all(pred) { return function(xs) { - while (xs[0] === "Cons") { - if (!pred(xs[1])) return false; - xs = xs[2]; - } - return true; - } - } - - function any(pred) { return function(xs) { - while (xs[0] === "Cons") { - if (pred(xs[1])) return true; - xs = xs[2]; - } - return false; - } - } - - function zipWith(f) { return function(xs) { return function(ys) { - var arr = []; - while (xs[0] === "Cons" && ys[0] === "Cons") { - arr.push(f(xs[1])(ys[1])); - xs = xs[2]; - ys = ys[2]; - } - return fromArray(arr); - } - } - } - - function zip(xs) { return function(ys) { - var arr = []; - while (xs[0] === "Cons" && ys[0] === "Cons") { - arr.push(["Tuple2",xs[1],ys[1]]); - xs = xs[2]; - ys = ys[2]; - } - return fromArray(arr); - } - } - - function sort(xs) { - return fromArray(toArray(xs).sort(function(a,b) { return a - b})); - } - - function take(n) { return function(xs) { - var arr = []; - while (xs[0] === "Cons" && n > 0) { - arr.push(xs[1]); - xs = xs[2]; - --n; - } - return fromArray(arr); - } - } - - function drop(n) { return function(xs) { - while (xs[0] === "Cons" && n > 0) { - xs = xs[2]; - --n; - } - return xs; - } - } - - function concatA( - - elm.Native.List = { - head:head, - tail:tail, - last:last, - - map:map, - foldl:foldl, - foldr:foldr, - - foldl1:foldl1, - foldr1:foldr1, - scanl:scanl, - scanl1:scanl1, - filter:filter, - length:length, - reverse:reverse, - - all:all, - any:any, - zipWith:zipWith, - zip:zip, - sort:sort, - take:take, - drop:drop}; -} \ No newline at end of file diff --git a/core/Set.elm b/core/Set.elm deleted file mode 100644 index 36b2d3e..0000000 --- a/core/Set.elm +++ /dev/null @@ -1,48 +0,0 @@ - -module Set (empty,singleton,insert,remove - ,member - ,foldl,foldr,map - ,union,intersect,diff - ,toList,fromList - ) where - -type Set t = Dict t () - -empty : Set t -empty = Dict.empty - -singleton : t -> Set t -singleton k = Dict.singleton k () - -insert : t -> Set t -> Set t -insert k = Dict.insert k () - -remove : t -> Set t -> Set t -remove = Dict.remove - -member : t -> Set t -> Bool -member = Dict.member - -union : Set t -> Set t -> Set t -union = Dict.union - -intersect : Set t -> Set t -> Set t -intersect = Dict.intersect - -diff : Set t -> Set t -> Set t -diff = Dict.diff - -toList : Set t -> [t] -toList = Dict.keys - -fromList : [t] -> Set t -fromList = List.foldl (\k t -> Dict.insert k () t) empty - -foldl : (a -> b -> b) -> b -> Set a -> b -foldl f = Dict.foldl (\k _ b -> f k b) - -foldr : (a -> b -> b) -> b -> Set a -> b -foldr f = Dict.foldr (\k _ b -> f k b) - -map : (a -> b) -> Set a -> Set b -map f = fromList . List.map f . toList \ No newline at end of file diff --git a/elm/Setup.hs b/elm/Setup.hs deleted file mode 100644 index 9a994af..0000000 --- a/elm/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/elm/elm-runtime-0.5.0.2.js b/elm/elm-runtime-0.5.0.2.js deleted file mode 100644 index 8f18b00..0000000 --- a/elm/elm-runtime-0.5.0.2.js +++ /dev/null @@ -1,123 +0,0 @@ -var Guid=function(){var d=0;return{guid:function(){return d+=1}}}(),Elm=Elm||{}; -Elm.JavaScript=function(){function d(a){for(var b=["Nil"],l=a.length;l--;)b=["Cons",a[l],b];return b}function a(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b}function g(a){return a.slice(1)}function i(a){return["Tuple"+a.length].concat(a)}return{castJSBoolToBool:function(a){return a},castBoolToJSBool:function(a){return a},castJSNumberToFloat:function(a){return a},castFloatToJSNumber:function(a){return a},castJSNumberToInt:function(a){return~~a},castIntToJSNumber:function(a){return a}, -Experimental:{castJSElementToElement:function(a){return function(b){return function(l){return["Element",Guid.guid(),["EExternalHtml",l],a,b,1,Nothing,Nothing]}}},castElementToJSElement:function(a){return Render.render(a)}},castJSArrayToList:d,castListToJSArray:a,castJSStringToString:d,castStringToJSString:function(g){return"string"===typeof g?g:a(g).join("")},castTupleToJSTuple2:g,castTupleToJSTuple3:g,castTupleToJSTuple4:g,castTupleToJSTuple5:g,castJSTupleToTuple2:i,castJSTupleToTuple3:i,castJSTupleToTuple4:i, -castJSTupleToTuple5:i}}();var Elm=Elm||{},JSjson=JSON; -Elm.JSON=function(){function d(b,a){return function(h){return function(e){var c=i.castStringToJSString(h);return e[1].hasOwnProperty(c)&&(e=e[1][c],e[0]===b)?e[1]:a}}}function a(b){return function(a){function h(b){switch(b[0]){case "JsonNull":return null;case "JsonString":return i.castStringToJSString(b[1]);case "JsonObject":var c={},b=b[1][1],f;for(f in b)c[f]=h(b[f]);return c;case "JsonArray":c=i.castListToJSArray(b[1]);for(f=c.length;f--;)c[f]=h(c[f]);return c;default:return b[1]}}return JSjson.stringify(h(["JsonObject", -a]),null,i.castStringToJSString(b))}}function g(b){function a(b){switch(typeof b){case "string":return["JsonString",i.castJSStringToString(b)];case "number":return["JsonNumber",i.castJSNumberToFloat(b)];case "boolean":return["JsonBool",i.castJSBoolToBool(b)];case "object":if(null===b)return["JsonNull"];for(var c in b)b[c]=a(b[c]);return b instanceof Array?["JsonArray",i.castJSArrayToList(b)]:["JsonObject",["JSON",b]]}}var b=JSjson.parse(b),h;for(h in b)b[h]=a(b[h]);return["JSON",b]}var i=Elm.JavaScript, -j=["JSON",{}];return{empty:j,singleton:function(b){return function(a){var h={};h[i.castStringToJSString(b)]=a;return["JSON",h]}},insert:function(b){return function(a){return function(h){var h=h[1],e={},c;for(c in h)e[c]=h[c];e[i.castStringToJSString(b)]=a;return["JSON",e]}}},lookup:function(b){return function(a){var h=i.castStringToJSString(b);return a[1].hasOwnProperty(h)?Just(a[1][h]):Nothing}},findString:d("JsonString",["Nil"]),findObject:d("JsonObject",j),findArray:d("JsonArray",["Nil"]),findWithDefault:function(b){return function(a){return function(h){var e= -i.castStringToJSString(a);return h[1].hasOwnProperty(e)?h[1][e]:b}}},remove:function(b){return function(a){var a=a[1],h={},e;for(e in a)h[e]=a[e];delete h[i.castStringToJSString(b)];return["JSON",h]}},toPrettyJSString:a,toJSString:a(""),fromJSString:g,toPrettyString:function(b){return function(g){return i.castJSStringToString(a(b)(g))}},toString:function(b){return i.castJSStringToString(a("")(b))},fromString:function(b){return g(i.castStringToJSString(b))},toList:function(b){var b=b[1],a=[],h;for(h in b)a.push(Value.Tuple(i.castJSStringToString(h), -b[h]));return i.castJSArrayToList(a)},fromList:function(b){for(var b=i.castListToJSArray(b),a={},h=b.length;h--;)a[i.castStringToJSString(b[h][1])]=b[h][2];return["JSON",a]},JsonString:function(b){return["JsonString",b]},JsonNumber:function(b){return["JsonNumber",b]},JsonBool:function(b){return["JsonBool",b]},JsonNull:["JsonNull"],JsonArray:function(b){return["JsonArray",b]},JsonObject:function(b){return["JsonObject",b]}}}(); -var Value=function(){function d(b){if(0==b.length)return b;for(var b=b.replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br/>"),b=b.split("<br/>"),a=b.length;a--;){var h=b,e=a,c;c=b[a];if(0!=c.length){c=c.split("");" "==c[0]&&(c[0]=" ");for(var f=c.length;--f;)" "==c[f][0]&&" "==c[f-1]&&(c[f-1]+=c[f],c[f]="");for(f=c.length;f--;)if(1<c[f].length&&" "==c[f][0]){for(var n=c[f].split(""),g=n.length-2;0<=g;g-=2)n[g]=" ";c[f]=n.join("")}c= -c.join("");c=" "===c[c.length-1]?c.slice(0,-1)+" ":c}h[e]=c}return b.join("<br/>")}var a=function(b,g){if("object"===typeof b){if(b===g)return!0;if(b.length!==g.length)return!1;for(var h=b.length;h--;)if(!a(b[h],g[h]))return!1;return!0}return b===g},g=function(b){if("boolean"===typeof b)return b?"True":"False";if("number"!==typeof b){if("string"===typeof b&&2>b.length)return"'"+b+"'";if(b[0]){if("Tuple"===b[0].substring(0,5)){for(var a="",h=b.length;--h;)a=","+g(b[h])+a;","===a[0]&&(a=a.substring(1)); -return"("+a+")"}if("Cons"===b[0])for(var h="string"===typeof b[1]?'"':"]",e="string"===typeof b[1]?"":",",c="string"===typeof b[1]?function(c){return c}:g,a=("string"===typeof b[1]?'"':"[")+c(b[1]),b=b[2];;)if("Cons"===b[0])a+=e+c(b[1]),b=b[2];else return a+h;else{if("Nil"===b[0])return"[]";if("JSON"===b[0])return"(JSON.fromList "+g(Elm.JSON.toList(b))+")";if("RBNode"===b[0]||"RBEmpty"===b[0])return"(Map.fromList "+g(Elm.Dict.fold(function(c){return function(b){return function(a){return["Cons",["Tuple2", -c,b],a]}}})(["Nil"])(b))+")";a="";for(h=b.length;--h;)a=" "+g(b[h])+a;a=b[0]+a;return 1<b.length?"("+a+")":a}}}return b+""},i=function(b){for(var a=["Nil"],h=b.length;h--;)a=["Cons",b[h],a];return a},j;j=document.addEventListener?function(b,a,h){b.addEventListener(a,h,!1)}:function(b,a,h){b.attachEvent("on"+a,h)};return{eq:a,str:i,show:function(b){return i(g(b))},Tuple:function(){var b=arguments.length,a=Array(b+1);for(a[0]="Tuple"+arguments.length;b--;)a[b+1]=arguments[b];return a},append:function(b, -a){if("string"===typeof b&&"string"===typeof a)return b.concat(a);if("Nil"===b[0])return a;for(var h=["Cons",b[1],["Nil"]],e=h,b=b[2];"Cons"===b[0];)e[2]=["Cons",b[1],["Nil"]],b=b[2],e=e[2];e[2]=a;return h},listToArray:function(b){for(var a=[];"Cons"===b[0];)a.push(b[1]),b=b[2];return a},toText:function(b){if("string"===typeof b)return d(b);for(var a=[];"Cons"===b[0];)a.push(b[1]),b=b[2];return d(a.join(""))},properEscape:d,getTextSize:function(b,a,h){var e=document.createElement("div");e.innerHTML= -h;e.style.textAlign="left";0<b&&(e.style.width=b+"px");e.style.visibility="hidden";e.style.styleFloat="left";e.style.cssFloat="left";document.body.appendChild(e);h=window.getComputedStyle(e);b=h.getPropertyValue("width").slice(0,-2)-0;h=h.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(e);delete e;return[Math.ceil(b),Math.ceil(Math.max(a,h))]},getSize:function(b){b=b.cloneNode(!0);b.style.visibility="hidden";b.style.styleFloat="left";b.style.cssFloat="left";document.body.appendChild(b); -var a=b.offsetWidth,h=b.offsetHeight;document.body.removeChild(b);delete b;return[a,h]},getExcess:function(b){b=b.cloneNode(!0);b.style.visibility="hidden";b.style.styleFloat="left";b.style.cssFloat="left";document.body.appendChild(b);var a=b.offsetWidth,h=b.offsetHeight,e=window.getComputedStyle(b),c=e.getPropertyValue("width").slice(0,-2)-0,e=e.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(b);delete b;return[a-c,h-e]},groupForms:function(b){for(var b=Elm.JavaScript.castListToJSArray(b), -a=[],h=[],e=b.length;e--;){var c=b[e];switch(c[4][0]){case "FElement":0<h.length&&(a.push(h),h=[]);a.push(c);break;default:h.push(c)}}0<h.length&&a.push(h);return a},wrap:function(a){var g=Value.getSize(a);return["Element",Guid.guid(),["EHtml",a],g[0],g[1],1,Nothing,Nothing]},addListener:j}}(),Elm=Elm||{}; -Elm.List=function(){function d(a){return function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&c("map");for(var f=["Cons",a(b[1]),["Nil"]],e=f,b=b[2];"Cons"===b[0];)e[2]=["Cons",a(b[1]),["Nil"]],b=b[2],e=e[2];return f}}function a(a){return function(b){return function(f){var e=b;if("Nil"===f[0])return e;for("Cons"!==f[0]&&c("foldl");"Cons"===f[0];)e=a(f[1])(e),f=f[2];return e}}}function g(a){return function(b){return function(f){var e=b;if("Nil"===f[0])return e;"Cons"!==f[0]&&c("foldr");for(var n=[];"Cons"=== -f[0];)n.push(f[1]),f=f[2];for(f=n.length;f--;)e=a(n[f])(e);return e}}}function i(c){return function(b){var f;"Cons"!==b[0]?f=void 0:(f=b[1],b=b[2],f=a(c)(f)(b));return f}}function j(b){return function(a){return function(f){if("Nil"===f[0])return["Cons",a,["Nil"]];"Cons"!==f[0]&&c("scanl");for(var e=[a];"Cons"===f[0];)a=b(f[1])(a),e.push(a),f=f[2];for(var f=["Nil"],n=e.length;n--;)f=["Cons",e[n],f];return f}}}function b(c){return function(a){a:{for(var f=[function(c){return"Nil"!==c[0]?void 0:["Tuple2", -["Nil"],["Nil"]]},function(a){if("Cons"===a[0]){var f=a[1],a=a[2];var e=b(c)(a);"Tuple2"!==e[0]?f=void 0:(a=e[1],e=e[2],f=c(f)?["Tuple2",["Cons",f,a],e]:["Tuple2",a,["Cons",f,e]]);return f}}],e=f.length;e--;){var n=f[e](a);if(void 0!==n){a=n;break a}}a=void 0}return a}}function l(c){a:{for(var a=[function(c){return"Nil"!==c[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(c){if("Cons"!==c[0])c=void 0;else if(c=["Tuple2",c[1],l(c[2])],"Tuple2"!==c[0]||"Tuple2"!==c[1][0])c=void 0;else var a=c[1][1],b= -c[1][2],c="Tuple2"!==c[2][0]?void 0:["Tuple2",["Cons",a,c[2][1]],["Cons",b,c[2][2]]];return c}],b=a.length;b--;){var f=a[b](c);if(void 0!==f){c=f;break a}}c=void 0}return c}function h(c){return function(a){a:{for(var b=[function(c){return"Nil"!==c[0]?void 0:["Nil"]},function(c){if("Cons"===c[0]){var a=c[1];return"Nil"!==c[2][0]?void 0:["Cons",a,["Nil"]]}},function(a){if("Cons"===a[0]){var b=a[1];if("Cons"===a[2][0]){var f=a[2][1],a=a[2][2];return["Cons",b,["Cons",c,h(c)(["Cons",f,a])]]}}}],f=b.length;f--;){var e= -b[f](a);if(void 0!==e){a=e;break a}}a=void 0}return a}}function e(c){return function(a){a:{for(var b=[function(c){return"Nil"!==c[0]?void 0:["Nil"]},function(c){if("Cons"===c[0]){var a=c[1];return"Nil"!==c[2][0]?void 0:a}},function(a){if("Cons"===a[0]){var b=a[1];if("Cons"===a[2][0]){var f=a[2][1],a=a[2][2];return Value.append(b,Value.append(c,e(c)(["Cons",f,a])))}}}],f=b.length;f--;){var n=b[f](a);if(void 0!==n){a=n;break a}}a=void 0}return a}}var c=function(c){throw"Function '"+c+"' expecting a list!"; -},f=a(function(c){return function(a){return["Cons",c,a]}})(["Nil"]),n=g(function(c){return function(a){return Value.append(c,a)}})(["Nil"]),m=a(function(c){return function(a){return c&&a}})(!0),s=a(function(c){return function(a){return c||a}})(!1),p=a(function(c){return function(a){return c+a}})(0),k=a(function(c){return function(a){return c*a}})(1),u=i(function(c){return function(a){return Math.max(c,a)}}),x=i(function(c){return function(a){return Math.min(c,a)}});return{head:function(c){if("Cons"!== -c[0])throw"Error: 'head' only accepts lists of length greater than one.";return c[1]},tail:function(c){if("Cons"!==c[0])throw"Error: 'tail' only accepts lists of length greater than one.";return c[2]},last:function(c){if("Cons"!==c[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var a=c[1];"Cons"===c[0];)a=c[1],c=c[2];return a},map:d,foldl:a,foldr:g,foldl1:i,foldr1:function(a){return function(b){if("Nil"===b[0])throw"'foldr1' requires an non-empty list.";"Cons"!==b[0]&& -c("foldr1");for(var f=[];"Cons"===b[0];)f.push(b[1]),b=b[2];for(var b=f.pop(),e=f.length;e--;)b=a(f[e])(b);return b}},scanl:j,scanl1:function(c){return function(a){if("Cons"!==a[0])throw"Error: 'scanl1' requires a list of at least length 1.";return j(c)(a[1])(a[2])}},filter:function(a){return function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&c("filter");for(var f=[];"Cons"===b[0];)a(b[1])&&f.push(b[1]),b=b[2];for(var b=["Nil"],e=f.length;e--;)b=["Cons",f[e],b];return b}},length:function(c){for(var a= -0;"Cons"===c[0];)a+=1,c=c[2];return a},reverse:f,concat:n,concatMap:function(c){return function(a){return n(d(c)(a))}},and:m,or:s,all:function(c){return a(function(a){return function(b){return b&&c(a)}})(!0)},any:function(c){return a(function(a){return function(b){return b||c(a)}})(!1)},sum:p,product:k,maximum:u,minimum:x,partition:b,zipWith:function(a){return function(b){return function(f){if("Nil"===b[0]||"Nil"===f[0])return["Nil"];("Cons"!==b[0]||"Cons"!==f[0])&&c("zipWith");for(var e=[];"Cons"=== -b[0]&&"Cons"===f[0];)e.push(a(b[1])(f[1])),b=b[2],f=f[2];for(var f=["Nil"],n=e.length;n--;)f=["Cons",e[n],f];return f}}},zip:function(a){return function(b){if("Nil"===a[0]||"Nil"===b[0])return["Nil"];("Cons"!==a[0]||"Cons"!==b[0])&&c("zip");for(var f=[];"Cons"===a[0]&&"Cons"===b[0];)f.push(["Tuple2",a[1],b[1]]),a=a[2],b=b[2];for(var b=["Nil"],e=f.length;e--;)b=["Cons",f[e],b];return b}},unzip:l,intersperse:h,intercalate:e,sort:function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&c("sort");for(var b= -[];"Cons"===a[0];)b.push(a[1]),a=a[2];b.sort(function(c,a){return c-a});for(var a=["Nil"],f=b.length;f--;)a=["Cons",b[f],a];return a},take:function(a){return function(b){if(0>=a)return["Nil"];if("Nil"===b[0])return b;"Cons"!==b[0]&&c("take");var f=["Cons",b[1],["Nil"]],e=f,b=b[2];for(--a;"Cons"===b[0]&&0<a;)e[2]=["Cons",b[1],["Nil"]],e=e[2],b=b[2],--a;return f}},drop:function(a){return function(b){if("Nil"===b[0])return b;for("Cons"!==b[0]&&c("drop");"Cons"===b[0]&&0<a;)b=b[2],--a;return b}}}}(); -Elm=Elm||{}; -Elm.Maybe=function(){function d(a){return function(d){return"Just"===a[0]?["Cons",a[1],d]:d}}function a(a){return function(d){return function(j){var b=a(d);return"Just"===b[0]?["Cons",b[1],j]:j}}}return{Just:function(a){return["Just",a]},Nothing:["Nothing"],catMaybes:Elm.List.foldr(d)(["Nil"]),isJust:function(a){return"Just"===a[0]},isNothing:function(a){return"Nothing"===a[0]},fromMaybe:function(a){return function(d){return"Just"===d[0]?d[1]:a}},consMaybe:d,mapMaybe:function(g){return Elm.List.foldr(a(g))(["Nil"])},maybe:function(a){return function(d){return function(j){return"Just"=== -j[0]?d(j[1]):a}}}}}(); -(function(){for(var d in Elm)this[d]=Elm[d];if(Elm.Dict)throw"Module name collision, 'Dict' is already defined.";Elm.Dict=function(){function a(a){return function(c){return function(b){return function(f){return function(e){return["RBNode",a,c,b,f,e]}}}}}function g(a){return function(){switch(a[0]){case "RBEmpty":return z(Value.str("(min RBEmpty) is not defined"));case "RBNode":switch(a[4][0]){case "RBEmpty":return["Tuple2",a[2],a[3]]}return g(a[4])}throw"Non-exhaustive pattern match in case";}()} -function d(a){return function(c){var b;a:{switch(c[0]){case "RBEmpty":b=Nothing;break a;case "RBNode":b=function(){switch(compare(a)(c[2])[0]){case "EQ":return Just(c[3]);case "GT":return d(a)(c[5]);case "LT":return d(a)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case";}return b}}function j(a){return function(c){return function(b){var f;a:{switch(b[0]){case "RBEmpty":f=a;break a;case "RBNode":f=function(){switch(compare(c)(b[2])[0]){case "EQ":return b[3]; -case "GT":return j(a)(c)(b[5]);case "LT":return j(a)(c)(b[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case";}return f}}}function b(a){return function(c){return A(d(a)(c))}}function l(c){a:{switch(c[0]){case "RBNode":switch(c[5][0]){case "RBNode":c=a(c[1])(c[5][2])(c[5][3])(a(w)(c[2])(c[3])(c[4])(c[5][4]))(c[5][5]);break a}}c=z(Value.str("rotateLeft of a node without enough children"))}return c}function h(c){a:{switch(c[0]){case "RBNode":switch(c[4][0]){case "RBNode":c= -a(c[1])(c[4][2])(c[4][3])(c[4][4])(a(w)(c[2])(c[3])(c[4][5])(c[5]));break a}}c=z(Value.str("rotateRight of a node without enough children"))}return c}function e(c){a:{switch(c[0]){case "Black":c=w;break a;case "Red":c=C;break a}throw"Non-exhaustive pattern match in case";}return c}function c(c){a:{switch(c[0]){case "RBNode":switch(c[4][0]){case "RBNode":switch(c[5][0]){case "RBNode":c=a(e(c[1]))(c[2])(c[3])(a(e(c[4][1]))(c[4][2])(c[4][3])(c[4][4])(c[4][5]))(a(e(c[5][1]))(c[5][2])(c[5][3])(c[5][4])(c[5][5])); -break a}}}c=z(Value.str("color_flip called on a RBEmpty or RBNode with a RBEmpty child"))}return c}function f(a){a:switch(a[0]){case "RBNode":switch(a[5][0]){case "RBNode":switch(a[5][1][0]){case "Red":a=l(a);break a}}}a:switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":switch(a[4][4][0]){case "RBNode":switch(a[4][4][1][0]){case "Red":a=h(a);break a}}}}}a:switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":switch(a[5][0]){case "RBNode":switch(a[5][1][0]){case "Red":a= -c(a);break a}}}}}return a}function n(c){a:switch(c[0]){case "RBNode":switch(c[1][0]){case "Red":c=a(C)(c[2])(c[3])(c[4])(c[5]);break a}}return c}function m(c){return function(b){return function(e){var h=function(e){var n;a:{switch(e[0]){case "RBEmpty":n=a(w)(c)(b)(y)(y);break a;case "RBNode":n=function(){switch(compare(c)(e[2])[0]){case "EQ":return a(e[1])(e[2])(b)(e[4])(e[5]);case "GT":return a(e[1])(e[2])(e[3])(e[4])(h(e[5]));case "LT":return a(e[1])(e[2])(e[3])(h(e[4]))(e[5])}throw"Non-exhaustive pattern match in case"; -}();n=f(n);break a}throw"Non-exhaustive pattern match in case";}return n};return n(h(e))}}}function s(c){a:{switch(c[0]){case "RBNode":switch(c[4][0]){case "RBNode":switch(c[4][1][0]){case "Red":c=!0;break a}}}c=!1}return c}function p(c){a:{switch(c[0]){case "RBNode":switch(c[4][0]){case "RBNode":switch(c[4][4][0]){case "RBNode":switch(c[4][4][1][0]){case "Red":c=!0;break a}}}}c=!1}return c}function k(b){if(not(s(b))&¬(p(b))){b=c(b);a:switch(b[0]){case "RBNode":b:switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":b= -c(l(a(b[1])(b[2])(b[3])(b[4])(h(b[5]))));break b}}}break a}}return b}function u(b){return function(e){var d;a:{switch(e[0]){case "RBEmpty":d=y;break a;case "RBNode":if("LT"===compare(b)(e[2])[0]){d=k(e);b:{switch(d[0]){case "RBEmpty":d=z(Value.str("delLT on RBEmpty"));break b;case "RBNode":d=f(a(d[1])(d[2])(d[3])(del(d[4]))(d[5]));break b}break}}else{e=s(e)?h(e):e;b:{switch(e[0]){case "RBNode":switch(e[5][0]){case "RBEmpty":e=eq(b,e[2]);break b}}e=!1}if(e)d=y;else{var e=not,i;b:{switch(d[0]){case "RBNode":switch(d[5][0]){case "RBNode":switch(d[5][1][0]){case "Red":i= -!0;break b}}}i=!1}if(e=e(i)){e=not;b:{switch(d[0]){case "RBNode":switch(d[5][0]){case "RBNode":switch(d[5][4][0]){case "RBNode":switch(d[5][4][1][0]){case "Red":i=!0;break b}}}}i=!1}e=e(i)}e&&(d=c(d),d=p(d)?c(h(d)):d);b:{switch(d[0]){case "RBNode":e=eq(b,d[2]);break b}e=!1}if(e)b:{switch(d[0]){case "RBEmpty":d=z(Value.str("delEQ called on a RBEmpty"));break b;case "RBNode":i=g(d[5]);c:{switch(i[0]){case "Tuple2":e=i[1];break c}break}c:{switch(i[0]){case "Tuple2":i=i[2];break c}break}var e=a(d[1])(e)(i)(d[4]), -j=function(c){a:{switch(c[0]){case "RBNode":switch(c[4][0]){case "RBEmpty":c=y;break a}}c=k(c);b:{switch(c[0]){case "RBEmpty":c=y;break b;case "RBNode":c=f(a(c[1])(c[2])(c[3])(j(c[4]))(c[5]));break b}throw"Non-exhaustive pattern match in case";}}return c};d=n(j(d[5]));d=f(e(d));break b}break}else b:{switch(d[0]){case "RBEmpty":d=z(Value.str("delGT called on a RBEmpty"));break b;case "RBNode":d=f(a(d[1])(d[2])(d[3])(d[4])(del(d[5])));break b}break}}}break a}throw"Non-exhaustive pattern match in case"; -}return n(d)}}function x(c){return function(b){a:{switch(b[0]){case "RBEmpty":b=y;break a;case "RBNode":b=a(b[1])(b[2])(c(b[3]))(x(c)(b[4]))(x(c)(b[5]));break a}throw"Non-exhaustive pattern match in case";}return b}}function q(c){return function(a){return function(b){a:{switch(b[0]){case "RBEmpty":b=a;break a;case "RBNode":b=q(c)(c(b[2])(b[3])(q(c)(a)(b[4])))(b[5]);break a}throw"Non-exhaustive pattern match in case";}return b}}}function r(c){return function(a){return function(b){a:{switch(b[0]){case "RBEmpty":b= -a;break a;case "RBNode":b=r(c)(c(b[2])(b[3])(r(c)(a)(b[5])))(b[4]);break a}throw"Non-exhaustive pattern match in case";}return b}}}var t=[],v;for(v in Elm.Prelude)0<=t.indexOf(v)||(this[v]=Elm.Prelude[v]);var A=Elm.Maybe.isJust,w=["Red"],C=["Black"],y=["RBEmpty"],B=y,z=console.log;return{empty:B,lookup:d,findWithDefault:j,member:b,insert:m,singleton:function(c){return function(a){return m(c)(a)(y)}},remove:u,map:x,foldl:q,foldr:r,union:function(c){return function(a){return q(m)(a)(c)}},intersect:function(c){return function(a){return q(function(c){return function(f){return function(e){return b(c)(a)? -m(c)(f)(e):e}}})(B)(c)}},diff:function(c){return function(a){return q(function(c){return function(){return function(a){return u(c)(a)}}})(c)(a)}},keys:function(c){return q(function(c){return function(){return function(a){return["Cons",c,a]}}})(["Nil"])(c)},values:function(c){return q(function(){return function(c){return function(a){return["Cons",c,a]}}})(["Nil"])(c)},toList:function(c){return q(function(c){return function(a){return function(b){return["Cons",["Tuple2",c,a],b]}}})(["Nil"])(c)},fromList:function(c){return List.foldl(uncurry(m))(B)(c)}}}()})(); -(function(){for(var d in Elm)this[d]=Elm[d];Elm.Set=function(){var a=[],d;for(d in Elm.Prelude)0<=a.indexOf(d)||(this[d]=Elm.Prelude[d]);a=Dict.empty;d=Dict.remove;var i=Dict.member,j=Dict.union,b=Dict.intersect,l=Dict.diff,h=Dict.keys,e=List.foldl(function(c){return function(a){return Dict.insert(c)(["Tuple0"])(a)}})(a);return{empty:a,singleton:function(c){return Dict.singleton(c)(["Tuple0"])},insert:function(c){return Dict.insert(c)(["Tuple0"])},remove:d,member:i,union:j,intersect:b,diff:l,toList:h, -fromList:e,foldl:function(c){return Dict.foldl(function(a){return function(){return function(b){return c(a)(b)}}})},foldr:function(c){return Dict.foldr(function(a){return function(){return function(b){return c(a)(b)}}})},map:function(c){return function(a){a=h(a);return e(List.map(c)(a))}}}}()})();Elm=Elm||{}; -Elm.Char=function(){function d(a,b){return function(d){d=d.charCodeAt(0);return a<=d&&d<=b}}var a=d(48,57),g=d(97,102),i=d(65,70);return{fromCode:function(a){return String.fromCharCode(a)},toCode:function(a){return a.charCodeAt(0)},toUpper:function(a){return a.toUpperCase()},toLower:function(a){return a.toLowerCase()},toLocaleUpper:function(a){return a.toLocaleUpperCase()},toLocaleLower:function(a){return a.toLocaleLowerCase()},isLower:d(97,122),isUpper:d(65,90),isDigit:a,isOctDigit:d(48,55),isHexDigit:function(d){return a(d)|| -g(d)||i(d)}}}();Elm=Elm||{}; -Elm.Color=function(){return{rgba:function(d){return function(a){return function(g){return function(i){return["Color",d,a,g,i]}}}},rgb:function(d){return function(a){return function(g){return["Color",d,a,g,1]}}},red:["Color",255,0,0,1],green:["Color",0,255,0,1],blue:["Color",0,0,255,1],yellow:["Color",255,255,0,1],cyan:["Color",0,255,255,1],magenta:["Color",255,0,255,1],black:["Color",0,0,0,1],white:["Color",255,255,255,1],gray:["Color",128,128,128,1],grey:["Color",128,128,128,1],complement:function(d){var a, -g=d[1]/255;a=d[2]/255;var i=d[3]/255,d=Math.max(g,a,i),j=Math.min(g,a,i),j=d-j,b=0;0===j?b=0:d===g?b=(a-i)/j%6:d===a?b=(i-g)/j+2:d===i&&(b=(g-a)/j+4);a=60*b;var g=d*(0===d?0:j/d),b=(a+180)%360/60,l=g*(1-Math.abs(b%2-1)),j=i=a=0;0<=b&&1>b?(a=g,i=l,j=0):1<=b&&2>b?(a=l,i=g,j=0):2<=b&&3>b?(a=0,i=g,j=l):3<=b&&4>b?(a=0,i=l,j=g):4<=b&&5>b?(a=l,i=0,j=g):5<=b&&6>b&&(a=g,i=0,j=l);d-=g;return["Color",Math.round(255*(a+d)),Math.round(255*(i+d)),Math.round(255*(j+d)),1]},extract:function(d){return 1===d[4]?"rgb("+ -d[1]+","+d[2]+","+d[3]+")":"rgba("+d[1]+","+d[2]+","+d[3]+","+d[4]+")"}}}(); -var Collage=function(){function d(a,c){var b=c.length-1;if(!(0>=b))for(a.moveTo(c[b][1],c[b][2]);b--;)a.lineTo(c[b][1],c[b][2])}function a(a,c,b,d){0===a.length&&(a=[8,4]);var h=d.length-1;if(!(0>=h)){var g=d[h][1],i=d[h][2],k=0,j=0,l=0,q=0,r=0,t=0,v=a.length,A=!0,w=a[0];for(c.moveTo(g,i);h--;){k=d[h][1];j=d[h][2];l=k-g;q=j-i;for(r=Math.sqrt(l*l+q*q);w<=r;)g+=l*w/r,i+=q*w/r,c[A?"lineTo":"moveTo"](g,i),l=k-g,q=j-i,r=Math.sqrt(l*l+q*q),A=!A,t=(t+1)%v,w=a[t];0<r&&(c[A?"lineTo":"moveTo"](k,j),w-=r);g= -k;i=j}}c.strokeStyle=Elm.Color.extract(b);c.stroke()}function g(b,c,f,n,g){c.clearRect(0,0,f,n);for(f=g.length;f--;){var i=g[f],p=b,n=c,k=i[1],j=i[2],l=i[3][1],q=i[3][2],i=i[4];n.save();(0!==l||0!==q)&&n.translate(l,q);k!==~~k&&n.rotate(2*Math.PI*k);1!==j&&n.scale(j,j);n.beginPath();switch(i[0]){case "FLine":a:switch(p=n,k=i,i=k[3][1],k[1][0]){case "Solid":k=k[2];d(p,i);p.strokeStyle=Elm.Color.extract(k);p.stroke();break;case "Dotted":a([3,3],p,k[2],i);break a;case "Dashed":a([8,4],p,k[2],i);break a; -case "Custom":a(k[1][1],p,k[2],i)}break;case "FShape":a:switch(l=p,j=n,p=i[1],k=i[2],i=i[3][1],p[0]){case "Filled":p=j;d(p,i);p.fillStyle=Elm.Color.extract(k);p.fill();break a;case "Outlined":p=j;d(p,i);p.strokeStyle=Elm.Color.extract(k);p.stroke();break a;case "Textured":k=l;p=p[1];l=new Image;l.src=h.castStringToJSString(p);l.onload=k;d(j,i);j.fillStyle=j.createPattern(l,"repeat");j.fill();break a;case "CustomOutline":a(p[1],j,k,i)}break;case "FImage":k=n,j=i[1],l=i[2],i=i[3],q=new Image,q.onload= -p,q.src=h.castStringToJSString(i),k.drawImage(q,-j/2,-l/2,j,l)}n.restore()}}function i(a,c,b){var d=Render.newElement("canvas");d.style.width=~~a+"px";d.style.height=~~c+"px";d.style.display="block";d.width=~~a;d.height=~~c;if(d.getContext){var h=d.getContext("2d"),a=d.width,c=d.height;g(function(){g(this,h,a,c,b)},h,a,c,b);return d}d.innerHTML="Your browser does not support the canvas element.";return d}function j(a,c,b,d,h,i,g){var k=Render.render(g),b="translate("+(h-g[3]/2)+"px,"+(i-g[4]/2)+"px) "+ -(1===d?"":"scale("+d+","+d+")")+" "+(b===~~b?"":"rotate("+360*b+"deg)");k.style.transform=b;k.style.msTransform=b;k.style.MozTransform=b;k.style.webkitTransform=b;k.style.OTransform=b;b=Render.newElement("div");Render.addTo(b,k);b.style.width=~~a+"px";b.style.height=~~c+"px";b.style.overflow="hidden";return b}function b(a,c,b){if(!Value.eq(b,c)){var d=a.style.width.slice(0,-2)-0,h=a.style.height.slice(0,-2)-0;if("object"===typeof b[0]){if("object"===typeof c[0]&&a.getContext){var l=a.getContext("2d"); -return g(function(){g(this,l,d,h,b)},l,d,h,b)}c=i(d,h,b);c.style.position="absolute";return a.parentNode.replaceChild(c,a)}c=j(d,h,b[1],b[2],b[3][1],b[3][2],b[4][1]);c.style.position="absolute";return a.parentNode.replaceChild(c,a)}}function l(a,c,b,d,h){var i=0,g,k=(a[1]-d[1])/b,a=(a[2]-d[2])/b;0!==c&&(c*=-2*Math.PI,b=k*Math.cos(c)-a*Math.sin(c),a=k*Math.sin(c)+a*Math.cos(c),k=b);if(0===h.length)return!1;g=h[0];for(b=h.length-1;b--;){c=h[b];d=g[1];g=g[2];var j=c[1],l=c[2];if(g<l)var q=g,r=l;else q= -l,r=g;if(d<j)var t=d,v=j;else t=j,v=d;q<a&&a<=r&&k<=v&&(k<=t||k<=(a-g)*(j-d)/(l-g)+d)&&++i;g=c}return 1===i%2}var h=Elm.JavaScript;return{collage:function(a,c,b){if(0===b.length)return i(a,c,[]);for(var d=Array(b.length),h=b.length;h--;){var g=b[h];d[h]="string"===typeof g[0]?j(a,c,g[1],g[2],g[3][1],g[3][2],g[4][1]):i(a,c,g)}return 1===b.length?d[0]:Render.flowWith(Render.goIn,function(c){return c},d)},updateCollage:function(a,c,f){if(1===f.length)return b(a,c[0],f[0]);for(var a=a.childNodes,d=a.length, -h=d;h--;)b(a[d-h-1],c[h],f[h])},insideForm:function(a){return function(c){var b=a[1],d=a[2];if(6>c.length){var h=c[3][1],g=c[3][2],i=0,j=c[2];switch(c[4][0]){case "FShape":for(var u=c[4][3][1],x=u.length;--x;)var q=u[x],i=Math.max(i,q[1]*q[1]+q[2]*q[2]);i*=j*j;break;case "FImage":u=j*c[4][1]/2;j=j*c[4][2]/2;i=u*u+j*j;break;case "FElement":u=j*c[4][1][3]/2,j=j*c[4][1][4]/2,i=u*u+j*j}c.push(function(c,a){var b=c-h,f=a-g;return b*b+f*f<i+1})}if(!c[5](b,d))return!1;var r,t;switch(c[4][0]){case "FShape":return l(a, -c[1],c[2],c[3],c[4][3][1]);case "FLine":return!1;case "FImage":r=c[4][1]/2;t=c[4][2]/2;break;case "FElement":r=c[4][1][3]/2,t=c[4][1][4]/2}return l(a,c[1],c[2],c[3],[[null,r,t],[null,-r,t],[null,-r,-t],[null,r,-t],[null,r,t]])}}}}(),Elm=Elm||{}; -Elm.Graphics=function(){function d(c){return function(a){return["Position",c,a]}}function a(c){return function(a){return["EText",c,a]}}function g(c){return function(a){return["EFlow",c,k.castListToJSArray(a)]}}function i(c){return["Line",k.castListToJSArray(c)]}function j(c){return function(a){var b=k.castListToJSArray(c);0<b.length&&b.push(b[0]);return["Shape",b,a]}}function b(c){return function(a){return function(b){return function(f){return["Form",c,a,b,f]}}}}function l(c){return function(a){return function(b){return["FLine", -c,a,b]}}}function h(c){return function(a){return function(b){return["FShape",c,a,b]}}}function e(c,a,b,f,d,e){return["Element",Guid.guid(),c,a,b,f,d,e]}function c(c,a,b){return["Element",Guid.guid(),c,a,b,1,Nothing,Nothing]}function f(c){return~~c[3]}function n(c){return~~c[4]}function m(a){return function(b){return function(f){return c(["EImage",k.castStringToJSString(f)],a,b)}}}function s(a){return function(b){return c(A,a,b)}}function p(c){return function(a){return function(b){var f=map(function(b){return["Tuple2", -c/2*cos(2*(pi/50)*b),a/2*sin(2*(pi/50)*b)]}),d=49,e=["Nil"];if(0<=d){do e=["Cons",d,e];while(0<d--)}return j(f(e))(b)}}}var k=Elm.JavaScript,u=["DRight"],x=["DDown"],q=["DOut"],r=["Near"],t=["Mid"],v=["Far"],A=["EEmpty"],w=["Solid"],C=["Dotted"],y=["Dashed"],B=["Filled"],z=["Outlined"],D=d(r)(r),E=d(v)(r),F=d(r)(v),G=d(v)(v),H=d(r)(t),I=d(v)(t),r=d(t)(r),v=d(t)(v),t=d(t)(t);return{left:["DLeft"],right:u,down:x,up:["DUp"],inward:["DIn"],outward:q,topLeft:D,topRight:E,bottomLeft:F,bottomRight:G,midLeft:H, -midRight:I,midTop:r,midBottom:v,middle:t,middleAt:function(c){return function(a){return["PositionAt",c,a]}},topLeftAt:function(c){return function(a){return["PositionTL",c,a]}},topRightAt:function(c){return function(a){return["PositionTR",c,a]}},bottomLeftAt:function(c){return function(a){return["PositionBL",c,a]}},bottomRightAt:function(c){return function(a){return["PositionBR",c,a]}},absolute:function(c){return["Absolute",c]},relative:function(c){return["Relative",c]},width:function(c){return function(a){var b= -a[2];switch(b[0]){case "EImage":case "EVideo":return e(a[2],c,a[4]*c/a[3],a[5],a[6],a[7]);case "EText":return b=Value.getTextSize(c,a[4],b[2]),e(a[2],c,b[1],a[5],a[6],a[7])}return e(a[2],c,a[4],a[5],a[6],a[7])}},height:function(a){return function(c){switch(c[2][0]){case "EImage":case "EVideo":return e(c[2],c[3]*a/c[4],a,c[5],c[6],c[7])}return e(c[2],c[3],a,c[5],c[6],c[7])}},size:function(c){return function(a){return function(b){return e(b[2],c,a,b[5],b[6],b[7])}}},opacity:function(c){return function(a){return e(a[2], -a[3],a[4],c,a[6],a[7])}},color:function(c){return function(a){return e(a[2],a[3],a[4],a[5],Just(c),a[7])}},link:function(a){return function(c){return e(c[2],c[3],c[4],c[5],c[6],Just(k.castStringToJSString(a)))}},widthOf:f,heightOf:n,sizeOf:function(c){return["Tuple2",~~c[3],~~c[4]]},text:function(b){var f=Value.getTextSize(0,0,b);return c(a("left")(b),f[0],f[1])},asText:function(b){var b=monospace(Value.toText(Value.show(b))),f=Value.getTextSize(0,0,b);return c(a("left")(b),f[0],f[1])},plainText:function(b){var b= -Value.toText(b),f=Value.getTextSize(0,0,b);return c(a("left")(b),f[0],f[1])},centeredText:function(b){var f=Value.getTextSize(0,0,b);return c(a("center")(b),f[0],f[1])},justifiedText:function(b){var f=Value.getTextSize(0,0,b);return c(a("justify")(b),f[0],f[1])},rightedText:function(b){var f=Value.getTextSize(0,0,b);return c(a("right")(b),f[0],f[1])},image:m,images:function(c){var a=Elm.Signal.constant(s(0)(0)),c=Elm.Signal.lift(function(c){var c=k.castStringToJSString(c),b=new Image;b.onload=function(){Dispatcher.notify(a.id, -m(this.width)(this.height)(c))};b.src=c})(c);return Elm.Signal.lift2(function(c){return function(){return c}})(a)(c)},video:function(a){return function(b){return function(f){return c(["EVideo",k.castStringToJSString(f)],a,b)}}},fittedImage:function(a){return function(b){return function(f){return c(["EFittedImage",k.castStringToJSString(f)],a,b)}}},flow:function(a){return function(b){var d;d=map(f)(b);a:{switch(a[0]){case "DLeft":d=sum(d);break a;case "DRight":d=sum(d);break a}d=maximum(d)}var e;e= -map(n)(b);a:{switch(a[0]){case "DDown":e=sum(e);break a;case "DUp":e=sum(e);break a}e=maximum(e)}return c(g(a)(b),d,e)}},above:function(a){return function(b){return c(g(x)(["Cons",a,["Cons",b,["Nil"]]]),max(~~a[3])(~~b[3]),~~a[4]+~~b[4])}},below:function(a){return function(b){return c(g(x)(["Cons",b,["Cons",a,["Nil"]]]),max(~~a[3])(~~b[3]),~~a[4]+~~b[4])}},beside:function(a){return function(b){return c(g(u)(["Cons",a,["Cons",b,["Nil"]]]),~~a[3]+~~b[3],max(~~a[4])(~~b[4]))}},layers:function(a){return c(g(q)(a), -maximum(map(f)(a)),maximum(map(n)(a)))},collage:function(a){return function(b){return function(f){return c(["ECollage",a,b,Value.groupForms(f)],a,b)}}},spacer:s,container:function(a){return function(b){return function(f){return function(d){return c(["EContainer",f,d],a,b)}}}},line:i,segment:function(a){return function(c){return i(["Cons",a,["Cons",c,["Nil"]]])}},polygon:j,rect:function(a){return function(c){return function(b){return j(["Cons",["Tuple2",0-a/2,0-c/2],["Cons",["Tuple2",0-a/2,c/2],["Cons", -["Tuple2",a/2,c/2],["Cons",["Tuple2",a/2,0-c/2],["Nil"]]]]])(b)}}},oval:p,circle:function(a){return p(2*a)(2*a)},ngon:function(a){return function(c){return function(b){var f=toFloat(a),d=map(function(a){return["Tuple2",c*cos(2*(pi/f)*a),c*sin(2*(pi/f)*a)]}),e=a-1,h=["Nil"];if(0<=e){do h=["Cons",e,h];while(0<e--)}return j(d(h))(b)}}},solid:function(a){return function(c){return b(0)(1)(["Tuple2",0,0])(l(w)(a)(c))}},dotted:function(a){return function(c){return b(0)(1)(["Tuple2",0,0])(l(C)(a)(c))}},dashed:function(a){return function(c){return b(0)(1)(["Tuple2", -0,0])(l(y)(a)(c))}},customLine:function(a){return function(c){return function(f){return b(0)(1)(["Tuple2",0,0])(l(["Custom",k.castListToJSArray(a)])(c)(f))}}},filled:function(a){return function(c){return b(0)(1)(c[2])(h(B)(a)(c))}},outlined:function(a){return function(c){return b(0)(1)(c[2])(h(z)(a)(c))}},customOutline:function(a){return function(c){return function(f){return b(0)(1)(f[2])(h(["CustomOutline",k.castListToJSArray(a)])(c)(f))}}},textured:function(a){return function(c){return b(0)(1)(c[2])(h(["Textured", -a])(null)(c))}},sprite:function(a){return function(c){return function(f){return function(d){return b(0)(1)(d)(["FImage",c,f,k.castStringToJSString(a)])}}}},toForm:function(a){return function(c){return b(0)(1)(a)(["FElement",c])}},rotate:function(a){return function(c){a:{switch(c[0]){case "Form":var f=c[2],d=c[3],e=c[4],c=b(a+c[1])(f)(d)(e);break a}throw"Non-exhaustive pattern match in case";}return c}},scale:function(a){return function(c){return b(c[1])(a*c[2])(c[3])(c[4])}},move:function(a){return function(c){return function(f){var d; -a:{switch(f[0]){case "Form":d=f[1];var e=f[2],h=f[3],f=f[4];switch(h[0]){case "Tuple2":var g=h[1],h=h[2];d=b(d)(e)(["Tuple2",a+g,c+h])(f);break a}}throw"Non-exhaustive pattern match in case";}return d}}},isWithin:Collage.insideForm}}();Elm=Elm||{}; -Elm.Text=function(){function d(a){return Value.toText(a)}var a=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},g=function(a,b){return function(d){return"<span style='"+a+":"+b+"'>"+d+"</span>"}},i=function(a){a=Elm.JavaScript.castStringToJSString(a);return g("font-family",a)},j=a("h1"),b=g("font-style","italic"),a=a("b"),l=g("text-decoration","underline"),h=g("text-decoration","overline"),e=g("text-decoration","line-through");return{fromString:d,toText:d,header:j, -height:function(a){return g("font-size",a+"em")},italic:b,bold:a,underline:l,overline:h,strikeThrough:e,monospace:i("monospace"),typeface:i,color:function(a){return g("color",Elm.Color.extract(a))},link:function(a){return function(b){return"<a href='"+d(a)+"'>"+b+"</a>"}}}}(); -var Render=function(){function d(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a}function a(a){return a}function g(a){a.style.styleFloat="left";a.style.cssFloat="left";return a}function i(a){a.style.position="absolute";return a}function j(a,b,e){for(var h=d("div"),g=e.length;g--;){var i=a(b(e[g]));h.appendChild(i)}return h}function b(a){switch(a[0]){case "Absolute":return a[1]+"px";case "Relative":return 100*a[1]+"%"}}function l(a,f){f.style.position="absolute";f.style.margin= -"auto";switch(a[0]){case "Position":"Far"!==a[1][0]&&(f.style.left=0);"Near"!==a[1][0]&&(f.style.right=0);"Far"!==a[2][0]&&(f.style.top=0);"Near"!==a[2][0]&&(f.style.bottom=0);break;case "PositionAt":f.style.top=b(a[2]);f.style.left=b(a[1]);var d="translate("+-elem[3]/2+"px,"+-elem[4]/2+"px)";f.style.transform=d;f.style.msTransform=d;f.style.MozTransform=d;f.style.webkitTransform=d;f.style.OTransform=d;break;default:d=a[0].slice(-2),f.style["T"===d[0]?"top":"bottom"]=b(a[2]),f.style["L"===d[1]?"left": -"right"]=b(a[1])}}function h(c){var b={};switch(c[2][0]){case "EText":var b=c[2][1],e=c[2][2],m=d("div");m.innerHTML=e;m.style.textAlign=b;b=m;break;case "EImage":b=c[2][1];e=d("img");e.src=b;e.name=b;e.style.display="block";b=e;break;case "EVideo":m=c[2][1];b=d("video");b.controls="controls";e=d("source");e.src=m;m=m.split(".");e.type="video/"+m[m.length-1];b.appendChild(e);b.style.display="block";break;case "EFittedImage":var s=c[3],p=c[4],b=c[2][1],e=d("div");e.style.width=s+"px";e.style.height= -p+"px";e.style.position="relative";e.style.overflow="hidden";var k=d("img");k.onload=function(){k.style.position="absolute";k.style.margin="auto";var a=s,b=p;s/p>this.width/this.height?b=Math.round(this.height*s/this.width):a=Math.round(this.width*p/this.height);k.style.width=a+"px";k.style.height=b+"px";k.style.left=(s-a)/2+"px";k.style.top=(p-b)/2+"px"};k.src=b;k.name=b;e.appendChild(k);b=e;break;case "EFlow":a:{b=c[2][2];switch(c[2][1][0]){case "DDown":b=b.slice(0).reverse();case "DUp":b=j(a,h, -b);break a;case "DRight":b=b.slice(0).reverse();case "DLeft":b=j(g,h,b);break a;case "DOut":b=b.slice(0).reverse();case "DIn":b=j(i,h,b);break a}b=void 0}break;case "ECollage":b=Collage.collage(c[2][1],c[2][2],c[2][3]);break;case "EEmpty":b=d("div");break;case "EContainer":e=c[2][1];b=h(c[2][2]);l(e,b);e=d("div");e.style.position="relative";e.style.overflow="hidden";e.appendChild(b);b=e;break;case "EHtml":b=c[2][1];"button"!==b.type&&(e=Value.getExcess(b),c[3]-=e[0],c[4]-=e[1]);break;case "EExternalHtml":b= -d("div"),b.appendChild(c[2][1])}b.id=c[1];b.style.width=~~c[3]+"px";b.style.height=~~c[4]+"px";1!==c[5]&&(b.style.opacity=c[5]);"Just"===c[6][0]&&(b.style.backgroundColor=Elm.Color.extract(c[6][1]));return"Just"===c[7][0]?(e=d("a"),e.href=c[7][1],e.appendChild(b),e):b}function e(b,d,j){"A"===b.tagName&&(b=b.firstChild);if(d[1]!==j[1]){if(d[2][0]!==j[2][0])return b.parentNode.replaceChild(h(j),b);var m=j[2],s=d[2];switch(m[0]){case "EText":m[1]!==s[1]&&(b.style.textAlign=m[1]);m[2]!==s[2]&&(b.innerHTML= -m[2]);break;case "EImage":m[1]!==s[1]&&(b.src=m[1]);break;case "EVideo":case "EFittedImage":if(!Value.eq(m,s)||j[3]!==d[3]||j[4]!==d[4])return b.parentNode.replaceChild(h(j),b);break;case "ECollage":if(m[1]!==s[1]||m[2]!==s[2]||m[3].length!==s[3].length)return b.parentNode.replaceChild(h(j),b);Collage.updateCollage(b,s[3],m[3]);break;case "EFlow":if(m[1]!==s[1])return b.parentNode.replaceChild(h(j),b);var p=m[2],k=b.childNodes;if(p.length!==k.length)return b.parentNode.replaceChild(h(j),b);var s= -s[2],u={};switch(m[1][0]){case "DDown":case "DUp":u=a;break;case "DRight":case "DLeft":u=g;break;case "DOut":case "DIn":u=i}for(m=k.length;m--;)e(k[m],s[m],p[m]),u(k[m]);break;case "EContainer":e(b.childNodes[0],s[2],m[2]);l(m[1],b.childNodes[0]);break;case "EHtml":j[1]!==d[1]&&(p=h(j),b.parentNode.replaceChild(p,b),b=p);"button"!==p.type&&(m=Value.getExcess(b),j[3]-=m[0],j[4]-=m[1]);break;case "EExternalHtml":j[1]!==d[1]&&b.parentNode.replaceChild(h(j),b)}j[3]!==d[3]&&(b.style.width=~~j[3]+"px"); -j[4]!==d[4]&&(b.style.height=~~j[4]+"px");j[5]!==d[5]&&(b.style.opacity=j[5]);2===j[6].length&&(m=Elm.Color.extract(j[6][1]),m!==b.style.backgroundColor&&(b.style.backgroundColor=m));if(2===j[7].length&&(1===d[7].length||j[7][1]!==d[7][1]))b.parentNode.href=j[7][1];j[1]=d[1]}}return{render:h,update:e,addTo:function(a,b){a.appendChild(b)},newElement:d,flowWith:j,goIn:i}}(),Elm=Elm||{}; -Elm.Signal=function(){var d=function(a,b,d){for(var h=a.kids,g=h.length;g--;)h[g].recv(b,d,a.id)},a=function(a){this.id=Guid.guid();this.value=a;this.kids=[];this.defaultNumberOfKids=0;this.recv=function(a,b,e){if(b=b===this.id)this.value=e;d(this,a,b);return b};Dispatcher.inputs.push(this)},g=function(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.count=0;this.changed=!1;b.reverse();this.recalc=function(){for(var d=a,f=b.length;f--;)d=d(b[f].value);this.value=d};this.recalc();this.recv= -function(a,e){this.count+=1;e&&(this.changed=!0);this.count==b.length&&(this.changed&&this.recalc(),d(this,a,this.changed),this.changed=!1,this.count=0)};for(var f=b.length;f--;)b[f].kids.push(this)},i=function(a,b,f,h){this.id=Guid.guid();this.value=f?b(h.value):b;this.kids=[];this.recv=function(b,c){c&&(this.value=a(h.value)(this.value));d(this,b,c)};h.kids.push(this)},j=function(a,b,f){this.id=Guid.guid();this.value=a(f.value)?b:f.value;this.kids=[];this.recv=function(b,c){var h=c&&!a(f.value); -h&&(this.value=f.value);d(this,b,h)};f.kids.push(this)},b=function(a){this.id=Guid.guid();this.value=a.value;this.kids=[];this.recv=function(b,f){var h=f&&!eq(this.value,a.value);h&&(this.value=a.value);d(this,b,h)};a.kids.push(this)},l=function(a){return function(b){return function(d){d=new g(function(a){return function(b){return[a,b]}},[a,d]);d=new j(function(a){return a[0]},[!0,b],d);return new g(function(a){return a[1]},[d])}}},h=function(a,b){this.id=Guid.guid();this.value=b.value;this.kids= -[];this.count=0;this.changed=!1;this.recv=function(f,h,g){g===a.id&&(this.changed=h);this.count+=1;2==this.count&&(this.changed&&(this.value=b.value),d(this,f,this.changed),this.count=0,this.changed=!1)};a.kids.push(this);b.kids.push(this)};return{constant:function(b){return new a(b)},lift:function(a){return function(b){return new g(a,[b])}},lift2:function(a){return function(b){return function(d){return new g(a,[b,d])}}},lift3:function(a){return function(b){return function(d){return function(h){return new g(a, -[b,d,h])}}}},lift4:function(a){return function(b){return function(d){return function(h){return function(i){return new g(a,[b,d,h,i])}}}}},foldp:function(a){return function(b){return function(d){return new i(a,b,!1,d)}}},foldp_:function(a){return function(b){return function(d){return new i(a,b,!0,d)}}},foldp1:function(a){return function(b){return new i(a,function(a){return a},!0,b)}},count:function(a){return new i(function(){return function(a){return a+1}},0,!1,a)},keepIf:function(a){return function(b){return function(d){return new j(function(b){return!a(b)}, -b,d)}}},dropIf:function(a){return function(b){return function(d){return new j(a,b,d)}}},keepWhen:function(a){return l(new g(function(a){return!a},[a]))},dropWhen:l,dropRepeats:function(a){return new b(a)},sampleOn:function(a){return function(b){return new h(a,b)}}}}(); -var Dispatcher=function(){function d(a){if(!a.hasOwnProperty("defaultNumberOfKids"))return!0;var g=a.kids.length;if(0==g)return!1;if(g>a.defaultNumberOfKids)return!0;for(var h=!1;g--;)h=h||d(a.kids[g]);return h}var a=null,g=0,i=[],j=null;return{initialize:function(){a=Elm.main();a.hasOwnProperty("recv")||(a=Elm.Signal.constant(a));j=a.value;for(var b=[],g=i.length;g--;)d(i[g])&&b.push(i[g]);i=b;document.getElementById("content").appendChild(Render.render(j));b=document.getElementById("widthChecker").offsetWidth; -b!==window.innerWidth&&Dispatcher.notify(Window.dimensions.id,Value.Tuple(b,window.innerHeight));a=Elm.Signal.lift(function(a){var b=document.getElementById("content");Render.update(b.firstChild,j,a);return j=a})(a)},notify:function(a,d){g+=1;for(var h=!1,e=i.length;e--;)h=i[e].recv(g,a,d)||h;return h},inputs:i}}(); -Elm.HTTP=function(){function d(a){return function(d){return function(c){return function(f){return{"0":"Request",length:1,verb:b.castStringToJSString(a),url:b.castStringToJSString(d),data:null===c?null:b.castStringToJSString(c),headers:f}}}}}function a(a){return d("GET")(a)(null)(["Nil"])}function g(a,d){return function(c){if(""!==c.url){var f={value:["Waiting"]};a.push(f);var g=null;window.ActiveXObject&&(g=new ActiveXObject("Microsoft.XMLHTTP"));window.XMLHttpRequest&&(g=new XMLHttpRequest);g.onreadystatechange= -function(){4===g.readyState&&(f.value=200===g.status?["Success",l(g.responseText)]:["Failure",g.status,l(g.statusText)],setTimeout(function(){i(a,d)},0))};g.open(c.verb,c.url,!0);Elm.List.map(function(a){g.setRequestHeader(b.castStringToJSString(a[1]),b.castStringToJSString(a[2]))})(c.headers);g.send(c.data)}}}function i(a,b){0<a.length&&(Dispatcher.notify(b.id,a[0].value),"Waiting"!==a[0].value[0]&&(a.shift(),setTimeout(function(){i(a,b)},0)))}function j(a){var b=Elm.Signal.constant(["Waiting"]), -a=Elm.Signal.lift(g([],b))(a);return Elm.Signal.lift2(function(a){return function(){return a}})(b)(a)}var b=Elm.JavaScript,l=Elm.JavaScript.castJSStringToString;return{get:a,post:function(a){return function(b){return d("POST")(a)(b)(["Nil"])}},request:d,send:j,sendGet:function(b){return j(Elm.Signal.lift(a)(b))}}}(); -Elm.Input=function(){var d=Elm.JavaScript,a=Elm.JavaScript.castJSStringToString,g=function(b,g){b.placeholder=d.castStringToJSString(g);var h=Elm.Signal.constant(["Nil"]);Value.addListener(b,"keyup",function(){Dispatcher.notify(h.id,a(b.value));b.focus()});b.style.padding="1px";return Value.Tuple(Value.wrap(b),h)},i=function(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a},j=function(a){for(var d=i("select"),g=[];"Cons"===a[0];){var e=i("option"),c=Value.toText(a[1][1]); -e.value=c;e.innerHTML=c;d.appendChild(e);g.push(a[1][2]);a=a[2]}var f=Elm.Signal.constant(g[0]);Value.addListener(d,"change",function(){Dispatcher.notify(f.id,g[d.selectedIndex])});return Value.Tuple(Value.wrap(d),f)};return{textArea:function(a){return function(d){var h=i("textarea");h.rows=d;h.cols=a;return g(h,"")}},textField:function(a){var d=i("input");d.type="text";return g(d,a)},password:function(a){var d=i("input");d.type="password";return g(d,a)},checkbox:function(a){var d=i("input");d.type= -"checkbox";d.checked=a;var g=Elm.Signal.constant(a);Value.addListener(d,"change",function(){Dispatcher.notify(g.id,d.checked)});return Value.Tuple(Value.wrap(d),g)},dropDown:j,stringDropDown:function(a){return j(Elm.List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var g=i("input");g.type="button";g.value=d.castStringToJSString(a);var h=Elm.Signal.constant(!1);Value.addListener(g,"click",function(){Dispatcher.notify(h.id,!0);Dispatcher.notify(h.id,!1)});return Value.Tuple(Value.wrap(g), -h)}}}(); -Elm.Keyboard={Raw:function(){function d(a,g){return"Nil"===g[0]?g:g[1]===a?g[2]:["Cons",g[1],d(a,g[2])]}var a=Elm.Signal.constant(["Nil"]),g=Elm.Signal.constant(["Nothing"]);Value.addListener(document,"keydown",function(d){var g;a:{for(g=a.value;"Nil"!==g[0];){if(g[1]===d.keyCode){g=!0;break a}g=g[2]}g=!1}g||Dispatcher.notify(a.id,["Cons",d.keyCode,a.value])||this.removeEventListener("keydown",arguments.callee,!1)});Value.addListener(document,"keyup",function(g){var j=d(g.keyCode,a.value);Dispatcher.notify(a.id, -j)||this.removeEventListener("keyup",arguments.callee,!1)});Value.addListener(window,"blur",function(d){Dispatcher.notify(a.id,["Nil"])||this.removeEventListener("blur",arguments.callee,!1)});Value.addListener(document,"keypress",function(a){var d=Dispatcher.notify(g.id,["Just",a.charCode||a.keyCode]);Dispatcher.notify(g.id,["Nothing"]);d||this.removeEventListener("keypress",arguments.callee,!1)});return{keysDown:a,charPressed:g}}()}; -Elm.Mouse=function(){function d(a){var b=0,c=0;a||(a=window.event);if(a.pageX||a.pageY)b=a.pageX,c=a.pageY;else if(a.clientX||a.clientY)b=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,c=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return Value.Tuple(b,c)}var a=Elm.Signal.constant(Value.Tuple(0,0));a.defaultNumberOfKids=2;var g=Elm.Signal.lift(function(a){return a[1]})(a);g.defaultNumberOfKids=0;var i=Elm.Signal.lift(function(a){return a[2]})(a);i.defaultNumberOfKids= -0;var j=Elm.Signal.constant(!1),b=Elm.Signal.constant(!1),l=Elm.Signal.constant(Value.Tuple());Value.addListener(document,"click",function(a){var d=Dispatcher.notify(b.id,!0),c=Dispatcher.notify(l.id,Value.Tuple());Dispatcher.notify(b.id,!1);!d&&!c&&this.removeEventListener("click",arguments.callee,!1)});Value.addListener(document,"mousedown",function(a){Dispatcher.notify(j.id,!0)||this.removeEventListener("mousedown",arguments.callee,!1)});Value.addListener(document,"mouseup",function(a){Dispatcher.notify(j.id, -!1)||this.removeEventListener("mouseup",arguments.callee,!1)});Value.addListener(document,"mousemove",function(b){Dispatcher.notify(a.id,d(b))||this.removeEventListener("mousemove",arguments.callee,!1)});return{position:a,x:g,y:i,isClicked:b,isDown:j,clicks:l,isClickedOn:function(a){var a=Render.render(a),b=Elm.Signal.constant(!1);Value.addListener(a,"click",function(){Dispatcher.notify(b.id,!0);Dispatcher.notify(b.id,!1)});return Value.Tuple(Value.wrap(a),b)}}}(); -Elm.Random=function(){return{inRange:function(d){return function(a){return Elm.Signal.constant(Math.floor(Math.random()*(a-d+1))+d)}},randomize:function(d){return function(a){return function(g){return Elm.Signal.lift(function(){return Math.floor(Math.random()*(a-d+1))+d})(g)}}}}}(); -Elm.Time=function(){return{every:function(d){var d=1E3*d,a=Elm.Signal.constant(0),g=0;setInterval(function(){g+=d;Dispatcher.notify(a.id,g/1E3)},d);return a},after:function(d){var d=1E3*d,a=Elm.Signal.constant(!1);setTimeout(function(){Dispatcher.notify(a.id,!0)},d);return a},before:function(d){var d=1E3*d,a=Elm.Signal.constant(!0);setTimeout(function(){Dispatcher.notify(a.id,!1)},d);return a}}}(); -Elm.Window=function(){var d=Elm.Signal.constant(Value.Tuple(window.innerWidth,window.innerHeight));d.defaultNumberOfKids=2;var a=Elm.Signal.lift(function(a){return a[1]})(d);a.defaultNumberOfKids=0;var g=Elm.Signal.lift(function(a){return a[2]})(d);g.defaultNumberOfKids=0;Value.addListener(window,"resize",function(a){var g=document.getElementById("widthChecker").offsetWidth;Dispatcher.notify(d.id,Value.Tuple(g,window.innerHeight))||this.removeEventListener("resize",arguments.callee,!1)});return{dimensions:d, -width:a,height:g}}();Value.addListener(document,"elm_log",function(d){console.log(d.value)});Value.addListener(document,"elm_title",function(d){document.title=d.value});Value.addListener(document,"elm_redirect",function(d){0<d.value.length&&(window.location=d.value)});Elm=Elm||{}; -Elm.Prelude=function(){var d=function(a){return function(g){var i=a%g,i=0==a?0:0<g?0<=a?i:i+g:-d(-a)(-g);return i==g?0:i}};return{eq:Value.eq,id:function(a){return a},not:function(a){return!a},fst:function(a){return a[1]},snd:function(a){return a[2]},rem:function(a){return function(d){return a%d}},div:function(a){return function(d){return~~(a/d)}},compare:function(a){return function(d){a="object"===typeof a?toText(a):a;d="object"===typeof d?toText(d):d;return[a===d?"EQ":a<d?"LT":"GT"]}},toFloat:function(a){return a}, -round:function(a){return Math.round(a)},floor:function(a){return Math.floor(a)},ceiling:function(a){return Math.ceil(a)},truncate:function(a){return~~a},readInt:function(a){var a=JavaScript.castStringToJSString(a),d=a.length;if(0===d)return Nothing;var i=0;if("-"==a[0]){if(1===d)return Nothing;i=1}for(;i<d;++i)if(!Char.isDigit(a[i]))return Nothing;return Just(parseInt(a))},readFloat:function(a){var a=JavaScript.castStringToJSString(a),d=a.length;if(0===d)return Nothing;var i=0;if("-"==a[0]){if(1=== -d)return Nothing;i=1}for(var j=0;i<d;++i)if(!Char.isDigit(a[i])){if("."===a[i]&&(j+=1,1>=j))continue;return Nothing}return Just(parseFloat(a))},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,e:Math.E,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,atan2:function(a){return function(d){return Math.atan2(a,d)}},mod:d,min:function(a){return function(d){return Math.min(a,d)}},max:function(a){return function(d){return Math.max(a,d)}},flip:function(a){return function(d){return function(i){return a(i)(d)}}}, -clamp:function(a){return function(d){return function(i){return Math.min(d,Math.max(a,i))}}},curry:function(a){return function(d){return function(i){return a(["Tuple2",d,i])}}},uncurry:function(a){return function(d){if("Tuple2"!==d[0])throw"Function was uncurry'd but was not given a pair.";return a(d[1])(d[2])}},logBase:function(a){return function(d){return Math.log(d)/Math.log(a)}},Just:Elm.Maybe.Just,Nothing:Elm.Maybe.Nothing,maybe:Elm.Maybe.maybe,map:Elm.List.map,filter:Elm.List.filter,head:Elm.List.head, -tail:Elm.List.tail,last:Elm.List.last,length:Elm.List.length,reverse:Elm.List.reverse,foldr:Elm.List.foldr,foldr1:Elm.List.foldr1,foldl:Elm.List.foldl,foldl1:Elm.List.foldl1,and:Elm.List.and,or:Elm.List.or,all:Elm.List.all,any:Elm.List.any,sum:Elm.List.sum,product:Elm.List.product,concat:Elm.List.concat,concatMap:Elm.List.concatMap,maximum:Elm.List.maximum,minimum:Elm.List.minimum,scanl:Elm.List.scanl,scanl1:Elm.List.scanl1,take:Elm.List.take,drop:Elm.List.drop,zip:Elm.List.zip,unzip:Elm.List.unzip, -lift:Elm.Signal.lift,lift2:Elm.Signal.lift2,lift3:Elm.Signal.lift3,lift4:Elm.Signal.lift4,foldp:Elm.Signal.foldp,foldp1:Elm.Signal.foldp1,foldp_:Elm.Signal.foldp_,constant:Elm.Signal.constant,count:Elm.Signal.count,keepIf:Elm.Signal.keepIf,dropIf:Elm.Signal.dropIf,keepWhen:Elm.Signal.keepWhen,dropWhen:Elm.Signal.dropWhen,dropRepeats:Elm.Signal.dropRepeats,sampleOn:Elm.Signal.sampleOn}}(); -(function(){var d=function(a){for(var d in a)Elm.Prelude[d]=a[d]};d(Elm.Color);d(Elm.Text);d(Elm.Graphics);show=Value.show})(); -(function(){for(var d in Elm)this[d]=Elm[d];Elm.Automaton=function(){function a(a){return["Automaton",a]}function d(a){return["DragFrom",a]}function i(b){return function(c){var d;a:{switch(b[0]){case "Automaton":d=b[1];break a}throw"Non-exhaustive pattern match in case";}var e;a:{switch(c[0]){case "Automaton":e=c[1];break a}throw"Non-exhaustive pattern match in case";}return a(function(a){var a=d(a),b;a:{switch(a[0]){case "Tuple2":b=a[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(a[0]){case "Tuple2":a= -a[2];break a}throw"Non-exhaustive pattern match in case";}var c=e(b);a:{switch(c[0]){case "Tuple2":b=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c=c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",b,i(a)(c)]})}}function j(b){return a(function(a){var c=unzip(map(function(b){a:{switch(b[0]){case "Automaton":b=b[1](a);break a}throw"Non-exhaustive pattern match in case";}return b})(b)),d;a:{switch(c[0]){case "Tuple2":d=c[1];break a}throw"Non-exhaustive pattern match in case"; -}a:{switch(c[0]){case "Tuple2":c=c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",d,j(c)]})}function b(c){return a(function(a){return["Tuple2",c(a),b(c)]})}function l(b){return function(c){return a(function(a){a=c(a)(b);return["Tuple2",a,l(a)(c)]})}}function h(b){return function(c){return a(function(a){var d=c(a)(b);a:{switch(d[0]){case "Tuple2":a=d[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(d[0]){case "Tuple2":d=d[2];break a}throw"Non-exhaustive pattern match in case"; -}return["Tuple2",a,h(d)(c)]})}}function e(a){return function(b){a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":b=["Tuple2",a[1]-b[1],a[2]-b[2]];break b}break}break a}throw"Non-exhaustive pattern match in case";}return b}}function c(a){return function(b){var c;a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":var f=function(a){return["Tuple2",b[2],["Tuple2",a,b[2]]]};c=function(){switch(b[1][0]){case "DragFrom":var c;a[1]?c=["Tuple2",uncurry(move)(e(a[2])(b[1][1]))(b[2]),["Tuple2", -d(b[1][1]),b[2]]]:(c=uncurry(move)(e(a[2])(b[1][1]))(b[2]),c=["Tuple2",c,["Tuple2",m,c]]);return c;case "Ignore":return f(a[1]?s:m);case "Listen":return f(not(a[1])?m:isWithin(a[2])(b[2])?d(a[2]):s)}throw"Non-exhaustive pattern match in case";}();break b}break}break a}throw"Non-exhaustive pattern match in case";}return c}}var f=[],n;for(n in Elm.Prelude)0<=f.indexOf(n)||(this[n]=Elm.Prelude[n]);var m=["Listen"],s=["Ignore"],f=l(0)(function(){return function(a){return 1+a}});return{Automaton:a,run:function(a){return function(b){a:{switch(a[0]){case "Automaton":b= -lift(fst)(foldp_(function(a){return function(b){a:{switch(b[0]){case "Tuple2":switch(b[2][0]){case "Automaton":b=b[2][1](a);break a}}throw"Non-exhaustive pattern match in case";}return b}})(a[1])(b));break a}throw"Non-exhaustive pattern match in case";}return b}},step:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return b}},composeAuto:i,combine:j,pure:b,init:l,init_:h,count:f,Listen:m,Ignore:s,DragFrom:d,vecSub:e,stepDrag:c, -draggable:function(a){return h(["Tuple2",m,a])(c)}}}()})(); \ No newline at end of file diff --git a/elm/elm-runtime-0.6.0.3.js b/elm/elm-runtime-0.6.0.3.js deleted file mode 100644 index c5af3ca..0000000 --- a/elm/elm-runtime-0.6.0.3.js +++ /dev/null @@ -1,134 +0,0 @@ -Elm={};var Guid=function(){var e=0;return{guid:function(){return e+=1}}}(); -Elm.JavaScript=function(){function e(a){for(var b=["Nil"],l=a.length;l--;)b=["Cons",a[l],b];return b}function j(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b}function a(a){return a.slice(1)}function d(a){return["Tuple"+a.length].concat(a)}return{castJSBoolToBool:function(a){return a},castBoolToJSBool:function(a){return a},castJSNumberToFloat:function(a){return a},castFloatToJSNumber:function(a){return a},castJSNumberToInt:function(a){return~~a},castIntToJSNumber:function(a){return a}, -Experimental:{castJSElementToElement:function(a){return function(b){return function(l){return["Element",Guid.guid(),["EExternalHtml",l],a,b,1,Nothing,Nothing]}}},castElementToJSElement:function(a){return Render.render(a)}},castJSArrayToList:e,castListToJSArray:j,castJSStringToString:e,castStringToJSString:function(a){return"string"===typeof a?a:j(a).join("")},castTupleToJSTuple2:a,castTupleToJSTuple3:a,castTupleToJSTuple4:a,castTupleToJSTuple5:a,castJSTupleToTuple2:d,castJSTupleToTuple3:d,castJSTupleToTuple4:d, -castJSTupleToTuple5:d}}();var JSjson=window.JSON; -Elm.JSON=function(){function e(b,a){return function(h){return function(k){var f=d.castStringToJSString(h);return k[1].hasOwnProperty(f)&&(k=k[1][f],k[0]===b)?k[1]:a}}}function j(b){return function(a){function h(b){switch(b[0]){case "JsonNull":return null;case "JsonString":return d.castStringToJSString(b[1]);case "JsonObject":var f={},b=b[1][1],c;for(c in b)f[c]=h(b[c]);return f;case "JsonArray":f=d.castListToJSArray(b[1]);for(c=f.length;c--;)f[c]=h(f[c]);return f;default:return b[1]}}return JSjson.stringify(h(["JsonObject", -a]),null,d.castStringToJSString(b))}}function a(b){function a(b){switch(typeof b){case "string":return["JsonString",d.castJSStringToString(b)];case "number":return["JsonNumber",d.castJSNumberToFloat(b)];case "boolean":return["JsonBool",d.castJSBoolToBool(b)];case "object":if(null===b)return["JsonNull"];for(var f in b)b[f]=a(b[f]);return b instanceof Array?["JsonArray",d.castJSArrayToList(b)]:["JsonObject",["JSON",b]]}}var b=JSjson.parse(b),h;for(h in b)b[h]=a(b[h]);return["JSON",b]}var d=Elm.JavaScript, -i=["JSON",{}];return{empty:i,singleton:function(b){return function(a){var h={};h[d.castStringToJSString(b)]=a;return["JSON",h]}},insert:function(b){return function(a){return function(h){var h=h[1],k={},f;for(f in h)k[f]=h[f];k[d.castStringToJSString(b)]=a;return["JSON",k]}}},lookup:function(b){return function(a){var h=d.castStringToJSString(b);return a[1].hasOwnProperty(h)?["Just",a[1][h]]:["Nothing"]}},findString:e("JsonString",["Nil"]),findObject:e("JsonObject",i),findArray:e("JsonArray",["Nil"]), -findWithDefault:function(b){return function(a){return function(h){var k=d.castStringToJSString(a);return h[1].hasOwnProperty(k)?h[1][k]:b}}},remove:function(b){return function(a){var a=a[1],h={},k;for(k in a)h[k]=a[k];delete h[d.castStringToJSString(b)];return["JSON",h]}},toPrettyJSString:j,toJSString:j(""),fromJSString:a,toPrettyString:function(b){return function(a){return d.castJSStringToString(j(b)(a))}},toString:function(b){return d.castJSStringToString(j("")(b))},fromString:function(b){return a(d.castStringToJSString(b))}, -toList:function(b){var b=b[1],a=[],h;for(h in b)a.push(Value.Tuple(d.castJSStringToString(h),b[h]));return d.castJSArrayToList(a)},fromList:function(b){for(var b=d.castListToJSArray(b),a={},h=b.length;h--;)a[d.castStringToJSString(b[h][1])]=b[h][2];return["JSON",a]},JsonString:function(b){return["JsonString",b]},JsonNumber:function(b){return["JsonNumber",b]},JsonBool:function(b){return["JsonBool",b]},JsonNull:["JsonNull"],JsonArray:function(b){return["JsonArray",b]},JsonObject:function(b){return["JsonObject", -b]}}}(); -var Value=function(){function e(b){if(0==b.length)return b;for(var b=b.replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br/>"),b=b.split("<br/>"),a=b.length;a--;){var h=b,d=a,f;f=b[a];if(0!=f.length){f=f.split("");" "==f[0]&&(f[0]=" ");for(var c=f.length;--c;)" "==f[c][0]&&" "==f[c-1]&&(f[c-1]+=f[c],f[c]="");for(c=f.length;c--;)if(1<f[c].length&&" "==f[c][0]){for(var g=f[c].split(""),r=g.length-2;0<=r;r-=2)g[r]=" ";f[c]=g.join("")}f=f.join(""); -f=" "===f[f.length-1]?f.slice(0,-1)+" ":f}h[d]=f}return b.join("<br/>")}var j=function(b,a){if("object"===typeof b){if(b===a)return!0;if(b.length!==a.length)return!1;for(var h=b.length;h--;)if(!j(b[h],a[h]))return!1;return!0}return b===a},a=function(b){if("boolean"===typeof b)return b?"True":"False";if("number"!==typeof b){if("string"===typeof b&&2>b.length)return"'"+b+"'";if(b[0]){if("Tuple"===b[0].substring(0,5)){for(var d="",h=b.length;--h;)d=","+a(b[h])+d;","===d[0]&&(d=d.substring(1));return"("+ -d+")"}if("Cons"===b[0])for(var h="string"===typeof b[1]?'"':"]",k="string"===typeof b[1]?"":",",f="string"===typeof b[1]?function(b){return b}:a,d=("string"===typeof b[1]?'"':"[")+f(b[1]),b=b[2];;)if("Cons"===b[0])d+=k+f(b[1]),b=b[2];else return d+h;else{if("Nil"===b[0])return"[]";if("JSON"===b[0])return"(JSON.fromList "+a(Elm.JSON.toList(b))+")";if("RBNode"===b[0]||"RBEmpty"===b[0])return b=Elm.Dict.foldr(function(b){return function(a){return function(f){return["Cons",["Tuple2",b,a],f]}}})(["Nil"])(b), -d="Dict","Cons"===b[0]&&"Tuple0"===b[1][2][0]&&(d="Set",b=Elm.List.map(function(b){return b[1]})(b)),"("+d+".fromList "+a(b)+")";d="";for(h=b.length;--h;)d=" "+a(b[h])+d;d=b[0]+d;return 1<b.length?"("+d+")":d}}}return b+""},d=function(b){for(var a=["Nil"],d=b.length;d--;)a=["Cons",b[d],a];return a},i;i=document.addEventListener?function(b,a,d){b.addEventListener(a,d,!1)}:function(b,a,d){b.attachEvent("on"+a,d)};return{eq:j,str:d,show:function(b){return d(a(b))},Tuple:function(){var b=arguments.length, -a=Array(b+1);for(a[0]="Tuple"+arguments.length;b--;)a[b+1]=arguments[b];return a},append:function(b,a){if("string"===typeof b&&"string"===typeof a)return b.concat(a);if("Nil"===b[0])return a;for(var d=["Cons",b[1],["Nil"]],k=d,b=b[2];"Cons"===b[0];)k[2]=["Cons",b[1],["Nil"]],b=b[2],k=k[2];k[2]=a;return d},listToArray:function(b){for(var a=[];"Cons"===b[0];)a.push(b[1]),b=b[2];return a},toText:function(a){if("string"===typeof a)return e(a);for(var d=[];"Cons"===a[0];)d.push(a[1]),a=a[2];return e(d.join(""))}, -properEscape:e,getTextSize:function(a,d,h){var k=document.createElement("div");k.innerHTML=h;k.style.textAlign="left";0<a&&(k.style.width=a+"px");k.style.visibility="hidden";k.style.styleFloat="left";k.style.cssFloat="left";document.body.appendChild(k);h=window.getComputedStyle(k,null);a=h.getPropertyValue("width").slice(0,-2)-0;h=h.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(k);return[Math.ceil(a),Math.ceil(Math.max(d,h))]},getSize:function(a){a=a.cloneNode(!0);a.style.visibility= -"hidden";a.style.styleFloat="left";a.style.cssFloat="left";document.body.appendChild(a);var d=a.offsetWidth,h=a.offsetHeight;document.body.removeChild(a);return[d,h]},getExcess:function(a){a=a.cloneNode(!0);a.style.visibility="hidden";a.style.styleFloat="left";a.style.cssFloat="left";document.body.appendChild(a);var d=a.offsetWidth,h=a.offsetHeight,k=window.getComputedStyle(a,null),f=k.getPropertyValue("width").slice(0,-2)-0,k=k.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(a); -return[d-f,h-k]},groupForms:function(a){for(var a=Elm.JavaScript.castListToJSArray(a),d=[],h=[],k=a.length;k--;){var f=a[k];switch(f[4][0]){case "FElement":0<h.length&&(d.push(h),h=[]);d.push(f);break;default:h.push(f)}}0<h.length&&d.push(h);return d},wrap:function(a){var d=Value.getSize(a);return["Element",Guid.guid(),["EHtml",a],d[0],d[1],1,["Nothing"],["Nothing"]]},addListener:i}}(); -Elm.List=function(){function e(a){return function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&f("map");for(var c=["Cons",a(b[1]),["Nil"]],g=c,b=b[2];"Cons"===b[0];)g[2]=["Cons",a(b[1]),["Nil"]],b=b[2],g=g[2];return c}}function j(a){return function(b){return function(c){var g=b;if("Nil"===c[0])return g;for("Cons"!==c[0]&&f("foldl");"Cons"===c[0];)g=a(c[1])(g),c=c[2];return g}}}function a(a){return function(b){return function(c){var g=b;if("Nil"===c[0])return g;"Cons"!==c[0]&&f("foldr");for(var d=[];"Cons"=== -c[0];)d.push(c[1]),c=c[2];for(c=d.length;c--;)g=a(d[c])(g);return g}}}function d(a){return function(f){var b;"Cons"!==f[0]?b=void 0:(b=f[1],f=f[2],b=j(a)(b)(f));return b}}function i(a){return function(b){return function(c){if("Nil"===c[0])return["Cons",b,["Nil"]];"Cons"!==c[0]&&f("scanl");for(var g=[b];"Cons"===c[0];)b=a(c[1])(b),g.push(b),c=c[2];for(var c=["Nil"],d=g.length;d--;)c=["Cons",g[d],c];return c}}}function b(a){return function(f){a:{for(var c=[function(a){return"Nil"!==a[0]?void 0:["Tuple2", -["Nil"],["Nil"]]},function(f){if("Cons"===f[0]){var c=f[1],f=f[2];var g=b(a)(f);"Tuple2"!==g[0]?c=void 0:(f=g[1],g=g[2],c=a(c)?["Tuple2",["Cons",c,f],g]:["Tuple2",f,["Cons",c,g]]);return c}}],g=c.length;g--;){var d=c[g](f);if(void 0!==d){f=d;break a}}f=void 0}return f}}function l(a){a:{for(var f=[function(a){return"Nil"!==a[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(a){if("Cons"!==a[0])a=void 0;else if(a=["Tuple2",a[1],l(a[2])],"Tuple2"!==a[0]||"Tuple2"!==a[1][0])a=void 0;else var f=a[1][1],b= -a[1][2],a="Tuple2"!==a[2][0]?void 0:["Tuple2",["Cons",f,a[2][1]],["Cons",b,a[2][2]]];return a}],b=f.length;b--;){var c=f[b](a);if(void 0!==c){a=c;break a}}a=void 0}return a}function h(a){return function(f){a:{for(var b=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var f=a[1];return"Nil"!==a[2][0]?void 0:["Cons",f,["Nil"]]}},function(f){if("Cons"===f[0]){var b=f[1];if("Cons"===f[2][0]){var c=f[2][1],f=f[2][2];return["Cons",b,["Cons",a,h(a)(["Cons",c,f])]]}}}],c=b.length;c--;){var g= -b[c](f);if(void 0!==g){f=g;break a}}f=void 0}return f}}function k(a){return function(f){a:{for(var b=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var f=a[1];return"Nil"!==a[2][0]?void 0:f}},function(f){if("Cons"===f[0]){var b=f[1];if("Cons"===f[2][0]){var c=f[2][1],f=f[2][2];return Value.append(b,Value.append(a,k(a)(["Cons",c,f])))}}}],c=b.length;c--;){var g=b[c](f);if(void 0!==g){f=g;break a}}f=void 0}return f}}var f=function(a){throw"Function '"+a+"' expecting a list!"; -},c=j(function(a){return function(f){return["Cons",a,f]}})(["Nil"]),g=a(function(a){return function(f){return Value.append(a,f)}})(["Nil"]),r=j(function(a){return function(f){return a&&f}})(!0),m=j(function(a){return function(f){return a||f}})(!1),n=j(function(a){return function(f){return a+f}})(0),u=j(function(a){return function(f){return a*f}})(1),x=d(function(a){return function(f){return Math.max(a,f)}}),q=d(function(a){return function(f){return Math.min(a,f)}});return{head:function(a){if("Cons"!== -a[0])throw"Error: 'head' only accepts lists of length greater than one.";return a[1]},tail:function(a){if("Cons"!==a[0])throw"Error: 'tail' only accepts lists of length greater than one.";return a[2]},last:function(a){if("Cons"!==a[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var f=a[1];"Cons"===a[0];)f=a[1],a=a[2];return f},map:e,foldl:j,foldr:a,foldl1:d,foldr1:function(a){return function(b){if("Nil"===b[0])throw"'foldr1' requires an non-empty list.";"Cons"!==b[0]&& -f("foldr1");for(var c=[];"Cons"===b[0];)c.push(b[1]),b=b[2];for(var b=c.pop(),g=c.length;g--;)b=a(c[g])(b);return b}},scanl:i,scanl1:function(a){return function(f){if("Cons"!==f[0])throw"Error: 'scanl1' requires a list of at least length 1.";return i(a)(f[1])(f[2])}},filter:function(a){return function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&f("filter");for(var c=[];"Cons"===b[0];)a(b[1])&&c.push(b[1]),b=b[2];for(var b=["Nil"],g=c.length;g--;)b=["Cons",c[g],b];return b}},length:function(a){for(var f= -0;"Cons"===a[0];)f+=1,a=a[2];return f},reverse:c,concat:g,concatMap:function(a){return function(f){return g(e(a)(f))}},and:r,or:m,all:function(a){return j(function(f){return function(b){return b&&a(f)}})(!0)},any:function(a){return j(function(f){return function(b){return b||a(f)}})(!1)},sum:n,product:u,maximum:x,minimum:q,partition:b,zipWith:function(a){return function(b){return function(c){if("Nil"===b[0]||"Nil"===c[0])return["Nil"];("Cons"!==b[0]||"Cons"!==c[0])&&f("zipWith");for(var g=[];"Cons"=== -b[0]&&"Cons"===c[0];)g.push(a(b[1])(c[1])),b=b[2],c=c[2];for(var c=["Nil"],d=g.length;d--;)c=["Cons",g[d],c];return c}}},zip:function(a){return function(b){if("Nil"===a[0]||"Nil"===b[0])return["Nil"];("Cons"!==a[0]||"Cons"!==b[0])&&f("zip");for(var c=[];"Cons"===a[0]&&"Cons"===b[0];)c.push(["Tuple2",a[1],b[1]]),a=a[2],b=b[2];for(var b=["Nil"],g=c.length;g--;)b=["Cons",c[g],b];return b}},unzip:l,intersperse:h,intercalate:k,sort:function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&f("sort");for(var b= -[];"Cons"===a[0];)b.push(a[1]),a=a[2];b.sort(function(a,f){return a-f});for(var a=["Nil"],c=b.length;c--;)a=["Cons",b[c],a];return a},take:function(a){return function(b){if(0>=a)return["Nil"];if("Nil"===b[0])return b;"Cons"!==b[0]&&f("take");var c=["Cons",b[1],["Nil"]],g=c,b=b[2];for(--a;"Cons"===b[0]&&0<a;)g[2]=["Cons",b[1],["Nil"]],g=g[2],b=b[2],--a;return c}},drop:function(a){return function(b){if("Nil"===b[0])return b;for("Cons"!==b[0]&&f("drop");"Cons"===b[0]&&0<a;)b=b[2],--a;return b}}}}(); -Elm.Maybe=function(){function e(a){return function(d){return"Just"===a[0]?["Cons",a[1],d]:d}}function j(a){return function(d){return function(i){var b=a(d);return"Just"===b[0]?["Cons",b[1],i]:i}}}return{Just:function(a){return["Just",a]},Nothing:["Nothing"],catMaybes:Elm.List.foldr(e)(["Nil"]),isJust:function(a){return"Just"===a[0]},isNothing:function(a){return"Nothing"===a[0]},fromMaybe:function(a){return function(d){return"Just"===d[0]?d[1]:a}},consMaybe:e,mapMaybe:function(a){return Elm.List.foldr(j(a))(["Nil"])}, -maybe:function(a){return function(d){return function(i){return"Just"===i[0]?d(i[1]):a}}}}}(); -Elm.Char=function(){function e(a,b){return function(d){d=d.charCodeAt(0);return a<=d&&d<=b}}var j=e(48,57),a=e(97,102),d=e(65,70);return{fromCode:function(a){return String.fromCharCode(a)},toCode:function(a){return a.charCodeAt(0)},toUpper:function(a){return a.toUpperCase()},toLower:function(a){return a.toLowerCase()},toLocaleUpper:function(a){return a.toLocaleUpperCase()},toLocaleLower:function(a){return a.toLocaleLowerCase()},isLower:e(97,122),isUpper:e(65,90),isDigit:j,isOctDigit:e(48,55),isHexDigit:function(e){return j(e)|| -a(e)||d(e)}}}(); -Elm.Color=function(){function e(e){var a=e.value*e.saturation,d=e.hue/60,i=a*(1-Math.abs(d%2-1)),b=0,l=0,h=0;0<=d&&1>d?(b=a,l=i,h=0):1<=d&&2>d?(b=i,l=a,h=0):2<=d&&3>d?(b=0,l=a,h=i):3<=d&&4>d?(b=0,l=i,h=a):4<=d&&5>d?(b=i,l=0,h=a):5<=d&&6>d&&(b=a,l=0,h=i);e=e.value-a;return["Color",Math.round(255*(b+e)),Math.round(255*(l+e)),Math.round(255*(h+e)),1]}return{rgba:function(e){return function(a){return function(d){return function(i){return["Color",e,a,d,i]}}}},rgb:function(e){return function(a){return function(d){return["Color",e, -a,d,1]}}},hsva:function(j){return function(a){return function(d){return function(i){var b=e({hue:j,saturation:a,value:d});b[4]=i;return b}}}},hsv:function(j){return function(a){return function(d){return e({hue:j,saturation:a,value:d})}}},red:["Color",255,0,0,1],green:["Color",0,255,0,1],blue:["Color",0,0,255,1],yellow:["Color",255,255,0,1],cyan:["Color",0,255,255,1],magenta:["Color",255,0,255,1],black:["Color",0,0,0,1],white:["Color",255,255,255,1],gray:["Color",128,128,128,1],grey:["Color",128,128, -128,1],complement:function(j){var a;a=j[1]/255;var d=j[2]/255,j=j[3]/255,i=Math.max(a,d,j),b=Math.min(a,d,j),b=i-b,l=0;0===b?l=0:i===a?l=(d-j)/b%6:i===d?l=(j-a)/b+2:i===j&&(l=(a-d)/b+4);a={value:i,hue:60*l,saturation:0===i?0:b/i};a.hue=(a.hue+180)%360;return e(a)},extract:function(e){return 1===e[4]?"rgb("+e[1]+","+e[2]+","+e[3]+")":"rgba("+e[1]+","+e[2]+","+e[3]+","+e[4]+")"}}}(); -var Collage=function(){function e(a,b){var c=b.length-1;if(!(0>=c))for(a.moveTo(b[c][1],b[c][2]);c--;)a.lineTo(b[c][1],b[c][2])}function j(a,b,c,g){0===a.length&&(a=[8,4]);var d=g.length-1;if(!(0>=d)){var m=g[d][1],h=g[d][2],e=0,i=0,j=0,l=0,p=0,s=0,v=a.length,z=!0,w=a[0];for(b.moveTo(m,h);d--;){e=g[d][1];i=g[d][2];j=e-m;l=i-h;for(p=Math.sqrt(j*j+l*l);w<=p;)m+=j*w/p,h+=l*w/p,b[z?"lineTo":"moveTo"](m,h),j=e-m,l=i-h,p=Math.sqrt(j*j+l*l),z=!z,s=(s+1)%v,w=a[s];0<p&&(b[z?"lineTo":"moveTo"](e,i),w-=p);m= -e;h=i}}b.strokeStyle=Elm.Color.extract(c);b.stroke()}function a(a,b,c,g,d){b.clearRect(0,0,c,g);for(c=d.length;c--;){var m=d[c],n=a,g=b,i=m[1],l=m[2],q=m[3][1],t=m[3][2],m=m[4];g.save();(0!==q||0!==t)&&g.translate(q,t);i!==~~i&&g.rotate(2*Math.PI*i);1!==l&&g.scale(l,l);g.beginPath();switch(m[0]){case "FLine":a:switch(n=g,i=m,m=i[3][1],i[1][0]){case "Solid":i=i[2];e(n,m);n.strokeStyle=Elm.Color.extract(i);n.stroke();break;case "Dotted":j([3,3],n,i[2],m);break a;case "Dashed":j([8,4],n,i[2],m);break a; -case "Custom":j(i[1][1],n,i[2],m)}break;case "FShape":a:switch(q=n,l=g,n=m[1],i=m[2],m=m[3][1],n[0]){case "Filled":n=l;e(n,m);n.fillStyle=Elm.Color.extract(i);n.fill();break a;case "Outlined":n=l;e(n,m);n.strokeStyle=Elm.Color.extract(i);n.stroke();break a;case "Textured":i=q;n=n[1];q=new Image;q.src=h.castStringToJSString(n);q.onload=i;e(l,m);l.fillStyle=l.createPattern(q,"repeat");l.fill();break a;case "CustomOutline":j(n[1],l,i,m)}break;case "FImage":i=g,l=m[1],q=m[2],m=m[3],t=new Image,t.onload= -n,t.src=h.castStringToJSString(m),i.drawImage(t,-l/2,-q/2,l,q)}g.restore()}}function d(b,f,c){var g=Render.newElement("canvas"),b=~~b,f=~~f;g.style.width=b+"px";g.style.height=f+"px";g.style.display="block";g.width=b;g.height=f;if(g.getContext){var d=g.getContext("2d");a(function(){a(this,d,b,f,c)},d,b,f,c);return g}g.innerHTML="Your browser does not support the canvas element.";return g}function i(a,b,c,g,d,h,e){var i=Render.render(e),c="translate("+(d-e[3]/2)+"px,"+(h-e[4]/2)+"px) "+(1===g?"":"scale("+ -g+","+g+")")+" "+(c===~~c?"":"rotate("+360*c+"deg)");i.style.transform=c;i.style.msTransform=c;i.style.MozTransform=c;i.style.webkitTransform=c;i.style.OTransform=c;c=Render.newElement("div");Render.addTo(c,i);c.style.width=~~a+"px";c.style.height=~~b+"px";c.style.overflow="hidden";return c}function b(b,f,c){if(!Value.eq(c,f)){var g=b.style.width.slice(0,-2)-0,h=b.style.height.slice(0,-2)-0;if("object"===typeof c[0]){if("object"===typeof f[0]&&b.getContext){var m=b.getContext("2d");return a(function(){a(this, -m,g,h,c)},m,g,h,c)}f=d(g,h,c);f.style.position="absolute";return b.parentNode.replaceChild(f,b)}f=i(g,h,c[1],c[2],c[3][1],c[3][2],c[4][1]);f.style.position="absolute";return b.parentNode.replaceChild(f,b)}}function l(a,b,c,g,d){var h=0,e,i=(a[1]-g[1])/c,a=(a[2]-g[2])/c;0!==b&&(b*=-2*Math.PI,c=i*Math.cos(b)-a*Math.sin(b),a=i*Math.sin(b)+a*Math.cos(b),i=c);if(0===d.length)return!1;e=d[0];for(c=d.length-1;c--;){b=d[c];g=e[1];e=e[2];var j=b[1],l=b[2];if(e<l)var t=e,p=l;else t=l,p=e;if(g<j)var s=g,v=j; -else s=j,v=g;t<a&&a<=p&&i<=v&&(i<=s||i<=(a-e)*(j-g)/(l-e)+g)&&++h;e=b}return 1===h%2}var h=Elm.JavaScript;return{collage:function(a,b,c){if(0===c.length)return d(a,b,[]);for(var g=Array(c.length),h=c.length;h--;){var e=c[h];g[h]="string"===typeof e[0]?i(a,b,e[1],e[2],e[3][1],e[3][2],e[4][1]):d(a,b,e)}return 1===c.length?g[0]:Render.flowWith(Render.goIn,function(a){return a},g)},updateCollage:function(a,f,c){if(1===c.length)return b(a,f[0],c[0]);for(var a=a.childNodes,g=a.length,d=g;d--;)b(a[g-d-1], -f[d],c[d])},insideForm:function(a){return function(b){var c=a[1],g=a[2];if(6>b.length){var d=b[3][1],e=b[3][2],h=0,i=b[2];switch(b[4][0]){case "FShape":for(var j=b[4][3][1],q=j.length;--q;)var t=j[q],h=Math.max(h,t[1]*t[1]+t[2]*t[2]);h*=i*i;break;case "FImage":j=i*b[4][1]/2;i=i*b[4][2]/2;h=j*j+i*i;break;case "FElement":j=i*b[4][1][3]/2,i=i*b[4][1][4]/2,h=j*j+i*i}b.push(function(a,b){var c=a-d,f=b-e;return c*c+f*f<h+1})}if(!b[5](c,g))return!1;var p,s;switch(b[4][0]){case "FShape":return l(a,b[1],b[2], -b[3],b[4][3][1]);case "FLine":return!1;case "FImage":p=b[4][1]/2;s=b[4][2]/2;break;case "FElement":p=b[4][1][3]/2,s=b[4][1][4]/2}return l(a,b[1],b[2],b[3],[[null,p,s],[null,-p,s],[null,-p,-s],[null,p,-s],[null,p,s]])}}}}(); -Elm.Graphics=function(){function e(a){return function(b){return["Position",a,b]}}function j(a){return function(b){return["EText",a,b]}}function a(a){return function(b){return["EFlow",a,u.castListToJSArray(b)]}}function d(a){return["Line",u.castListToJSArray(a)]}function i(a){return function(b){var c=u.castListToJSArray(a);0<c.length&&c.push(c[0]);return["Shape",c,b]}}function b(a){return function(b){return function(c){return function(f){return["Form",a,b,c,f]}}}}function l(a){return function(b){return function(c){return["FLine", -a,b,c]}}}function h(a){return function(b){return function(c){return["FShape",a,b,c]}}}function k(a,b,c,f,g,d){return["Element",Guid.guid(),a,b,c,f,g,d]}function f(a,b,c){return["Element",Guid.guid(),a,b,c,1,["Nothing"],["Nothing"]]}function c(a){return~~a[3]}function g(a){return~~a[4]}function r(a){return function(b){return function(c){return f(["EImage",u.castStringToJSString(c)],a,b)}}}function m(a){return function(b){return f(z,a,b)}}function n(a){return function(b){return function(c){var f=map(function(c){return["Tuple2", -a/2*Math.cos(2*(Math.PI/50)*c),b/2*Math.sin(2*(Math.PI/50)*c)]}),g=49,d=["Nil"];if(0<=g){do d=["Cons",g,d];while(0<g--)}return i(f(d))(c)}}}for(this.i in Elm.List)eval("var "+this.i+" = Elm.List[this.i];");var u=Elm.JavaScript,x=["DRight"],q=["DDown"],t=["DOut"],p=["Near"],s=["Mid"],v=["Far"],z=["EEmpty"],w=["Solid"],C=["Dotted"],E=["Dashed"],A=["Filled"],D=["Outlined"],y=e(p)(p),B=e(v)(p),F=e(p)(v),G=e(v)(v),H=e(p)(s),I=e(v)(s),p=e(s)(p),v=e(s)(v),s=e(s)(s);return{left:["DLeft"],right:x,down:q,up:["DUp"], -inward:["DIn"],outward:t,topLeft:y,topRight:B,bottomLeft:F,bottomRight:G,midLeft:H,midRight:I,midTop:p,midBottom:v,middle:s,middleAt:function(a){return function(b){return["PositionAt",a,b]}},topLeftAt:function(a){return function(b){return["PositionTL",a,b]}},topRightAt:function(a){return function(b){return["PositionTR",a,b]}},bottomLeftAt:function(a){return function(b){return["PositionBL",a,b]}},bottomRightAt:function(a){return function(b){return["PositionBR",a,b]}},absolute:function(a){return["Absolute", -a]},relative:function(a){return["Relative",a]},width:function(a){return function(b){var c=b[2];switch(c[0]){case "EImage":case "EVideo":return k(b[2],a,b[4]*a/b[3],b[5],b[6],b[7]);case "EText":return c=Value.getTextSize(a,b[4],c[2]),k(b[2],a,c[1],b[5],b[6],b[7])}return k(b[2],a,b[4],b[5],b[6],b[7])}},height:function(a){return function(b){switch(b[2][0]){case "EImage":case "EVideo":return k(b[2],b[3]*a/b[4],a,b[5],b[6],b[7])}return k(b[2],b[3],a,b[5],b[6],b[7])}},size:function(a){return function(b){return function(c){return k(c[2], -a,b,c[5],c[6],c[7])}}},opacity:function(a){return function(b){return k(b[2],b[3],b[4],a,b[6],b[7])}},color:function(a){return function(b){return k(b[2],b[3],b[4],b[5],["Just",a],b[7])}},link:function(a){return function(b){return k(b[2],b[3],b[4],b[5],b[6],["Just",u.castStringToJSString(a)])}},widthOf:c,heightOf:g,sizeOf:function(a){return["Tuple2",~~a[3],~~a[4]]},text:function(a){var b=Value.getTextSize(0,0,a);return f(j("left")(a),b[0],b[1])},asText:function(a){var a=Elm.Text.monospace(Value.toText(Value.show(a))), -b=Value.getTextSize(0,0,a);return f(j("left")(a),b[0],b[1])},plainText:function(a){var a=Value.toText(a),b=Value.getTextSize(0,0,a);return f(j("left")(a),b[0],b[1])},centeredText:function(a){var b=Value.getTextSize(0,0,a);return f(j("center")(a),b[0],b[1])},justifiedText:function(a){var b=Value.getTextSize(0,0,a);return f(j("justify")(a),b[0],b[1])},rightedText:function(a){var b=Value.getTextSize(0,0,a);return f(j("right")(a),b[0],b[1])},image:r,images:function(a){var b=Elm.Signal.constant(m(0)(0)), -a=Elm.Signal.lift(function(a){var a=u.castStringToJSString(a),c=new Image;c.onload=function(){Dispatcher.notify(b.id,r(this.width)(this.height)(a))};c.src=a})(a);return Elm.Signal.lift2(function(a){return function(){return a}})(b)(a)},video:function(a){return function(b){return function(c){return f(["EVideo",u.castStringToJSString(c)],a,b)}}},fittedImage:function(a){return function(b){return function(c){return f(["EFittedImage",u.castStringToJSString(c)],a,b)}}},flow:function(b){return function(d){var h; -h=map(c)(d);a:{switch(b[0]){case "DLeft":h=sum(h);break a;case "DRight":h=sum(h);break a}h=maximum(h)}var e;e=map(g)(d);a:{switch(b[0]){case "DDown":e=sum(e);break a;case "DUp":e=sum(e);break a}e=maximum(e)}return f(a(b)(d),h,e)}},above:function(b){return function(c){return f(a(q)(["Cons",b,["Cons",c,["Nil"]]]),Math.max(~~b[3],~~c[3]),~~b[4]+~~c[4])}},below:function(b){return function(c){return f(a(q)(["Cons",c,["Cons",b,["Nil"]]]),Math.max(~~b[3],~~c[3]),~~b[4]+~~c[4])}},beside:function(b){return function(c){return f(a(x)(["Cons", -b,["Cons",c,["Nil"]]]),~~b[3]+~~c[3],Math.max(~~b[4],~~c[4]))}},layers:function(b){return f(a(t)(b),maximum(map(c)(b)),maximum(map(g)(b)))},collage:function(a){return function(b){return function(c){return f(["ECollage",a,b,Value.groupForms(c)],a,b)}}},spacer:m,container:function(a){return function(b){return function(c){return function(g){return f(["EContainer",c,g],a,b)}}}},line:d,segment:function(a){return function(b){return d(["Cons",a,["Cons",b,["Nil"]]])}},polygon:i,rect:function(a){return function(b){return function(c){return i(["Cons", -["Tuple2",0-a/2,0-b/2],["Cons",["Tuple2",0-a/2,b/2],["Cons",["Tuple2",a/2,b/2],["Cons",["Tuple2",a/2,0-b/2],["Nil"]]]]])(c)}}},oval:n,circle:function(a){return n(2*a)(2*a)},ngon:function(a){return function(b){return function(c){var f=map(function(c){return["Tuple2",b*Math.cos(2*(Math.PI/a)*c),b*Math.sin(2*(Math.PI/a)*c)]}),g=a-1,d=["Nil"];if(0<=g){do d=["Cons",g,d];while(0<g--)}return i(f(d))(c)}}},solid:function(a){return function(c){return b(0)(1)(["Tuple2",0,0])(l(w)(a)(c))}},dotted:function(a){return function(c){return b(0)(1)(["Tuple2", -0,0])(l(C)(a)(c))}},dashed:function(a){return function(c){return b(0)(1)(["Tuple2",0,0])(l(E)(a)(c))}},customLine:function(a){return function(c){return function(f){return b(0)(1)(["Tuple2",0,0])(l(["Custom",u.castListToJSArray(a)])(c)(f))}}},filled:function(a){return function(c){return b(0)(1)(c[2])(h(A)(a)(c))}},outlined:function(a){return function(c){return b(0)(1)(c[2])(h(D)(a)(c))}},customOutline:function(a){return function(c){return function(f){return b(0)(1)(f[2])(h(["CustomOutline",u.castListToJSArray(a)])(c)(f))}}}, -textured:function(a){return function(c){return b(0)(1)(c[2])(h(["Textured",a])(null)(c))}},sprite:function(a){return function(c){return function(f){return function(g){return b(0)(1)(g)(["FImage",c,f,u.castStringToJSString(a)])}}}},toForm:function(a){return function(c){return b(0)(1)(a)(["FElement",c])}},rotate:function(a){return function(c){a:{switch(c[0]){case "Form":var f=c[2],g=c[3],d=c[4],c=b(a+c[1])(f)(g)(d);break a}throw"Non-exhaustive pattern match in case";}return c}},scale:function(a){return function(c){return b(c[1])(a* -c[2])(c[3])(c[4])}},move:function(a){return function(c){return function(f){var g;a:{switch(f[0]){case "Form":g=f[1];var d=f[2],h=f[3],f=f[4];switch(h[0]){case "Tuple2":var e=h[1],h=h[2];g=b(g)(d)(["Tuple2",a+e,c+h])(f);break a}}throw"Non-exhaustive pattern match in case";}return g}}},isWithin:Collage.insideForm}}(); -Elm.Text=function(){function e(a){return Value.toText(a)}var j=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},a=function(a,b){return function(g){return"<span style='"+a+":"+b+"'>"+g+"</span>"}},d=function(b){b=Elm.JavaScript.castStringToJSString(b);return a("font-family",b)},i=j("h1"),b=a("font-style","italic"),j=j("b"),l=a("text-decoration","underline"),h=a("text-decoration","overline"),k=a("text-decoration","line-through");return{fromString:e,toText:e,header:i, -height:function(b){return a("font-size",b+"em")},italic:b,bold:j,underline:l,overline:h,strikeThrough:k,monospace:d("monospace"),typeface:d,color:function(b){return a("color",Elm.Color.extract(b))},link:function(a){return function(b){return"<a href='"+e(a)+"'>"+b+"</a>"}}}}(); -var Render=function(){function e(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a}function j(a){return a}function a(a){a.style.styleFloat="left";a.style.cssFloat="left";return a}function d(a){a.style.position="absolute";return a}function i(a,b,g){for(var d=e("div"),h=g.length;h--;){var i=a(b(g[h]));d.appendChild(i)}return d}function b(a){switch(a[0]){case "Absolute":return a[1]+"px";case "Relative":return 100*a[1]+"%"}}function l(a,c){c.style.position="absolute";c.style.margin= -"auto";switch(a[0]){case "Position":"Far"!==a[1][0]&&(c.style.left=0);"Near"!==a[1][0]&&(c.style.right=0);"Far"!==a[2][0]&&(c.style.top=0);"Near"!==a[2][0]&&(c.style.bottom=0);break;case "PositionAt":c.style.top=b(a[2]);c.style.left=b(a[1]);var g="translate("+~~(-c.style.width.slice(0,-2)/2)+"px,"+~~(-c.style.height.slice(0,-2)/2)+"px)";c.style.transform=g;c.style.msTransform=g;c.style.MozTransform=g;c.style.webkitTransform=g;c.style.OTransform=g;break;default:g=a[0].slice(-2),c.style["T"===g[0]? -"top":"bottom"]=b(a[2]),c.style["L"===g[1]?"left":"right"]=b(a[1])}}function h(b){var c={};switch(b[2][0]){case "EText":var c=b[2][1],g=b[2][2],r=e("div");r.innerHTML=g;r.style.textAlign=c;c=r;break;case "EImage":c=b[2][1];g=e("img");g.src=c;g.name=c;g.style.display="block";c=g;break;case "EVideo":r=b[2][1];c=e("video");c.controls="controls";g=e("source");g.src=r;r=r.split(".");g.type="video/"+r[r.length-1];c.appendChild(g);c.style.display="block";break;case "EFittedImage":var m=b[3],n=b[4],c=b[2][1], -g=e("div");g.style.width=m+"px";g.style.height=n+"px";g.style.position="relative";g.style.overflow="hidden";var k=e("img");k.onload=function(){k.style.position="absolute";k.style.margin="auto";var a=m,b=n;m/n>this.width/this.height?b=Math.round(this.height*m/this.width):a=Math.round(this.width*n/this.height);k.style.width=a+"px";k.style.height=b+"px";k.style.left=(m-a)/2+"px";k.style.top=(n-b)/2+"px"};k.src=c;k.name=c;g.appendChild(k);c=g;break;case "EFlow":a:{c=b[2][2];switch(b[2][1][0]){case "DDown":c= -c.slice(0).reverse();case "DUp":c=i(j,h,c);break a;case "DRight":c=c.slice(0).reverse();case "DLeft":c=i(a,h,c);break a;case "DOut":c=c.slice(0).reverse();case "DIn":c=i(d,h,c);break a}c=void 0}break;case "ECollage":c=Collage.collage(b[2][1],b[2][2],b[2][3]);break;case "EEmpty":c=e("div");break;case "EContainer":g=b[2][1];c=h(b[2][2]);l(g,c);g=e("div");g.style.position="relative";g.style.overflow="hidden";g.appendChild(c);c=g;break;case "EHtml":c=b[2][1];"button"!==c.type&&(g=Value.getExcess(c),b[3]-= -g[0],b[4]-=g[1]);break;case "EExternalHtml":c=e("div"),c.appendChild(b[2][1])}c.id=b[1];c.style.width=~~b[3]+"px";c.style.height=~~b[4]+"px";1!==b[5]&&(c.style.opacity=b[5]);"Just"===b[6][0]&&(c.style.backgroundColor=Elm.Color.extract(b[6][1]));return"Just"===b[7][0]?(g=e("a"),g.href=b[7][1],g.appendChild(c),g):c}function k(b,c,g){"A"===b.tagName&&(b=b.firstChild);if(c[1]!==g[1]){if(c[2][0]!==g[2][0])return b.parentNode.replaceChild(h(g),b);var e=g[2],i=c[2];switch(e[0]){case "EText":e[1]!==i[1]&& -(b.style.textAlign=e[1]);e[2]!==i[2]&&(b.innerHTML=e[2]);break;case "EImage":e[1]!==i[1]&&(b.src=e[1]);break;case "EVideo":case "EFittedImage":if(!Value.eq(e,i)||g[3]!==c[3]||g[4]!==c[4])return b.parentNode.replaceChild(h(g),b);break;case "ECollage":if(e[1]!==i[1]||e[2]!==i[2]||e[3].length!==i[3].length)return b.parentNode.replaceChild(h(g),b);Collage.updateCollage(b,i[3],e[3]);break;case "EFlow":if(e[1]!==i[1])return b.parentNode.replaceChild(h(g),b);var n=e[2],u=b.childNodes;if(n.length!==u.length)return b.parentNode.replaceChild(h(g), -b);var i=i[2],x=function(a){return a};switch(e[1][0]){case "DDown":case "DUp":x=j;break;case "DRight":case "DLeft":x=a;break;case "DOut":case "DIn":x=d}for(e=u.length;e--;)k(u[e],i[e],n[e]),x(u[e]);break;case "EContainer":k(b.childNodes[0],i[2],e[2]);l(e[1],b.childNodes[0]);break;case "EHtml":g[1]!==c[1]&&(n=h(g),b.parentNode.replaceChild(n,b),b=n);"button"!==n.type&&(e=Value.getExcess(b),g[3]-=e[0],g[4]-=e[1]);break;case "EExternalHtml":g[1]!==c[1]&&b.parentNode.replaceChild(h(g),b)}g[3]!==c[3]&& -(b.style.width=~~g[3]+"px");g[4]!==c[4]&&(b.style.height=~~g[4]+"px");g[5]!==c[5]&&(b.style.opacity=g[5]);2===g[6].length&&(e=Elm.Color.extract(g[6][1]),e!==b.style.backgroundColor&&(b.style.backgroundColor=e));if(2===g[7].length&&(1===c[7].length||g[7][1]!==c[7][1]))b.parentNode.href=g[7][1];g[1]=c[1]}}return{render:h,update:k,addTo:function(a,b){a.appendChild(b)},newElement:e,flowWith:i,goIn:d}}(); -Elm.Signal=function(){function e(a){this.id=Guid.guid();this.value=a;this.kids=[];this.defaultNumberOfKids=0;this.recv=function(a,b,c){if(b=b===this.id)this.value=c;k(this,a,b);return b};Dispatcher.inputs.push(this)}function j(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.count=0;this.changed=!1;b.reverse();this.recalc=function(){for(var d=a,f=b.length;f--;)d=d(b[f].value);this.value=d};this.recalc();this.recv=function(a,c){this.count+=1;c&&(this.changed=!0);this.count==b.length&&(this.changed&& -this.recalc(),k(this,a,this.changed),this.changed=!1,this.count=0)};for(var d=b.length;d--;)b[d].kids.push(this)}function a(a,b,d,f){this.id=Guid.guid();this.value=d?b(f.value):b;this.kids=[];this.recv=function(b,d){d&&(this.value=a(f.value)(this.value));k(this,b,d)};f.kids.push(this)}function d(a,b,d){this.id=Guid.guid();this.value=a(d.value)?b:d.value;this.kids=[];this.recv=function(b,g){var f=g&&!a(d.value);f&&(this.value=d.value);k(this,b,f)};d.kids.push(this)}function i(a){this.id=Guid.guid(); -this.value=a.value;this.kids=[];this.recv=function(b,d){var f=d&&!Value.eq(this.value,a.value);f&&(this.value=a.value);k(this,b,f)};a.kids.push(this)}function b(a,b){this.id=Guid.guid();var d=(new window.Date).getTime();this.value=a?Value.Tuple(d,b.value):d;this.kids=[];this.recv=function(d,f){f&&(this.value=a?Value.Tuple(d,b.value):d);k(this,d,f)};b.kids.push(this)}function l(a,b){this.id=Guid.guid();this.value=b.value;this.kids=[];this.count=0;this.changed=!1;this.recv=function(d,f,e){e===a.id&& -(this.changed=f);this.count+=1;2==this.count&&(this.changed&&(this.value=b.value),k(this,d,this.changed),this.count=0,this.changed=!1)};a.kids.push(this);b.kids.push(this)}function h(a,b){this.id=Guid.guid();this.value=a.value;this.kids=[];this.next=null;this.count=0;this.changed=!1;this.recv=function(d,f,e){this.count+=1;f&&(this.changed=!0,e==b.id&&null===this.next&&(this.next=b.value),e==a.id&&(this.next=a.value));2==this.count&&(this.changed&&(this.value=this.next,this.next=null),k(this,d,this.changed), -this.changed=!1,this.count=0)};a.kids.push(this);b.kids.push(this)}var k=function(a,b,d){for(var f=a.kids,e=f.length;e--;)f[e].recv(b,d,a.id)},f=function(a){return function(b){return function(f){f=new j(function(a){return function(b){return[a,b]}},[a,f]);f=new d(function(a){return a[0]},[!0,b],f);return new j(function(a){return a[1]},[f])}}};return{constant:function(a){return new e(a)},lift:function(a){return function(b){return new j(a,[b])}},lift2:function(a){return function(b){return function(d){return new j(a, -[b,d])}}},lift3:function(a){return function(b){return function(d){return function(f){return new j(a,[b,d,f])}}}},lift4:function(a){return function(b){return function(d){return function(f){return function(e){return new j(a,[b,d,f,e])}}}}},lift5:function(a){return function(b){return function(d){return function(f){return function(e){return function(h){return new j(a,[b,d,f,e,h])}}}}}},lift6:function(a){return function(b){return function(d){return function(f){return function(e){return function(h){return function(i){return new j(a, -[b,d,f,e,h,i])}}}}}}},lift7:function(a){return function(b){return function(d){return function(f){return function(e){return function(h){return function(i){return function(k){return new j(a,[b,d,f,e,h,i,k])}}}}}}}},lift8:function(a){return function(b){return function(d){return function(f){return function(e){return function(h){return function(i){return function(k){return function(l){return new j(a,[b,d,f,e,h,i,k,l])}}}}}}}}},foldp:function(b){return function(d){return function(f){return new a(b,d,!1, -f)}}},foldp_:function(b){return function(d){return function(f){return new a(b,d,!0,f)}}},foldp1:function(b){return function(d){return new a(b,function(a){return a},!0,d)}},delay:function(a){return function(b){var d=new e(b.value),f=!0,b=new l(d,new j(function(a){return function(){return a}},[d,new j(function(b){f||setTimeout(function(){Dispatcher.notify(d.id,b)},a)},[b])])),f=!1;return b}},merge:function(a){return function(b){return new h(a,b)}},merges:function(a){return Elm.List.foldl1(function(a){return function(b){return new h(a, -b)}})(a)},average:function(a){return function(b){for(var d=Array(a),f=a;f--;)d[f]=0;var f=0,e=!1,h=0;return new j(function(b){h+=b-d[f];d[f]=b;b=h/Math.max(1,e?a:f);++f==a&&(e=!0,f=0);return b},[b])}},count:function(b){return new a(function(){return function(a){return a+1}},0,!1,b)},countIf:function(b){return function(d){return new a(function(a){return function(d){return b(a)?d+1:d}},0,!1,d)}},keepIf:function(a){return function(b){return function(f){return new d(function(b){return!a(b)},b,f)}}},dropIf:function(a){return function(b){return function(f){return new d(a, -b,f)}}},keepWhen:function(a){return f(new j(function(a){return!a},[a]))},dropWhen:f,dropRepeats:function(a){return new i(a)},sampleOn:function(a){return function(b){return new l(a,b)}},timestamp:function(a){return new b(!0,a)},timeOf:function(a){return new b(!1,a)}}}(); -var Dispatcher=function(){function e(a){if(!a.hasOwnProperty("defaultNumberOfKids"))return!0;var b=a.kids.length;if(0==b)return!1;if(b>a.defaultNumberOfKids)return!0;for(var d=!1;b--;)d=d||e(a.kids[b]);return d}var j=null,a=[],d=null;return{initialize:function(){j=Elm.main();j.hasOwnProperty("recv")||(j=Elm.Signal.constant(j));d=j.value;for(var i=[],b=a.length;b--;)e(a[b])&&i.push(a[b]);a=i;document.getElementById("content").appendChild(Render.render(d));i=document.getElementById("widthChecker").offsetWidth; -i!==window.innerWidth&&Dispatcher.notify(Elm.Window.dimensions.id,Value.Tuple(i,window.innerHeight));j=Elm.Signal.lift(function(a){var b=document.getElementById("content");Render.update(b.firstChild,d,a);return d=a})(j)},notify:function(d,b){for(var e=(new window.Date).getTime(),h=!1,j=a.length;j--;)h=a[j].recv(e,d,b)||h;return h},inputs:a}}(); -Elm.HTTP=function(){function e(a){return function(d){return function(f){return function(c){return{"0":"Request",length:1,verb:b.castStringToJSString(a),url:b.castStringToJSString(d),data:null===f?null:b.castStringToJSString(f),headers:c}}}}}function j(a){return e("GET")(a)(null)(["Nil"])}function a(a,e){return function(f){if(""!==f.url){var c={value:["Waiting"]};a.push(c);var g=null;window.ActiveXObject&&(g=new ActiveXObject("Microsoft.XMLHTTP"));window.XMLHttpRequest&&(g=new XMLHttpRequest);g.onreadystatechange= -function(){4===g.readyState&&(c.value=200===g.status?["Success",l(g.responseText)]:["Failure",g.status,l(g.statusText)],setTimeout(function(){d(a,e)},0))};g.open(f.verb,f.url,!0);Elm.List.map(function(a){g.setRequestHeader(b.castStringToJSString(a[1]),b.castStringToJSString(a[2]))})(f.headers);g.send(f.data)}}}function d(a,b){0<a.length&&(Dispatcher.notify(b.id,a[0].value),"Waiting"!==a[0].value[0]&&(a.shift(),setTimeout(function(){d(a,b)},0)))}function i(b){var d=Elm.Signal.constant(["Waiting"]), -b=Elm.Signal.lift(a([],d))(b);return Elm.Signal.lift2(function(a){return function(){return a}})(d)(b)}var b=Elm.JavaScript,l=Elm.JavaScript.castJSStringToString;return{get:j,post:function(a){return function(b){return e("POST")(a)(b)(["Nil"])}},request:e,send:i,sendGet:function(a){return i(Elm.Signal.lift(j)(a))}}}(); -Elm.Input=function(){var e=Elm.JavaScript,j=Elm.JavaScript.castJSStringToString,a=function(a,d){a.placeholder=e.castStringToJSString(d);var h=Elm.Signal.constant(["Nil"]);Value.addListener(a,"keyup",function(){Dispatcher.notify(h.id,j(a.value));a.focus()});a.style.padding="1px";return Value.Tuple(Value.wrap(a),h)},d=function(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a},i=function(a){for(var e=d("select"),h=[];"Cons"===a[0];){var i=d("option"),f=Value.toText(a[1][1]); -i.value=f;i.innerHTML=f;e.appendChild(i);h.push(a[1][2]);a=a[2]}var c=Elm.Signal.constant(h[0]);Value.addListener(e,"change",function(){Dispatcher.notify(c.id,h[e.selectedIndex])});return Value.Tuple(Value.wrap(e),c)};return{textArea:function(b){return function(e){var h=d("textarea");h.rows=e;h.cols=b;return a(h,"")}},textField:function(b){var e=d("input");e.type="text";return a(e,b)},password:function(b){var e=d("input");e.type="password";return a(e,b)},checkbox:function(a){var e=d("input");e.type= -"checkbox";e.checked=a;var h=Elm.Signal.constant(a);Value.addListener(e,"change",function(){Dispatcher.notify(h.id,e.checked)});return Value.Tuple(Value.wrap(e),h)},dropDown:i,stringDropDown:function(a){return i(Elm.List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var i=d("input");i.type="button";i.value=e.castStringToJSString(a);var h=Elm.Signal.constant(!1);Value.addListener(i,"click",function(){Dispatcher.notify(h.id,!0);Dispatcher.notify(h.id,!1)});return Value.Tuple(Value.wrap(i), -h)}}}(); -Elm.Keyboard={Raw:function(){function e(a,i){return"Nil"===i[0]?i:i[1]===a?i[2]:["Cons",i[1],e(a,i[2])]}var j=Elm.Signal.constant(["Nil"]),a=Elm.Signal.constant(["Nothing"]);Value.addListener(document,"keydown",function(a){var e;a:{for(e=j.value;"Nil"!==e[0];){if(e[1]===a.keyCode){e=!0;break a}e=e[2]}e=!1}e||Dispatcher.notify(j.id,["Cons",a.keyCode,j.value])||this.removeEventListener("keydown",arguments.callee,!1)});Value.addListener(document,"keyup",function(a){var i=e(a.keyCode,j.value);Dispatcher.notify(j.id, -i)||this.removeEventListener("keyup",arguments.callee,!1)});Value.addListener(window,"blur",function(a){Dispatcher.notify(j.id,["Nil"])||this.removeEventListener("blur",arguments.callee,!1)});Value.addListener(document,"keypress",function(d){var e=Dispatcher.notify(a.id,["Just",d.charCode||d.keyCode]);Dispatcher.notify(a.id,["Nothing"]);e||this.removeEventListener("keypress",arguments.callee,!1)});return{keysDown:j,charPressed:a}}()}; -Elm.Mouse=function(){function e(a){var b=0,d=0;a||(a=window.event);if(a.pageX||a.pageY)b=a.pageX,d=a.pageY;else if(a.clientX||a.clientY)b=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,d=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return Value.Tuple(b,d)}var j=Elm.Signal.constant(Value.Tuple(0,0));j.defaultNumberOfKids=2;var a=Elm.Signal.lift(function(a){return a[1]})(j);a.defaultNumberOfKids=0;var d=Elm.Signal.lift(function(a){return a[2]})(j);d.defaultNumberOfKids= -0;var i=Elm.Signal.constant(!1),b=Elm.Signal.constant(!1),l=Elm.Signal.constant(Value.Tuple());Value.addListener(document,"click",function(a){var d=Dispatcher.notify(b.id,!0),f=Dispatcher.notify(l.id,Value.Tuple());Dispatcher.notify(b.id,!1);!d&&!f&&this.removeEventListener("click",arguments.callee,!1)});Value.addListener(document,"mousedown",function(a){Dispatcher.notify(i.id,!0)||this.removeEventListener("mousedown",arguments.callee,!1)});Value.addListener(document,"mouseup",function(a){Dispatcher.notify(i.id, -!1)||this.removeEventListener("mouseup",arguments.callee,!1)});Value.addListener(document,"mousemove",function(a){Dispatcher.notify(j.id,e(a))||this.removeEventListener("mousemove",arguments.callee,!1)});return{position:j,x:a,y:d,isClicked:b,isDown:i,clicks:l,isClickedOn:function(a){var a=Render.render(a),b=Elm.Signal.constant(!1);Value.addListener(a,"click",function(){Dispatcher.notify(b.id,!0);Dispatcher.notify(b.id,!1)});return Value.Tuple(Value.wrap(a),b)}}}(); -Elm.Random=function(){return{inRange:function(e){return function(j){return Elm.Signal.constant(Math.floor(Math.random()*(j-e+1))+e)}},randomize:function(e){return function(j){return function(a){return Elm.Signal.lift(function(){return Math.floor(Math.random()*(j-e+1))+e})(a)}}}}}(); -Elm.Time=function(){function e(){return(new window.Date).getTime()}function j(a){return function(d){var i=1E3/a,b=e(),j=b,h=0,k=!0,f=Elm.Signal.constant(h),c=0;return Elm.Signal.lift2(function(a){return function(d){if(a){var m=!k&&a;c=setTimeout(function(){j=e();h=m?0:j-b;b=j;Dispatcher.notify(f.id,h)},i)}else k&&clearTimeout(c);k=a;return d}})(d)(f)}}Elm.Signal.constant(!0);return{fpsWhen:j,fps:function(a){return j(a)(Elm.Signal.constant(!0))},every:function(a){var d=Elm.Signal.constant(e());setInterval(function(){Dispatcher.notify(d.id, -e())},a);return d},delay:Elm.Signal.delay,since:function(a){return function(d){var e=Elm.Signal.count(Elm.Signal.delay(a)(d));return Elm.Signal.lift2(function(a){return function(d){return!Value.eq(a,d)}})(Elm.Signal.count(d))(e)}},after:function(a){var a=1E3*a,d=Elm.Signal.constant(!1);setTimeout(function(){Dispatcher.notify(d.id,!0)},a);return d},before:function(a){var a=1E3*a,d=Elm.Signal.constant(!0);setTimeout(function(){Dispatcher.notify(d.id,!1)},a);return d},hour:36E5,minute:6E4,second:1E3, -ms:1,inHours:function(a){return a/36E5},inMinutes:function(a){return a/6E4},inSeconds:function(a){return a/1E3},inMss:function(a){return a},toDate:function(a){return new window.Date(a)},read:function(a){a=window.Date.parse(a);return isNaN(a)?["Nothing"]:["Just",a]}}}(); -Elm.Window=function(){var e=Elm.Signal.constant(Value.Tuple(window.innerWidth,window.innerHeight));e.defaultNumberOfKids=2;var j=Elm.Signal.lift(function(a){return a[1]})(e);j.defaultNumberOfKids=0;var a=Elm.Signal.lift(function(a){return a[2]})(e);a.defaultNumberOfKids=0;Value.addListener(window,"resize",function(a){var i=document.getElementById("widthChecker").offsetWidth;Dispatcher.notify(e.id,Value.Tuple(i,window.innerHeight))||this.removeEventListener("resize",arguments.callee,!1)});return{dimensions:e, -width:j,height:a}}(); -Elm.Date=function(){var e="Sun Mon Tue Wed Thu Fri Sat".split(" "),j="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");return{read:function(a){a=new window.Date(Elm.JavaScript.castStringToJSString(a));return isNaN(a.getTime())?["Nothing"]:["Just",a]},year:function(a){return a.getFullYear()},month:function(a){return[j[a.getMonth()]]},day:function(a){return a.getDate()},hour:function(a){return a.getHours()},minute:function(a){return a.getMinutes()},second:function(a){return a.getSeconds()},dayOfWeek:function(a){return[e[a.getDay()]]}, -toTime:function(a){return a.getTime()},Mon:["Mon"],Tue:["Tue"],Wed:["Wed"],Thu:["Thu"],Fri:["Fri"],Sat:["Sat"],Sun:["Sun"],Jan:["Jan"],Feb:["Feb"],Mar:["Mar"],Apr:["Apr"],May:["May"],Jun:["Jun"],Jul:["Jul"],Aug:["Aug"],Sep:["Sep"],Oct:["Oct"],Nov:["Nov"],Dec:["Dec"]}}();Value.addListener(document,"elm_log",function(e){console.log(e.value)});Value.addListener(document,"elm_title",function(e){document.title=e.value}); -Value.addListener(document,"elm_redirect",function(e){0<e.value.length&&(window.location=e.value)}); -Elm.Prelude=function(){function e(a){return function(d){if(a instanceof Array&&d instanceof Array){var i=a.length;if(i==d.length){for(var b=1;b<i;++b){var j=e(a[b])(d[b]);if("EQ"!==j[0])return j}return["EQ"]}return[1==d.length?"GT":"LT"]}return[a===d?"EQ":a<d?"LT":"GT"]}}var j=function(a){return function(d){var e=a%d,e=0==a?0:0<d?0<=a?e:e+d:-j(-a)(-d);return e==d?0:e}};return{eq:Value.eq,id:function(a){return a},not:function(a){return!a},fst:function(a){return a[1]},snd:function(a){return a[2]},rem:function(a){return function(d){return a% -d}},div:function(a){return function(d){return~~(a/d)}},otherwise:!0,compare:e,toFloat:function(a){return a},round:function(a){return Math.round(a)},floor:function(a){return Math.floor(a)},ceiling:function(a){return Math.ceil(a)},truncate:function(a){return~~a},readInt:function(a){var a=Elm.JavaScript.castStringToJSString(a),d=a.length;if(0===d)return["Nothing"];var e=0;if("-"==a[0]){if(1===d)return["Nothing"];e=1}for(;e<d;++e)if(!Elm.Char.isDigit(a[e]))return["Nothing"];return["Just",parseInt(a)]}, -readFloat:function(a){var a=Elm.JavaScript.castStringToJSString(a),d=a.length;if(0===d)return["Nothing"];var e=0;if("-"==a[0]){if(1===d)return["Nothing"];e=1}for(var b=0;e<d;++e)if(!Elm.Char.isDigit(a[e])){if("."===a[e]&&(b+=1,1>=b))continue;return["Nothing"]}return["Just",parseFloat(a)]},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,e:Math.E,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,atan2:function(a){return function(d){return Math.atan2(a,d)}},mod:j,min:function(a){return function(d){return Math.min(a, -d)}},max:function(a){return function(d){return Math.max(a,d)}},flip:function(a){return function(d){return function(e){return a(e)(d)}}},clamp:function(a){return function(d){return function(e){return Math.min(d,Math.max(a,e))}}},curry:function(a){return function(d){return function(e){return a(["Tuple2",d,e])}}},uncurry:function(a){return function(d){if("Tuple2"!==d[0])throw"Function was uncurry'd but was not given a pair.";return a(d[1])(d[2])}},logBase:function(a){return function(d){return Math.log(d)/ -Math.log(a)}},Just:Elm.Maybe.Just,Nothing:Elm.Maybe.Nothing,maybe:Elm.Maybe.maybe,map:Elm.List.map,zip:Elm.List.zip,zipWith:Elm.List.zipWith,filter:Elm.List.filter,head:Elm.List.head,tail:Elm.List.tail,last:Elm.List.last,length:Elm.List.length,reverse:Elm.List.reverse,foldr:Elm.List.foldr,foldr1:Elm.List.foldr1,foldl:Elm.List.foldl,foldl1:Elm.List.foldl1,and:Elm.List.and,or:Elm.List.or,all:Elm.List.all,any:Elm.List.any,sum:Elm.List.sum,product:Elm.List.product,concat:Elm.List.concat,concatMap:Elm.List.concatMap, -maximum:Elm.List.maximum,minimum:Elm.List.minimum,scanl:Elm.List.scanl,scanl1:Elm.List.scanl1,take:Elm.List.take,drop:Elm.List.drop,zip:Elm.List.zip,unzip:Elm.List.unzip,lift:Elm.Signal.lift,lift2:Elm.Signal.lift2,lift3:Elm.Signal.lift3,lift4:Elm.Signal.lift4,lift5:Elm.Signal.lift5,lift6:Elm.Signal.lift6,lift7:Elm.Signal.lift7,lift8:Elm.Signal.lift8,foldp:Elm.Signal.foldp,foldp1:Elm.Signal.foldp1,foldp_:Elm.Signal.foldp_,constant:Elm.Signal.constant,merge:Elm.Signal.merge,count:Elm.Signal.count,countIf:Elm.Signal.countIf, -average:Elm.Signal.average,keepIf:Elm.Signal.keepIf,dropIf:Elm.Signal.dropIf,keepWhen:Elm.Signal.keepWhen,dropWhen:Elm.Signal.dropWhen,dropRepeats:Elm.Signal.dropRepeats,sampleOn:Elm.Signal.sampleOn,timestamp:Elm.Signal.timestamp,timeOf:Elm.Signal.timeOf}}();(function(){var e=function(e){for(var a in e)Elm.Prelude[a]=e[a]};e(Elm.Color);e(Elm.Text);e(Elm.Graphics);e(Elm.Time);show=Value.show})(); -Elm.Dict=function(){function e(a){return function(b){return function(c){return function(d){return function(e){return["RBNode",a,b,c,d,e]}}}}}function j(a){a:{switch(a[0]){case "RBEmpty":throw"(min RBEmpty) is not defined";case "RBNode":switch(a[4][0]){case "RBEmpty":a=["Tuple2",a[2],a[3]];break a}a=j(a[4]);break a}throw"Non-exhaustive pattern match in case";}return a}function a(b){return function(c){var d;a:{switch(c[0]){case "RBEmpty":d=v;break a;case "RBNode":d=function(){switch(p(b)(c[2])[0]){case "EQ":return z(c[3]); -case "GT":return a(b)(c[5]);case "LT":return a(b)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case";}return d}}function d(a){return function(b){return function(c){var e;a:{switch(c[0]){case "RBEmpty":e=a;break a;case "RBNode":e=function(){switch(p(b)(c[2])[0]){case "EQ":return c[3];case "GT":return d(a)(b)(c[5]);case "LT":return d(a)(b)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case"; -}return e}}}function i(b){return function(c){return E(a(b)(c))}}function b(a){a:{switch(a[0]){case "RBNode":switch(a[5][0]){case "RBNode":a=e(a[1])(a[5][2])(a[5][3])(e(A)(a[2])(a[3])(a[4])(a[5][4]))(a[5][5]);break a}}throw"rotateLeft of a node without enough children";}return a}function l(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":a=e(a[1])(a[4][2])(a[4][3])(a[4][4])(e(A)(a[2])(a[3])(a[4][5])(a[5]));break a}}throw"rotateRight of a node without enough children";}return a}function h(a){a:{switch(a[0]){case "Black":a= -A;break a;case "Red":a=D;break a}throw"Non-exhaustive pattern match in case";}return a}function k(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[5][0]){case "RBNode":a=e(h(a[1]))(a[2])(a[3])(e(h(a[4][1]))(a[4][2])(a[4][3])(a[4][4])(a[4][5]))(e(h(a[5][1]))(a[5][2])(a[5][3])(a[5][4])(a[5][5]));break a}}}throw"color_flip called on a RBEmpty or RBNode with a RBEmpty child";}return a}function f(a){a:switch(a[0]){case "RBNode":switch(a[5][0]){case "RBNode":switch(a[5][1][0]){case "Red":a= -b(a);break a}}}a:switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":switch(a[4][4][0]){case "RBNode":switch(a[4][4][1][0]){case "Red":a=l(a);break a}}}}}a:switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":switch(a[5][0]){case "RBNode":switch(a[5][1][0]){case "Red":a=k(a);break a}}}}}return a}function c(a){a:switch(a[0]){case "RBNode":switch(a[1][0]){case "Red":a=e(D)(a[2])(a[3])(a[4])(a[5]);break a}}return a}function g(a){return function(b){return function(d){var g= -function(c){var d;a:{switch(c[0]){case "RBEmpty":d=e(A)(a)(b)(y)(y);break a;case "RBNode":d=function(){switch(p(a)(c[2])[0]){case "EQ":return e(c[1])(c[2])(b)(c[4])(c[5]);case "GT":return e(c[1])(c[2])(c[3])(c[4])(g(c[5]));case "LT":return e(c[1])(c[2])(c[3])(g(c[4]))(c[5])}throw"Non-exhaustive pattern match in case";}();d=f(d);break a}throw"Non-exhaustive pattern match in case";}return d};return c(g(d))}}}function r(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":a= -!0;break a}}}a=!1}return a}function m(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][4][0]){case "RBNode":switch(a[4][4][1][0]){case "Red":a=!0;break a}}}}a=!1}return a}function n(a){if(w(r(a))&&w(m(a))){a=k(a);a:switch(a[0]){case "RBNode":b:switch(a[5][0]){case "RBNode":switch(a[5][4][0]){case "RBNode":switch(a[5][4][1][0]){case "Red":a=k(b(e(a[1])(a[2])(a[3])(a[4])(l(a[5]))));break b}}}break a}}return a}function u(a){return function(b){var d=function(b){a:{switch(b[0]){case "RBEmpty":b= -y;break a;case "RBNode":if("LT"===p(a)(b[2])[0])b:{b=n(b);switch(b[0]){case "RBEmpty":throw"delLT on RBEmpty";case "RBNode":b=f(e(b[1])(b[2])(b[3])(d(b[4]))(b[5]));break b}break}else{var g=r(b)?l(b):b,h;b:{switch(g[0]){case "RBNode":switch(g[5][0]){case "RBEmpty":h=C(a,g[2]);break b}}h=!1}if(h)b=g[4];else{g=w;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":h=!0;break b}}}h=!1}if(g=g(h)){g=w;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":h= -!0;break b}}}}h=!1}g=g(h)}g&&(b=k(b),b=m(b)?k(l(b)):b);b:{switch(b[0]){case "RBNode":g=C(a,b[2]);break b}g=!1}if(g)b:{switch(b[0]){case "RBEmpty":throw"delEQ called on a RBEmpty";case "RBNode":h=j(b[5]);c:{switch(h[0]){case "Tuple2":g=h[1];break c}break}c:{switch(h[0]){case "Tuple2":h=h[2];break c}break}var g=e(b[1])(g)(h)(b[4]),i=function(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBEmpty":a=y;break a}}b:{a=n(a);switch(a[0]){case "RBEmpty":a=y;break b;case "RBNode":a=f(e(a[1])(a[2])(a[3])(i(a[4]))(a[5])); -break b}throw"Non-exhaustive pattern match in case";}}return a},b=c(i(b[5])),b=f(g(b));break b}break}else b:{switch(b[0]){case "RBEmpty":throw"delGT called on a RBEmpty";case "RBNode":b=f(e(b[1])(b[2])(b[3])(b[4])(d(b[5])));break b}break}}}break a}throw"Non-exhaustive pattern match in case";}return b};return i(a)(b)?c(d(b)):b}}function x(a){return function(b){a:{switch(b[0]){case "RBEmpty":b=y;break a;case "RBNode":b=e(b[1])(b[2])(a(b[3]))(x(a)(b[4]))(x(a)(b[5]));break a}throw"Non-exhaustive pattern match in case"; -}return b}}function q(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=q(a)(a(c[2])(c[3])(q(a)(b)(c[4])))(c[5]);break a}throw"Non-exhaustive pattern match in case";}return c}}}function t(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=t(a)(a(c[2])(c[3])(t(a)(b)(c[5])))(c[4]);break a}throw"Non-exhaustive pattern match in case";}return c}}}var p=Elm.Prelude.compare,s=Elm.Prelude.uncurry,v=Elm.Prelude.Nothing, -z=Elm.Prelude.Just,w=Elm.Prelude.not,C=Elm.Prelude.eq,E=Elm.Maybe.isJust,A=["Red"],D=["Black"],y=["RBEmpty"],B=y;return{$op:{},empty:B,lookup:a,findWithDefault:d,member:i,insert:g,singleton:function(a){return function(b){return g(a)(b)(y)}},remove:u,map:x,foldl:q,foldr:t,union:function(a){return function(b){return q(g)(b)(a)}},intersect:function(a){return function(b){return q(function(a){return function(c){return function(d){return i(a)(b)?g(a)(c)(d):d}}})(B)(a)}},diff:function(a){return function(b){return q(function(a){return function(){return function(b){return u(a)(b)}}})(a)(b)}}, -keys:function(a){return t(function(a){return function(){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},values:function(a){return t(function(){return function(a){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},toList:function(a){return t(function(a){return function(b){return function(c){return["Cons",["Tuple2",a,b],c]}}})(["Nil"])(a)},fromList:function(a){return Elm.List.foldl(s(g))(B)(a)}}}(); -Elm.Set=function(){var e=Elm.Dict.empty,j=Elm.Dict.remove,a=Elm.Dict.member,d=Elm.Dict.union,i=Elm.Dict.intersect,b=Elm.Dict.diff,l=Elm.Dict.keys,h=Elm.List.foldl(function(a){return function(b){return Elm.Dict.insert(a)(["Tuple0"])(b)}})(e);return{empty:e,singleton:function(a){return Elm.Dict.singleton(a)(["Tuple0"])},insert:function(a){return Elm.Dict.insert(a)(["Tuple0"])},remove:j,member:a,union:d,intersect:i,diff:b,toList:l,fromList:h,foldl:function(a){return Elm.Dict.foldl(function(b){return function(){return function(c){return a(b)(c)}}})}, -foldr:function(a){return Elm.Dict.foldr(function(b){return function(){return function(c){return a(b)(c)}}})},map:function(a){return function(b){b=l(b);return h(Elm.List.map(a)(b))}}}}(); -(function(){try{var e={};for(this.i in Elm)eval("var "+this.i+"=Elm[this.i];");if(Elm.Automaton)throw"Module name collision, 'Automaton' is already defined.";Elm.Automaton=function(){function a(a){return["Automaton",a]}function d(b){return a(function(a){var c=unzip(map(function(b){a:{switch(b[0]){case "Automaton":b=b[1](a);break a}throw"Non-exhaustive pattern match in case";}return b})(b)),e;a:{switch(c[0]){case "Tuple2":e=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c= -c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",e,d(c)]})}function i(b){return a(function(a){return["Tuple2",b(a),i(b)]})}function b(c){return function(d){return a(function(a){a=d(a)(c);return["Tuple2",a,b(a)(d)]})}}function j(b){return function(c){return a(function(a){var d=c(a)(b);a:{switch(d[0]){case "Tuple2":a=d[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(d[0]){case "Tuple2":d=d[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2", -a,j(d)(c)]})}}function h(a){return function(b){a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":b=["Tuple2",a[1]-b[1],a[2]-b[2]];break b}break}break a}throw"Non-exhaustive pattern match in case";}return b}}function k(a){return function(b){var c;a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":var d=function(a){return["Tuple2",b[2],["Tuple2",a,b[2]]]};c=function(){switch(b[1][0]){case "DragFrom":var c;a[1]?c=["Tuple2",uncurry(move)(h(a[2])(b[1][1]))(b[2]),["Tuple2",["DragFrom", -b[1][1]],b[2]]]:(c=uncurry(move)(h(a[2])(b[1][1]))(b[2]),c=["Tuple2",c,["Tuple2",g,c]]);return c;case "Ignore":return d(a[1]?r:g);case "Listen":return d(not(a[1])?g:isWithin(a[2])(b[2])?["DragFrom",a[2]]:r)}throw"Non-exhaustive pattern match in case";}();break b}break}break a}throw"Non-exhaustive pattern match in case";}return c}}try{if(!(Elm.Prelude instanceof Object))throw"module not found";}catch(f){throw"Module 'Prelude' is missing. Compile with --make flag or load missing module in a separate JavaScript file."; -}var c={};for(this.i in Elm.Prelude)c[this.i]||eval("var "+this.i+" = Elm.Prelude[this.i];");var g=["Listen"],r=["Ignore"];e[">>>"]=function(b){return function(c){var d;a:{switch(b[0]){case "Automaton":d=b[1];break a}throw"Non-exhaustive pattern match in case";}var f;a:{switch(c[0]){case "Automaton":f=c[1];break a}throw"Non-exhaustive pattern match in case";}return a(function(a){var a=d(a),b;a:{switch(a[0]){case "Tuple2":b=a[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(a[0]){case "Tuple2":a= -a[2];break a}throw"Non-exhaustive pattern match in case";}var c=f(b);a:{switch(c[0]){case "Tuple2":b=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c=c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",b,e[">>>"](a)(c)]})}};e["<<<"]=function(a){return function(b){return e[">>>"](b)(a)}};e["^>>"]=function(a){return function(b){return e[">>>"](i(a))(b)}};e[">>^"]=function(a){return function(b){return e[">>>"](a)(i(b))}};e["^<<"]=function(a){return function(b){return e[">>>"](b)(i(a))}}; -e["<<^"]=function(a){return function(b){return e[">>>"](i(b))(a)}};c=b(0)(function(){return function(a){return 1+a}});return{$op:{">>>":e[">>>"],"<<<":e["<<<"],"^>>":e["^>>"],">>^":e[">>^"],"^<<":e["^<<"],"<<^":e["<<^"]},run:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=lift(fst)(foldp_(function(a){return function(b){a:{switch(b[0]){case "Tuple2":switch(b[2][0]){case "Automaton":b=b[2][1](a);break a}}throw"Non-exhaustive pattern match in case";}return b}})(a[1])(b));break a}throw"Non-exhaustive pattern match in case"; -}return b}},step:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return b}},combine:d,pure:i,init:b,init_:j,count:c,draggable:function(a){return j(["Tuple2",g,a])(k)}}}();Elm.main=function(){return Elm.Automaton.main}}catch(j){Elm.main=function(){document.body.innerHTML=Elm.Text.monospace('<br/><h2>Your browser may not be supported. Are you using a modern browser?</h2><br/><span style="color:grey">Runtime Error in Automaton module:<br/>'+ -j+"</span>");throw j;}}})(); \ No newline at end of file diff --git a/elm/elm-runtime-0.7.1.1.js b/elm/elm-runtime-0.7.1.1.js deleted file mode 100644 index 8608836..0000000 --- a/elm/elm-runtime-0.7.1.1.js +++ /dev/null @@ -1,142 +0,0 @@ -Elm={};var Guid=function(){var d=0;return{guid:function(){return d+=1}}}(); -Elm.JavaScript=function(){function d(b){for(var a=["Nil"],c=b.length;c--;)a=["Cons",b[c],a];return a}function f(b){for(var a=[];"Cons"===b[0];)a.push(b[1]),b=b[2];return a}function b(b){return b.slice(1)}function c(b){return["Tuple"+b.length].concat(b)}return{castJSBoolToBool:function(b){return b},castBoolToJSBool:function(b){return b},castJSNumberToFloat:function(b){return b},castFloatToJSNumber:function(b){return b},castJSNumberToInt:function(b){return~~b},castIntToJSNumber:function(b){return b}, -Experimental:{castJSElementToElement:function(b){return function(a){return function(c){return["Element",Guid.guid(),["EExternalHtml",c],b,a,1,["Nothing"],["Nothing"]]}}},castElementToJSElement:function(b){return Render.render(b)}},castJSArrayToList:d,castListToJSArray:f,castJSStringToString:d,castStringToJSString:function(b){return"string"===typeof b?b:f(b).join("")},castTupleToJSTuple2:b,castTupleToJSTuple3:b,castTupleToJSTuple4:b,castTupleToJSTuple5:b,castJSTupleToTuple2:c,castJSTupleToTuple3:c, -castJSTupleToTuple4:c,castJSTupleToTuple5:c}}();var JSjson=window.JSON; -Elm.JSON=function(){function d(a,b){return function(j){return function(l){var g=c.castStringToJSString(j);return l[1].hasOwnProperty(g)&&(l=l[1][g],l[0]===a)?l[1]:b}}}function f(a){return function(b){function j(a){switch(a[0]){case "JsonNull":return null;case "JsonString":return c.castStringToJSString(a[1]);case "JsonObject":var g={};a=a[1][1];for(var e in a)g[e]=j(a[e]);return g;case "JsonArray":g=c.castListToJSArray(a[1]);for(e=g.length;e--;)g[e]=j(g[e]);return g;default:return a[1]}}return JSjson.stringify(j(["JsonObject", -b]),null,c.castStringToJSString(a))}}function b(a){function b(a){switch(typeof a){case "string":return["JsonString",c.castJSStringToString(a)];case "number":return["JsonNumber",c.castJSNumberToFloat(a)];case "boolean":return["JsonBool",c.castJSBoolToBool(a)];case "object":if(null===a)return["JsonNull"];for(var g in a)a[g]=b(a[g]);return a instanceof Array?["JsonArray",c.castJSArrayToList(a)]:["JsonObject",["JSON",a]]}}a=JSjson.parse(a);for(var j in a)a[j]=b(a[j]);return["JSON",a]}var c=Elm.JavaScript, -h=["JSON",{}];return{empty:h,singleton:function(a){return function(b){var j={};j[c.castStringToJSString(a)]=b;return["JSON",j]}},insert:function(a){return function(b){return function(j){j=j[1];var l={},g;for(g in j)l[g]=j[g];l[c.castStringToJSString(a)]=b;return["JSON",l]}}},lookup:function(a){return function(b){var j=c.castStringToJSString(a);return b[1].hasOwnProperty(j)?["Just",b[1][j]]:["Nothing"]}},findString:d("JsonString",["Nil"]),findObject:d("JsonObject",h),findArray:d("JsonArray",["Nil"]), -findWithDefault:function(a){return function(b){return function(j){var l=c.castStringToJSString(b);return j[1].hasOwnProperty(l)?j[1][l]:a}}},remove:function(a){return function(b){b=b[1];var j={},l;for(l in b)j[l]=b[l];delete j[c.castStringToJSString(a)];return["JSON",j]}},toPrettyJSString:f,toJSString:f(""),fromJSString:b,toPrettyString:function(a){return function(b){return c.castJSStringToString(f(a)(b))}},toString:function(a){return c.castJSStringToString(f("")(a))},fromString:function(a){return b(c.castStringToJSString(a))}, -toList:function(a){a=a[1];var b=[],j;for(j in a)b.push(Value.Tuple(c.castJSStringToString(j),a[j]));return c.castJSArrayToList(b)},fromList:function(a){a=c.castListToJSArray(a);for(var b={},j=a.length;j--;)b[c.castStringToJSString(a[j][1])]=a[j][2];return["JSON",b]},JsonString:function(a){return["JsonString",a]},JsonNumber:function(a){return["JsonNumber",a]},JsonBool:function(a){return["JsonBool",a]},JsonNull:["JsonNull"],JsonArray:function(a){return["JsonArray",a]},JsonObject:function(a){return["JsonObject", -a]}}}(); -var Value=function(){function d(a){if(0==a.length)return a;a=a.replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br/>");a=a.split("<br/>");for(var b=a.length;b--;){var c=a,l=b,g;g=a[b];if(0!=g.length){g=g.split("");" "==g[0]&&(g[0]=" ");for(var e=g.length;--e;)" "==g[e][0]&&" "==g[e-1]&&(g[e-1]+=g[e],g[e]="");for(e=g.length;e--;)if(1<g[e].length&&" "==g[e][0]){for(var k=g[e].split(""),f=k.length-2;0<=f;f-=2)k[f]=" ";g[e]=k.join("")}g=g.join(""); -g=" "===g[g.length-1]?g.slice(0,-1)+" ":g}c[l]=g}return a.join("<br/>")}var f=function(a,b){if("object"===typeof a){if(a.hasOwnProperty("_")){for(var c in a)if(a[c]!=b[c])return!1;for(c in b)if(a[c]!=b[c])return!1;return!0}if(a===b)return!0;if(a.length!==b.length)return!1;for(c=a.length;c--;)if(!f(a[c],b[c]))return!1;return!0}return a===b},b=function(a){if("function"===typeof a)return"<function>";if("boolean"===typeof a)return a?"True":"False";if("number"!==typeof a){if("string"===typeof a&& -2>a.length)return"'"+a+"'";if("object"===typeof a&&a.hasOwnProperty("_")){var c=[],j;for(j in a)if("_"!=j)for(var l=a[j].length;l--;)c.push(j+" = "+b(a[j][l]));return 0===c.length?"{}":"{ "+c.join(", ")+" }"}if(a[0]){if("Tuple"===a[0].substring(0,5)){c=Array(a.length-1);for(l=a.length;--l;)c[l-1]=b(a[l]);return"("+c.join(",")+")"}if("Cons"===a[0]){j="string"===typeof a[1]?'"':"]";var l="string"===typeof a[1]?"":",",g="string"===typeof a[1]?function(a){return a}:b,c=("string"===typeof a[1]?'"':"[")+ -g(a[1]);for(a=a[2];;)if("Cons"===a[0])c+=l+g(a[1]),a=a[2];else return c+j}else{if("Nil"===a[0])return"[]";if("JSON"===a[0])return"(JSON.fromList "+b(Elm.JSON.toList(a))+")";if("RBNode"===a[0]||"RBEmpty"===a[0])return a=Elm.Dict.foldr(function(a){return function(g){return function(b){return["Cons",["Tuple2",a,g],b]}}})(["Nil"])(a),c="Dict","Cons"===a[0]&&"Tuple0"===a[1][2][0]&&(c="Set",a=Elm.List.map(function(a){return a[1]})(a)),"("+c+".fromList "+b(a)+")";c="";for(l=a.length;--l;)c=" "+b(a[l])+c; -c=a[0]+c;return 1<a.length?"("+c+")":c}}}return a+""},c=function(a){for(var b=["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b},h;h=document.addEventListener?function(a,b,c){a.addEventListener(b,c,!1)}:function(a,b,c){a.attachEvent("on"+b,c)};return{eq:f,str:c,show:function(a){return c(b(a))},Tuple:function(){var a=arguments.length,b=Array(a+1);for(b[0]="Tuple"+arguments.length;a--;)b[a+1]=arguments[a];return b},append:function(a,b){if("string"===typeof a&&"string"===typeof b)return a.concat(b); -if("Nil"===a[0])return b;var c=["Cons",a[1],["Nil"]],l=c;for(a=a[2];"Cons"===a[0];)l[2]=["Cons",a[1],["Nil"]],a=a[2],l=l[2];l[2]=b;return c},listToArray:function(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b},toText:function(a){if("string"===typeof a)return d(a);for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return d(b.join(""))},properEscape:d,getTextSize:function(a,b,c){var l=document.createElement("div");l.innerHTML=c;l.style.textAlign="left";0<a&&(l.style.width=a+"px");l.style.visibility= -"hidden";l.style.styleFloat="left";l.style.cssFloat="left";document.body.appendChild(l);c=window.getComputedStyle(l,null);a=c.getPropertyValue("width").slice(0,-2)-0;c=c.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(l);return[Math.ceil(a),Math.ceil(Math.max(b,c))]},getSize:function(a){a=a.cloneNode(!0);a.style.visibility="hidden";a.style.styleFloat="left";a.style.cssFloat="left";document.body.appendChild(a);var b=a.offsetWidth,c=a.offsetHeight;document.body.removeChild(a);return[b, -c]},getExcess:function(a){a=a.cloneNode(!0);a.style.visibility="hidden";a.style.styleFloat="left";a.style.cssFloat="left";document.body.appendChild(a);var b=a.offsetWidth,c=a.offsetHeight,l=window.getComputedStyle(a,null),g=l.getPropertyValue("width").slice(0,-2)-0,l=l.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(a);return[b-g,c-l]},groupForms:function(a){a=Elm.JavaScript.castListToJSArray(a);for(var b=[],c=[],l=a.length;l--;){var g=a[l];switch(g[4][0]){case "FElement":0<c.length&& -(b.push(c),c=[]);b.push(g);break;default:c.push(g)}}0<c.length&&b.push(c);return b},wrap:function(b){var c=Value.getSize(b);return["Element",Guid.guid(),["EHtml",b],c[0],c[1],1,["Nothing"],["Nothing"]]},addListener:h}}(); -Elm.List=function(){function d(b){return function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&g("map");var e=["Cons",b(a[1]),["Nil"]],c=e;for(a=a[2];"Cons"===a[0];)c[2]=["Cons",b(a[1]),["Nil"]],a=a[2],c=c[2];return e}}function f(a){return function(b){return function(e){var c=b;if("Nil"===e[0])return c;for("Cons"!==e[0]&&g("foldl");"Cons"===e[0];)c=a(e[1])(c),e=e[2];return c}}}function b(a){return function(b){return function(e){var c=b;if("Nil"===e[0])return c;"Cons"!==e[0]&&g("foldr");for(var k=[];"Cons"=== -e[0];)k.push(e[1]),e=e[2];for(e=k.length;e--;)c=a(k[e])(c);return c}}}function c(a){return function(b){var g;"Cons"!==b[0]?g=void 0:(g=b[1],b=b[2],g=f(a)(g)(b));return g}}function h(b){return function(a){return function(e){if("Nil"===e[0])return["Cons",a,["Nil"]];"Cons"!==e[0]&&g("scanl");for(var c=[a];"Cons"===e[0];)a=b(e[1])(a),c.push(a),e=e[2];e=["Nil"];for(var k=c.length;k--;)e=["Cons",c[k],e];return e}}}function a(b){return function(e){a:{for(var g=[function(b){return"Nil"!==b[0]?void 0:["Tuple2", -["Nil"],["Nil"]]},function(e){if("Cons"===e[0]){var g=e[1];e=e[2];var c=a(b)(e);"Tuple2"!==c[0]?g=void 0:(e=c[1],c=c[2],g=b(g)?["Tuple2",["Cons",g,e],c]:["Tuple2",e,["Cons",g,c]]);return g}}],c=g.length;c--;){var k=g[c](e);if(void 0!==k){e=k;break a}}e=void 0}return e}}function m(b){a:{for(var a=[function(b){return"Nil"!==b[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(b){if("Cons"!==b[0])b=void 0;else if(b=["Tuple2",b[1],m(b[2])],"Tuple2"!==b[0]||"Tuple2"!==b[1][0])b=void 0;else{var a=b[1][1],e= -b[1][2];b="Tuple2"!==b[2][0]?void 0:["Tuple2",["Cons",a,b[2][1]],["Cons",e,b[2][2]]]}return b}],e=a.length;e--;){var g=a[e](b);if(void 0!==g){b=g;break a}}b=void 0}return b}function j(b){return function(a){a:{for(var e=[function(b){return"Nil"!==b[0]?void 0:["Nil"]},function(b){if("Cons"===b[0]){var a=b[1];return"Nil"!==b[2][0]?void 0:["Cons",a,["Nil"]]}},function(a){if("Cons"===a[0]){var e=a[1];if("Cons"===a[2][0]){var g=a[2][1];a=a[2][2];return["Cons",e,["Cons",b,j(b)(["Cons",g,a])]]}}}],g=e.length;g--;){var c= -e[g](a);if(void 0!==c){a=c;break a}}a=void 0}return a}}function l(b){return function(a){a:{for(var e=[function(b){return"Nil"!==b[0]?void 0:["Nil"]},function(b){if("Cons"===b[0]){var a=b[1];return"Nil"!==b[2][0]?void 0:a}},function(a){if("Cons"===a[0]){var e=a[1];if("Cons"===a[2][0]){var g=a[2][1];a=a[2][2];return Value.append(e,Value.append(b,l(b)(["Cons",g,a])))}}}],g=e.length;g--;){var c=e[g](a);if(void 0!==c){a=c;break a}}a=void 0}return a}}var g=function(b){throw"Function '"+b+"' expecting a list!"; -},e=f(function(b){return function(a){return["Cons",b,a]}})(["Nil"]),k=b(function(b){return function(a){return Value.append(b,a)}})(["Nil"]),x=f(function(b){return function(a){return b&&a}})(!0),n=f(function(b){return function(a){return b||a}})(!1),p=f(function(b){return function(a){return b+a}})(0),s=f(function(b){return function(a){return b*a}})(1),v=c(function(b){return function(a){return Math.max(b,a)}}),t=c(function(b){return function(a){return Math.min(b,a)}});return{head:function(b){if("Cons"!== -b[0])throw"Error: 'head' only accepts lists of length greater than one.";return b[1]},tail:function(b){if("Cons"!==b[0])throw"Error: 'tail' only accepts lists of length greater than one.";return b[2]},last:function(b){if("Cons"!==b[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var a=b[1];"Cons"===b[0];)a=b[1],b=b[2];return a},map:d,foldl:f,foldr:b,foldl1:c,foldr1:function(b){return function(a){if("Nil"===a[0])throw"'foldr1' requires an non-empty list.";"Cons"!==a[0]&& -g("foldr1");for(var e=[];"Cons"===a[0];)e.push(a[1]),a=a[2];a=e.pop();for(var c=e.length;c--;)a=b(e[c])(a);return a}},scanl:h,scanl1:function(b){return function(a){if("Cons"!==a[0])throw"Error: 'scanl1' requires a list of at least length 1.";return h(b)(a[1])(a[2])}},filter:function(b){return function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&g("filter");for(var e=[];"Cons"===a[0];)b(a[1])&&e.push(a[1]),a=a[2];a=["Nil"];for(var c=e.length;c--;)a=["Cons",e[c],a];return a}},length:function(b){for(var a= -0;"Cons"===b[0];)a+=1,b=b[2];return a},reverse:e,concat:k,concatMap:function(b){return function(a){return k(d(b)(a))}},and:x,or:n,all:function(b){return f(function(a){return function(e){return e&&b(a)}})(!0)},any:function(b){return f(function(a){return function(e){return e||b(a)}})(!1)},sum:p,product:s,maximum:v,minimum:t,partition:a,zipWith:function(b){return function(a){return function(e){if("Nil"===a[0]||"Nil"===e[0])return["Nil"];("Cons"!==a[0]||"Cons"!==e[0])&&g("zipWith");for(var c=[];"Cons"=== -a[0]&&"Cons"===e[0];)c.push(b(a[1])(e[1])),a=a[2],e=e[2];e=["Nil"];for(var k=c.length;k--;)e=["Cons",c[k],e];return e}}},zip:function(a){return function(b){if("Nil"===a[0]||"Nil"===b[0])return["Nil"];("Cons"!==a[0]||"Cons"!==b[0])&&g("zip");for(var e=[];"Cons"===a[0]&&"Cons"===b[0];)e.push(["Tuple2",a[1],b[1]]),a=a[2],b=b[2];b=["Nil"];for(var c=e.length;c--;)b=["Cons",e[c],b];return b}},unzip:m,intersperse:j,intercalate:l,sort:function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&g("sort");for(var b= -[];"Cons"===a[0];)b.push(a[1]),a=a[2];b.sort(function(a,b){return a-b});a=["Nil"];for(var e=b.length;e--;)a=["Cons",b[e],a];return a},take:function(a){return function(b){if(0>=a)return["Nil"];if("Nil"===b[0])return b;"Cons"!==b[0]&&g("take");var e=["Cons",b[1],["Nil"]],c=e;b=b[2];for(--a;"Cons"===b[0]&&0<a;)c[2]=["Cons",b[1],["Nil"]],c=c[2],b=b[2],--a;return e}},drop:function(a){return function(b){if("Nil"===b[0])return b;for("Cons"!==b[0]&&g("drop");"Cons"===b[0]&&0<a;)b=b[2],--a;return b}}}}(); -Elm.Maybe=function(){function d(f){return function(b){return"Just"===f[0]?["Cons",f[1],b]:b}}return{Just:function(f){return["Just",f]},Nothing:["Nothing"],justs:Elm.List.foldr(d)(["Nil"]),isJust:function(f){return"Just"===f[0]},isNothing:function(f){return"Nothing"===f[0]},cons:d,maybe:function(f){return function(b){return function(c){return"Just"===c[0]?b(c[1]):f}}}}}(); -Elm.Either=function(){function d(b){return"Left"==b[0]}function f(b){return"Right"==b[0]}function b(b){return Elm.List.map(function(b){return b[1]})(b)}return{Left:function(b){return["Left",b]},Right:function(b){return["Right",b]},either:function(b){return function(f){return function(a){switch(a[0]){case "Left":return b(a[1]);case "Right":return f(a[1])}}}},isLeft:d,isRight:f,lefts:function(c){return b(Elm.List.filter(d)(c))},rights:function(c){return b(Elm.List.filter(f)(c))},partition:function(c){c= -Elm.List.partition(d)(c);c[1]=b(c[1]);c[2]=b(c[2]);return c}}}(); -Elm.Char=function(){function d(b,a){return function(c){c=c.charCodeAt(0);return b<=c&&c<=a}}var f=d(48,57),b=d(97,102),c=d(65,70);return{fromCode:function(b){return String.fromCharCode(b)},toCode:function(b){return b.charCodeAt(0)},toUpper:function(b){return b.toUpperCase()},toLower:function(b){return b.toLowerCase()},toLocaleUpper:function(b){return b.toLocaleUpperCase()},toLocaleLower:function(b){return b.toLocaleLowerCase()},isLower:d(97,122),isUpper:d(65,90),isDigit:f,isOctDigit:d(48,55),isHexDigit:function(d){return f(d)|| -b(d)||c(d)}}}(); -Elm.Color=function(){function d(f){var b=f.value*f.saturation,c=f.hue/60,d=b*(1-Math.abs(c%2-1)),a=0,m=0,j=0;0<=c&&1>c?(a=b,m=d,j=0):1<=c&&2>c?(a=d,m=b,j=0):2<=c&&3>c?(a=0,m=b,j=d):3<=c&&4>c?(a=0,m=d,j=b):4<=c&&5>c?(a=d,m=0,j=b):5<=c&&6>c&&(a=b,m=0,j=d);f=f.value-b;return["Color",Math.round(255*(a+f)),Math.round(255*(m+f)),Math.round(255*(j+f)),1]}return{rgba:function(f){return function(b){return function(c){return function(d){return["Color",f,b,c,d]}}}},rgb:function(f){return function(b){return function(c){return["Color",f, -b,c,1]}}},hsva:function(f){return function(b){return function(c){return function(h){var a=d({hue:f,saturation:b,value:c});a[4]=h;return a}}}},hsv:function(f){return function(b){return function(c){return d({hue:f,saturation:b,value:c})}}},red:["Color",255,0,0,1],green:["Color",0,255,0,1],blue:["Color",0,0,255,1],yellow:["Color",255,255,0,1],cyan:["Color",0,255,255,1],magenta:["Color",255,0,255,1],black:["Color",0,0,0,1],white:["Color",255,255,255,1],gray:["Color",128,128,128,1],grey:["Color",128,128, -128,1],complement:function(f){var b;b=f[1]/255;var c=f[2]/255;f=f[3]/255;var h=Math.max(b,c,f),a=Math.min(b,c,f),a=h-a,m=0;0===a?m=0:h===b?m=(c-f)/a%6:h===c?m=(f-b)/a+2:h===f&&(m=(b-c)/a+4);b={value:h,hue:60*m,saturation:0===h?0:a/h};b.hue=(b.hue+180)%360;return d(b)},extract:function(f){return 1===f[4]?"rgb("+f[1]+","+f[2]+","+f[3]+")":"rgba("+f[1]+","+f[2]+","+f[3]+","+f[4]+")"}}}(); -var Collage=function(){function d(b,a){var e=a.length-1;if(!(0>=e))for(b.moveTo(a[e][1],a[e][2]);e--;)b.lineTo(a[e][1],a[e][2])}function f(b,a,e,c){0===b.length&&(b=[8,4]);var f=c.length-1;if(!(0>=f)){var n=c[f][1],p=c[f][2],d=0,j=0,h=0,m=0,q=0,u=0,w=b.length,z=!0,y=b[0];for(a.moveTo(n,p);f--;){d=c[f][1];j=c[f][2];h=d-n;m=j-p;for(q=Math.sqrt(h*h+m*m);y<=q;)n+=h*y/q,p+=m*y/q,a[z?"lineTo":"moveTo"](n,p),h=d-n,m=j-p,q=Math.sqrt(h*h+m*m),z=!z,u=(u+1)%w,y=b[u];0<q&&(a[z?"lineTo":"moveTo"](d,j),y-=q);n= -d;p=j}}a.strokeStyle=Elm.Color.extract(e);a.stroke()}function b(b,a,e,c,x){a.clearRect(0,0,e,c);for(e=x.length;e--;){var n=x[e],p=b;c=a;var h=n[1],m=n[2],t=n[3][1],r=n[3][2],n=n[4];c.save();(0!==t||0!==r)&&c.translate(t,r);h!==~~h&&c.rotate(2*Math.PI*h);1!==m&&c.scale(m,m);c.beginPath();switch(n[0]){case "FLine":a:switch(p=c,h=n,n=h[3][1],h[1][0]){case "Solid":h=h[2];d(p,n);p.strokeStyle=Elm.Color.extract(h);p.stroke();break;case "Dotted":f([3,3],p,h[2],n);break a;case "Dashed":f([8,4],p,h[2],n); -break a;case "Custom":f(h[1][1],p,h[2],n)}break;case "FShape":a:switch(t=p,m=c,p=n[1],h=n[2],n=n[3][1],p[0]){case "Filled":p=m;d(p,n);p.fillStyle=Elm.Color.extract(h);p.fill();break a;case "Outlined":p=m;d(p,n);p.strokeStyle=Elm.Color.extract(h);p.stroke();break a;case "Textured":h=t;p=p[1];t=new Image;t.src=j.castStringToJSString(p);t.onload=h;d(m,n);m.fillStyle=m.createPattern(t,"repeat");m.fill();break a;case "CustomOutline":f(p[1],m,h,n)}break;case "FImage":h=c,m=n[1],t=n[2],n=n[3],r=new Image, -r.onload=p,r.src=j.castStringToJSString(n),h.drawImage(r,-m/2,-t/2,m,t)}c.restore()}}function c(a,c,e){var k=Render.newElement("canvas");a=~~a;c=~~c;k.style.width=a+"px";k.style.height=c+"px";k.style.display="block";k.width=a;k.height=c;if(k.getContext){var f=k.getContext("2d");b(function(){b(this,f,a,c,e)},f,a,c,e);return k}k.innerHTML="Your browser does not support the canvas element.";return k}function h(b,a,e,c,f,n,d){b="translate("+(e-f/2)+"px,"+(c-n/2)+"px) "+(1===a?"":"scale("+a+","+a+")")+ -" "+(b===~~b?"":"rotate("+360*b+"deg)");d.style.transform=b;d.style.msTransform=b;d.style.MozTransform=b;d.style.webkitTransform=b;d.style.OTransform=b}function a(a,g,e){if(!Value.eq(e,g)){var k=a.style.width.slice(0,-2)-0,f=a.style.height.slice(0,-2)-0;if("object"===typeof e[0]){if("object"===typeof g[0]&&a.getContext){var n=a.getContext("2d");return b(function(){b(this,n,k,f,e)},n,k,f,e)}g=c(k,f,e);g.style.position="absolute";return a.parentNode.replaceChild(g,a)}a.style.width=~~k+"px";a.style.height= -~~f+"px";var d=e[4][1];Render.update(a.firstChild,g[4][1],d);h(e[1],e[2],e[3][1],e[3][2],d[3],d[4],a.firstChild)}}function m(b,a,e,c,f){var n=0,d,j=(b[1]-c[1])/e;b=(b[2]-c[2])/e;0!==a&&(a*=-2*Math.PI,e=j*Math.cos(a)-b*Math.sin(a),b=j*Math.sin(a)+b*Math.cos(a),j=e);if(0===f.length)return!1;d=f[0];for(e=f.length-1;e--;){a=f[e];c=d[1];d=d[2];var h=a[1],m=a[2];if(d<m)var r=d,q=m;else r=m,q=d;if(c<h)var u=c,w=h;else u=h,w=c;r<b&&b<=q&&j<=w&&(j<=u||j<=(b-d)*(h-c)/(m-d)+c)&&++n;d=a}return 1===n%2}var j= -Elm.JavaScript;return{collage:function(b,a,e){if(0===e.length)return c(b,a,[]);for(var k=Array(e.length),d=e.length;d--;){var f=e[d];if("string"===typeof f[0]){var j=k,m=d,v=b,t=a,r=f[1],q=f[2],u=f[3][1],w=f[3][2],z=f[4][1],f=Render.render(z);h(r,q,u,w,z[3],z[4],f);r=Render.newElement("div");Render.addTo(r,f);r.style.width=~~v+"px";r.style.height=~~t+"px";r.style.overflow="hidden";j[m]=r}else k[d]=c(b,a,f)}return 1===e.length?k[0]:Render.flowWith(Render.goIn,function(b){return b},k)},updateCollage:function(b, -c,e){if(1===e.length)return a(b,c[0],e[0]);b=b.childNodes;for(var k=b.length,f=k;f--;)a(b[k-f-1],c[f],e[f])},insideForm:function(b){return function(a){var e=b[1],c=b[2];if(6>a.length){var f=a[3][1],d=a[3][2],j=0,h=a[2];switch(a[4][0]){case "FShape":for(var v=a[4][3][1],t=v.length;--t;)var r=v[t],j=Math.max(j,r[1]*r[1]+r[2]*r[2]);j*=h*h;break;case "FImage":v=h*a[4][1]/2;h=h*a[4][2]/2;j=v*v+h*h;break;case "FElement":v=h*a[4][1][3]/2,h=h*a[4][1][4]/2,j=v*v+h*h}a.push(function(b,a){var e=b-f,c=a-d;return e* -e+c*c<j+1})}if(!a[5](e,c))return!1;var q,u;switch(a[4][0]){case "FShape":return m(b,a[1],a[2],a[3],a[4][3][1]);case "FLine":return!1;case "FImage":q=a[4][1]/2;u=a[4][2]/2;break;case "FElement":q=a[4][1][3]/2,u=a[4][1][4]/2}return m(b,a[1],a[2],a[3],[[null,q,u],[null,-q,u],[null,-q,-u],[null,q,-u],[null,q,u]])}}}}(); -Elm.Graphics=function(){function d(b){return function(a){return["Position",b,a]}}function f(b){return function(a){return["EText",b,a]}}function b(b){return function(a){return["EFlow",b,s.castListToJSArray(a)]}}function c(b){return["Line",s.castListToJSArray(b)]}function h(b){return function(a){var e=s.castListToJSArray(b);0<e.length&&e.push(e[0]);return["Shape",e,a]}}function a(b){return function(a){return function(e){return function(c){return["Form",b,a,e,c]}}}}function m(b){return function(a){return function(e){return["FLine", -b,a,e]}}}function j(b){return function(a){return function(e){return["FShape",b,a,e]}}}function l(b,a,e,c,g,k){return["Element",Guid.guid(),b,a,e,c,g,k]}function g(b,a,e){return["Element",Guid.guid(),b,a,e,1,["Nothing"],["Nothing"]]}function e(b){return~~b[3]}function k(b){return~~b[4]}function x(b){return function(a){return function(e){return g(["EImage",s.castStringToJSString(e)],b,a)}}}function n(b){return function(a){return g(z,b,a)}}function p(b){return function(a){return function(e){var c=map(function(e){return["Tuple2", -b/2*Math.cos(2*(Math.PI/50)*e),a/2*Math.sin(2*(Math.PI/50)*e)]}),g=49,k=["Nil"];if(0<=g){do k=["Cons",g,k];while(0<g--)}return h(c(k))(e)}}}for(this.i in Elm.List)eval("var "+this.i+" = Elm.List[this.i];");var s=Elm.JavaScript,v=["DRight"],t=["DDown"],r=["DOut"],q=["Near"],u=["Mid"],w=["Far"],z=["EEmpty"],y=["Solid"],D=["Dotted"],F=["Dashed"],B=["Filled"],E=["Outlined"],A=d(q)(q),C=d(w)(q),G=d(q)(w),H=d(w)(w),I=d(q)(u),J=d(w)(u),q=d(u)(q),w=d(u)(w),u=d(u)(u);return{left:["DLeft"],right:v,down:t,up:["DUp"], -inward:["DIn"],outward:r,topLeft:A,topRight:C,bottomLeft:G,bottomRight:H,midLeft:I,midRight:J,midTop:q,midBottom:w,middle:u,middleAt:function(b){return function(a){return["PositionAt",b,a]}},topLeftAt:function(b){return function(a){return["PositionTL",b,a]}},topRightAt:function(b){return function(a){return["PositionTR",b,a]}},bottomLeftAt:function(b){return function(a){return["PositionBL",b,a]}},bottomRightAt:function(b){return function(a){return["PositionBR",b,a]}},absolute:function(b){return["Absolute", -b]},relative:function(b){return["Relative",b]},width:function(b){return function(a){var e=a[2];switch(e[0]){case "EImage":case "EVideo":return l(a[2],b,a[4]*b/a[3],a[5],a[6],a[7]);case "EText":return e=Value.getTextSize(b,a[4],e[2]),l(a[2],b,e[1],a[5],a[6],a[7])}return l(a[2],b,a[4],a[5],a[6],a[7])}},height:function(a){return function(b){switch(b[2][0]){case "EImage":case "EVideo":return l(b[2],b[3]*a/b[4],a,b[5],b[6],b[7])}return l(b[2],b[3],a,b[5],b[6],b[7])}},size:function(b){return function(a){return function(e){return l(e[2], -b,a,e[5],e[6],e[7])}}},opacity:function(b){return function(a){return l(a[2],a[3],a[4],b,a[6],a[7])}},color:function(b){return function(a){return l(a[2],a[3],a[4],a[5],["Just",b],a[7])}},link:function(b){return function(a){return l(a[2],a[3],a[4],a[5],a[6],["Just",s.castStringToJSString(b)])}},widthOf:e,heightOf:k,sizeOf:function(a){return["Tuple2",~~a[3],~~a[4]]},text:function(a){var b=Value.getTextSize(0,0,a);return g(f("left")(a),b[0],b[1])},asText:function(a){a=Elm.Text.monospace(Value.toText(Value.show(a))); -var b=Value.getTextSize(0,0,a);return g(f("left")(a),b[0],b[1])},plainText:function(a){a=Value.toText(a);var b=Value.getTextSize(0,0,a);return g(f("left")(a),b[0],b[1])},centeredText:function(a){var b=Value.getTextSize(0,0,a);return g(f("center")(a),b[0],b[1])},justifiedText:function(a){var b=Value.getTextSize(0,0,a);return g(f("justify")(a),b[0],b[1])},rightedText:function(a){var b=Value.getTextSize(0,0,a);return g(f("right")(a),b[0],b[1])},image:x,images:function(a){var b=Elm.Signal.constant(n(0)(0)); -a=Elm.Signal.lift(function(a){a=s.castStringToJSString(a);var e=new Image;e.onload=function(){Dispatcher.notify(b.id,x(this.width)(this.height)(a))};e.src=a})(a);return Elm.Signal.lift2(function(a){return function(){return a}})(b)(a)},video:function(a){return function(b){return function(e){return g(["EVideo",s.castStringToJSString(e)],a,b)}}},fittedImage:function(a){return function(b){return function(e){return g(["EFittedImage",s.castStringToJSString(e)],a,b)}}},flow:function(a){return function(c){var f; -f=map(e)(c);a:{switch(a[0]){case "DLeft":f=sum(f);break a;case "DRight":f=sum(f);break a}f=maximum(f)}var d;d=map(k)(c);a:{switch(a[0]){case "DDown":d=sum(d);break a;case "DUp":d=sum(d);break a}d=maximum(d)}return g(b(a)(c),f,d)}},above:function(a){return function(e){return g(b(t)(["Cons",a,["Cons",e,["Nil"]]]),Math.max(~~a[3],~~e[3]),~~a[4]+~~e[4])}},below:function(a){return function(e){return g(b(t)(["Cons",e,["Cons",a,["Nil"]]]),Math.max(~~a[3],~~e[3]),~~a[4]+~~e[4])}},beside:function(a){return function(e){return g(b(v)(["Cons", -a,["Cons",e,["Nil"]]]),~~a[3]+~~e[3],Math.max(~~a[4],~~e[4]))}},layers:function(a){return g(b(r)(a),maximum(map(e)(a)),maximum(map(k)(a)))},collage:function(a){return function(b){return function(e){return g(["ECollage",a,b,Value.groupForms(e)],a,b)}}},spacer:n,container:function(a){return function(b){return function(e){return function(c){return g(["EContainer",e,c],a,b)}}}},line:c,segment:function(a){return function(b){return c(["Cons",a,["Cons",b,["Nil"]]])}},polygon:h,rect:function(a){return function(b){return function(e){return h(["Cons", -["Tuple2",0-a/2,0-b/2],["Cons",["Tuple2",0-a/2,b/2],["Cons",["Tuple2",a/2,b/2],["Cons",["Tuple2",a/2,0-b/2],["Nil"]]]]])(e)}}},oval:p,circle:function(a){return p(2*a)(2*a)},ngon:function(a){return function(b){return function(e){var c=map(function(e){return["Tuple2",b*Math.cos(2*(Math.PI/a)*e),b*Math.sin(2*(Math.PI/a)*e)]}),g=a-1,k=["Nil"];if(0<=g){do k=["Cons",g,k];while(0<g--)}return h(c(k))(e)}}},solid:function(b){return function(e){return a(0)(1)(["Tuple2",0,0])(m(y)(b)(e))}},dotted:function(b){return function(e){return a(0)(1)(["Tuple2", -0,0])(m(D)(b)(e))}},dashed:function(b){return function(e){return a(0)(1)(["Tuple2",0,0])(m(F)(b)(e))}},customLine:function(b){return function(e){return function(c){return a(0)(1)(["Tuple2",0,0])(m(["Custom",s.castListToJSArray(b)])(e)(c))}}},filled:function(b){return function(e){return a(0)(1)(e[2])(j(B)(b)(e))}},outlined:function(b){return function(e){return a(0)(1)(e[2])(j(E)(b)(e))}},customOutline:function(b){return function(e){return function(c){return a(0)(1)(c[2])(j(["CustomOutline",s.castListToJSArray(b)])(e)(c))}}}, -textured:function(b){return function(e){return a(0)(1)(e[2])(j(["Textured",b])(null)(e))}},sprite:function(b){return function(e){return function(c){return function(g){return a(0)(1)(g)(["FImage",e,c,s.castStringToJSString(b)])}}}},toForm:function(b){return function(e){return a(0)(1)(b)(["FElement",e])}},rotate:function(b){return function(e){a:{switch(e[0]){case "Form":var c=e[2],g=e[3],k=e[4];e=a(b+e[1])(c)(g)(k);break a}throw"Non-exhaustive pattern match in case";}return e}},scale:function(b){return function(e){return a(e[1])(b* -e[2])(e[3])(e[4])}},move:function(b){return function(e){return function(c){var g;a:{switch(c[0]){case "Form":g=c[1];var k=c[2],f=c[3];c=c[4];switch(f[0]){case "Tuple2":var d=f[1],f=f[2];g=a(g)(k)(["Tuple2",b+d,e+f])(c);break a}}throw"Non-exhaustive pattern match in case";}return g}}},isWithin:Collage.insideForm}}(); -Elm.Text=function(){function d(a){return Value.toText(a)}var f=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},b=function(a,b){return function(c){return"<span style='"+a+":"+b+"'>"+c+"</span>"}},c=function(a){a=Elm.JavaScript.castStringToJSString(a);return b("font-family",a)},h=f("h1"),a=b("font-style","italic"),f=f("b"),m=b("text-decoration","underline"),j=b("text-decoration","overline"),l=b("text-decoration","line-through");return{fromString:d,toText:d,header:h, -height:function(a){return b("font-size",a+"em")},italic:a,bold:f,underline:m,overline:j,strikeThrough:l,monospace:c("monospace"),typeface:c,color:function(a){return b("color",Elm.Color.extract(a))},link:function(a){return function(b){return"<a href='"+d(a)+"'>"+b+"</a>"}}}}(); -var Render=function(){function d(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a}function f(a){return a}function b(a){a.style.styleFloat="left";a.style.cssFloat="left";return a}function c(a){a.style.position="absolute";return a}function h(a,b,c){for(var f=d("div"),j=c.length;j--;){var h=a(b(c[j]));f.appendChild(h)}return f}function a(a){switch(a[0]){case "Absolute":return a[1]+"px";case "Relative":return 100*a[1]+"%"}}function m(b,e){e.style.position="absolute";e.style.margin= -"auto";switch(b[0]){case "Position":"Far"!==b[1][0]&&(e.style.left=0);"Near"!==b[1][0]&&(e.style.right=0);"Far"!==b[2][0]&&(e.style.top=0);"Near"!==b[2][0]&&(e.style.bottom=0);break;case "PositionAt":e.style.top=a(b[2]);e.style.left=a(b[1]);var c="translate("+~~(-e.style.width.slice(0,-2)/2)+"px,"+~~(-e.style.height.slice(0,-2)/2)+"px)";e.style.transform=c;e.style.msTransform=c;e.style.MozTransform=c;e.style.webkitTransform=c;e.style.OTransform=c;break;default:c=b[0].slice(-2),e.style["T"===c[0]? -"top":"bottom"]=a(b[2]),e.style["L"===c[1]?"left":"right"]=a(b[1])}}function j(a){var e={};switch(a[2][0]){case "EText":var e=a[2][1],k=a[2][2],l=d("div");l.innerHTML=k;l.style.textAlign=e;e=l;break;case "EImage":e=a[2][1];k=d("img");k.src=e;k.name=e;k.style.display="block";e=k;break;case "EVideo":l=a[2][1];e=d("video");e.controls="controls";k=d("source");k.src=l;l=l.split(".");k.type="video/"+l[l.length-1];e.appendChild(k);e.style.display="block";break;case "EFittedImage":var n=a[3],p=a[4],e=a[2][1], -k=d("div");k.style.width=n+"px";k.style.height=p+"px";k.style.position="relative";k.style.overflow="hidden";var s=d("img");s.onload=function(){s.style.position="absolute";s.style.margin="auto";var a=n,b=p;n/p>this.width/this.height?b=Math.round(this.height*n/this.width):a=Math.round(this.width*p/this.height);s.style.width=a+"px";s.style.height=b+"px";s.style.left=(n-a)/2+"px";s.style.top=(p-b)/2+"px"};s.src=e;s.name=e;k.appendChild(s);e=k;break;case "EFlow":a:{e=a[2][2];switch(a[2][1][0]){case "DDown":e= -e.slice(0).reverse();case "DUp":e=h(f,j,e);break a;case "DRight":e=e.slice(0).reverse();case "DLeft":e=h(b,j,e);break a;case "DOut":e=e.slice(0).reverse();case "DIn":e=h(c,j,e);break a}e=void 0}break;case "ECollage":e=Collage.collage(a[2][1],a[2][2],a[2][3]);break;case "EEmpty":e=d("div");break;case "EContainer":k=a[2][1];e=j(a[2][2]);m(k,e);k=d("div");k.style.position="relative";k.style.overflow="hidden";k.appendChild(e);e=k;break;case "EHtml":e=a[2][1];"button"!==e.type&&(k=Value.getExcess(e),a[3]-= -k[0],a[4]-=k[1]);break;case "EExternalHtml":e=d("div"),e.appendChild(a[2][1])}e.id=a[1];e.style.width=~~a[3]+"px";e.style.height=~~a[4]+"px";1!==a[5]&&(e.style.opacity=a[5]);"Just"===a[6][0]&&(e.style.backgroundColor=Elm.Color.extract(a[6][1]));return"Just"===a[7][0]?(k=d("a"),k.href=a[7][1],k.appendChild(e),k):e}function l(a,e,k){"A"===a.tagName&&(a=a.firstChild);if(e[1]!==k[1]){if(e[2][0]!==k[2][0])return a.parentNode.replaceChild(j(k),a);var d=k[2],n=e[2];switch(d[0]){case "EText":d[1]!==n[1]&& -(a.style.textAlign=d[1]);d[2]!==n[2]&&(a.innerHTML=d[2]);break;case "EImage":d[1]!==n[1]&&(a.src=d[1]);break;case "EVideo":case "EFittedImage":if(!Value.eq(d,n)||k[3]!==e[3]||k[4]!==e[4])return a.parentNode.replaceChild(j(k),a);break;case "ECollage":if(d[1]!==n[1]||d[2]!==n[2]||d[3].length!==n[3].length)return a.parentNode.replaceChild(j(k),a);Collage.updateCollage(a,n[3],d[3]);break;case "EFlow":if(d[1]!==n[1])return a.parentNode.replaceChild(j(k),a);var h=d[2],s=a.childNodes;if(h.length!==s.length)return a.parentNode.replaceChild(j(k), -a);var n=n[2],v=function(a){return a};switch(d[1][0]){case "DDown":case "DUp":v=f;break;case "DRight":case "DLeft":v=b;break;case "DOut":case "DIn":v=c}for(d=s.length;d--;)l(s[d],n[d],h[d]),v(s[d]);break;case "EContainer":l(a.childNodes[0],n[2],d[2]);m(d[1],a.childNodes[0]);break;case "EHtml":k[1]!==e[1]&&(h=j(k),a.parentNode.replaceChild(h,a),a=h);"button"!==h.type&&(d=Value.getExcess(a),k[3]-=d[0],k[4]-=d[1]);break;case "EExternalHtml":k[1]!==e[1]&&a.parentNode.replaceChild(j(k),a)}k[3]!==e[3]&& -(a.style.width=~~k[3]+"px");k[4]!==e[4]&&(a.style.height=~~k[4]+"px");k[5]!==e[5]&&(a.style.opacity=k[5]);2===k[6].length&&(d=Elm.Color.extract(k[6][1]),d!==a.style.backgroundColor&&(a.style.backgroundColor=d));if(2===k[7].length&&(1===e[7].length||k[7][1]!==e[7][1]))a.parentNode.href=k[7][1];k[1]=e[1]}}return{render:j,update:l,addTo:function(a,b){a.appendChild(b)},newElement:d,flowWith:h,goIn:c}}(); -Elm.Signal=function(){function d(a){this.id=Guid.guid();this.value=a;this.kids=[];this.defaultNumberOfKids=0;this.recv=function(a,b,e){if(b=b===this.id)this.value=e;l(this,a,b);return b};Dispatcher.inputs.push(this)}function f(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.count=0;this.changed=!1;b.reverse();this.recalc=function(){for(var c=a,d=b.length;d--;)c=c(b[d].value);this.value=c};this.recalc();this.recv=function(a,e){this.count+=1;e&&(this.changed=!0);this.count==b.length&&(this.changed&& -this.recalc(),l(this,a,this.changed),this.changed=!1,this.count=0)};for(var c=b.length;c--;)b[c].kids.push(this)}function b(a,b,c,d){this.id=Guid.guid();this.value=c?b(d.value):b;this.kids=[];this.recv=function(b,c){c&&(this.value=a(d.value)(this.value));l(this,b,c)};d.kids.push(this)}function c(a,b,c){this.id=Guid.guid();this.value=a(c.value)?b:c.value;this.kids=[];this.recv=function(b,d){var f=d&&!a(c.value);f&&(this.value=c.value);l(this,b,f)};c.kids.push(this)}function h(a){this.id=Guid.guid(); -this.value=a.value;this.kids=[];this.recv=function(b,c){var d=c&&!Value.eq(this.value,a.value);d&&(this.value=a.value);l(this,b,d)};a.kids.push(this)}function a(a,b){this.id=Guid.guid();var c=(new window.Date).getTime();this.value=a?Value.Tuple(c,b.value):c;this.kids=[];this.recv=function(c,d){d&&(this.value=a?Value.Tuple(c,b.value):c);l(this,c,d)};b.kids.push(this)}function m(a,b){this.id=Guid.guid();this.value=b.value;this.kids=[];this.count=0;this.changed=!1;this.recv=function(c,d,f){f===a.id&& -(this.changed=d);this.count+=1;2==this.count&&(this.changed&&(this.value=b.value),l(this,c,this.changed),this.count=0,this.changed=!1)};a.kids.push(this);b.kids.push(this)}function j(a,b){this.id=Guid.guid();this.value=a.value;this.kids=[];this.next=null;this.count=0;this.changed=!1;this.recv=function(c,d,f){this.count+=1;d&&(this.changed=!0,f==b.id&&null===this.next&&(this.next=b.value),f==a.id&&(this.next=a.value));2==this.count&&(this.changed&&(this.value=this.next,this.next=null),l(this,c,this.changed), -this.changed=!1,this.count=0)};a.kids.push(this);b.kids.push(this)}var l=function(a,b,c){for(var d=a.kids,f=d.length;f--;)d[f].recv(b,c,a.id)},g=function(a){return function(b){return function(d){d=new f(function(a){return function(b){return[a,b]}},[a,d]);d=new c(function(a){return a[0]},[!0,b],d);return new f(function(a){return a[1]},[d])}}};return{constant:function(a){return new d(a)},lift:function(a){return function(b){return new f(a,[b])}},lift2:function(a){return function(b){return function(c){return new f(a, -[b,c])}}},lift3:function(a){return function(b){return function(c){return function(d){return new f(a,[b,c,d])}}}},lift4:function(a){return function(b){return function(c){return function(d){return function(j){return new f(a,[b,c,d,j])}}}}},lift5:function(a){return function(b){return function(c){return function(d){return function(j){return function(g){return new f(a,[b,c,d,j,g])}}}}}},lift6:function(a){return function(b){return function(c){return function(d){return function(j){return function(g){return function(h){return new f(a, -[b,c,d,j,g,h])}}}}}}},lift7:function(a){return function(b){return function(c){return function(d){return function(j){return function(g){return function(h){return function(l){return new f(a,[b,c,d,j,g,h,l])}}}}}}}},lift8:function(a){return function(b){return function(c){return function(d){return function(j){return function(g){return function(h){return function(l){return function(m){return new f(a,[b,c,d,j,g,h,l,m])}}}}}}}}},foldp:function(a){return function(c){return function(d){return new b(a,c,!1, -d)}}},foldp$:function(a){return function(c){return function(d){return new b(a,c,!0,d)}}},foldp1:function(a){return function(c){return new b(a,function(a){return a},!0,c)}},delay:function(a){return function(b){var c=new d(b.value),j=!0;b=new m(c,new f(function(a){return function(){return a}},[c,new f(function(b){j||setTimeout(function(){Dispatcher.notify(c.id,b)},a)},[b])]));j=!1;return b}},merge:function(a){return function(b){return new j(a,b)}},merges:function(a){return Elm.List.foldl1(function(a){return function(b){return new j(a, -b)}})(a)},mergeEither:function(a){return function(b){function c(a){return function(b){return[a,b]}}return new j(new f(c("Left"),[a]),new f(c("Right"),[b]))}},average:function(a){return function(b){for(var c=Array(a),d=a;d--;)c[d]=0;var d=0,j=!1,g=0;return new f(function(b){g+=b-c[d];c[d]=b;b=g/Math.max(1,j?a:d);++d==a&&(j=!0,d=0);return b},[b])}},count:function(a){return new b(function(){return function(a){return a+1}},0,!1,a)},countIf:function(a){return function(c){return new b(function(b){return function(c){return a(b)? -c+1:c}},0,!1,c)}},keepIf:function(a){return function(b){return function(d){return new c(function(b){return!a(b)},b,d)}}},dropIf:function(a){return function(b){return function(d){return new c(a,b,d)}}},keepWhen:function(a){return g(new f(function(a){return!a},[a]))},dropWhen:g,dropRepeats:function(a){return new h(a)},sampleOn:function(a){return function(b){return new m(a,b)}},timestamp:function(b){return new a(!0,b)},timeOf:function(b){return new a(!1,b)}}}(); -var Dispatcher=function(){function d(b){if(!b.hasOwnProperty("defaultNumberOfKids"))return!0;var a=b.kids.length;if(0==a)return!1;if(a>b.defaultNumberOfKids)return!0;for(var c=!1;a--;)c=c||d(b.kids[a]);return c}var f=null,b=[],c=null;return{initialize:function(){f=Elm.main();f.hasOwnProperty("recv")||(f=Elm.Signal.constant(f));c=f.value;for(var h=[],a=b.length;a--;)d(b[a])&&h.push(b[a]);b=h;document.getElementById("content").appendChild(Render.render(c));h=document.getElementById("widthChecker").offsetWidth; -h!==window.innerWidth&&Dispatcher.notify(Elm.Window.dimensions.id,Value.Tuple(h,window.innerHeight));f=Elm.Signal.lift(function(a){var b=document.getElementById("content");Render.update(b.firstChild,c,a);return c=a})(f)},notify:function(c,a){for(var d=(new window.Date).getTime(),f=!1,l=b.length;l--;)f=b[l].recv(d,c,a)||f;return f},inputs:b}}(); -Elm.HTTP=function(){function d(b){return function(c){return function(d){return function(e){return{"0":"Request",length:1,verb:a.castStringToJSString(b),url:a.castStringToJSString(c),data:null===d?null:a.castStringToJSString(d),headers:e}}}}}function f(a){return d("GET")(a)(null)(["Nil"])}function b(b,d){return function(f){if(""!==f.url){var e={value:["Waiting"]};b.push(e);var h=null;window.ActiveXObject&&(h=new ActiveXObject("Microsoft.XMLHTTP"));window.XMLHttpRequest&&(h=new XMLHttpRequest);h.onreadystatechange= -function(){4===h.readyState&&(e.value=200===h.status?["Success",m(h.responseText)]:["Failure",h.status,m(h.statusText)],setTimeout(function(){c(b,d)},0))};h.open(f.verb,f.url,!0);Elm.List.map(function(b){h.setRequestHeader(a.castStringToJSString(b[1]),a.castStringToJSString(b[2]))})(f.headers);h.send(f.data)}}}function c(a,b){0<a.length&&(Dispatcher.notify(b.id,a[0].value),"Waiting"!==a[0].value[0]&&(a.shift(),setTimeout(function(){c(a,b)},0)))}function h(a){var c=Elm.Signal.constant(["Waiting"]); -a=Elm.Signal.lift(b([],c))(a);return Elm.Signal.lift2(function(a){return function(){return a}})(c)(a)}var a=Elm.JavaScript,m=Elm.JavaScript.castJSStringToString;return{get:f,post:function(a){return function(b){return d("POST")(a)(b)(["Nil"])}},request:d,send:h,sendGet:function(a){return h(Elm.Signal.lift(f)(a))}}}(); -Elm.Input=function(){var d=Elm.JavaScript,f=Elm.JavaScript.castJSStringToString,b=function(a,b){a.placeholder=d.castStringToJSString(b);var c=Elm.Signal.constant(["Nil"]);Value.addListener(a,"keyup",function(){Dispatcher.notify(c.id,f(a.value));a.focus()});a.style.padding="1px";return Value.Tuple(Value.wrap(a),c)},c=function(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a},h=function(a){for(var b=c("select"),d=[];"Cons"===a[0];){var f=c("option"),h=Value.toText(a[1][1]); -f.value=h;f.innerHTML=h;b.appendChild(f);d.push(a[1][2]);a=a[2]}var e=Elm.Signal.constant(d[0]);Value.addListener(b,"change",function(){Dispatcher.notify(e.id,d[b.selectedIndex])});return Value.Tuple(Value.wrap(b),e)};return{textArea:function(a){return function(d){var f=c("textarea");f.rows=d;f.cols=a;return b(f,"")}},textField:function(a){var d=c("input");d.type="text";return b(d,a)},password:function(a){var d=c("input");d.type="password";return b(d,a)},checkbox:function(a){var b=c("input");b.type= -"checkbox";b.checked=a;var d=Elm.Signal.constant(a);Value.addListener(b,"change",function(){Dispatcher.notify(d.id,b.checked)});return Value.Tuple(Value.wrap(b),d)},dropDown:h,stringDropDown:function(a){return h(Elm.List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var b=c("input");b.type="button";b.value=d.castStringToJSString(a);var f=Elm.Signal.constant(!1);Value.addListener(b,"click",function(){Dispatcher.notify(f.id,!0);Dispatcher.notify(f.id,!1)});return Value.Tuple(Value.wrap(b), -f)}}}(); -Elm.Keyboard={Raw:function(){function d(b,f){return"Nil"===f[0]?f:f[1]===b?f[2]:["Cons",f[1],d(b,f[2])]}var f=Elm.Signal.constant(["Nil"]),b=Elm.Signal.constant(["Nothing"]);Value.addListener(document,"keydown",function(b){var d;a:{for(d=f.value;"Nil"!==d[0];){if(d[1]===b.keyCode){d=!0;break a}d=d[2]}d=!1}d||Dispatcher.notify(f.id,["Cons",b.keyCode,f.value])||this.removeEventListener("keydown",arguments.callee,!1)});Value.addListener(document,"keyup",function(b){var h=d(b.keyCode,f.value);Dispatcher.notify(f.id, -h)||this.removeEventListener("keyup",arguments.callee,!1)});Value.addListener(window,"blur",function(b){Dispatcher.notify(f.id,["Nil"])||this.removeEventListener("blur",arguments.callee,!1)});Value.addListener(document,"keypress",function(c){var d=Dispatcher.notify(b.id,["Just",c.charCode||c.keyCode]);Dispatcher.notify(b.id,["Nothing"]);d||this.removeEventListener("keypress",arguments.callee,!1)});return{keysDown:f,charPressed:b}}()}; -(function(){function d(b){b=Elm.Signal.lift(b)(Elm.Keyboard.Raw.keysDown);Elm.Keyboard.Raw.keysDown.defaultNumberOfKids+=1;b.defaultNumberOfKids=0;return b}function f(b,f,a,m){return d(function(d){for(var l=0,g=0;"Cons"==d[0];){switch(d[1]){case b:--l;break;case f:++l;break;case a:++g;break;case m:--g}d=d[2]}return{_:[!0],x:[l],y:[g]}})}function b(b){return d(function(d){for(;"Cons"==d[0];){if(b==d[1])return!0;d=d[2]}return!1})}Elm.Keyboard.arrows=f(37,39,38,40);Elm.Keyboard.wasd=f(65,68,87,83);Elm.Keyboard.shift= -b(16);Elm.Keyboard.ctrl=b(17);Elm.Keyboard.space=b(32)})(); -Elm.Mouse=function(){function d(a){var b=0,c=0;a||(a=window.event);if(a.pageX||a.pageY)b=a.pageX,c=a.pageY;else if(a.clientX||a.clientY)b=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,c=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return Value.Tuple(b,c)}var f=Elm.Signal.constant(Value.Tuple(0,0));f.defaultNumberOfKids=2;var b=Elm.Signal.lift(function(a){return a[1]})(f);b.defaultNumberOfKids=0;var c=Elm.Signal.lift(function(a){return a[2]})(f);c.defaultNumberOfKids= -0;var h=Elm.Signal.constant(!1),a=Elm.Signal.constant(!1),m=Elm.Signal.constant(Value.Tuple());Value.addListener(document,"click",function(b){var c=Dispatcher.notify(a.id,!0),d=Dispatcher.notify(m.id,Value.Tuple());Dispatcher.notify(a.id,!1);!c&&!d&&this.removeEventListener("click",arguments.callee,!1)});Value.addListener(document,"mousedown",function(a){Dispatcher.notify(h.id,!0)||this.removeEventListener("mousedown",arguments.callee,!1)});Value.addListener(document,"mouseup",function(a){Dispatcher.notify(h.id, -!1)||this.removeEventListener("mouseup",arguments.callee,!1)});Value.addListener(document,"mousemove",function(a){Dispatcher.notify(f.id,d(a))||this.removeEventListener("mousemove",arguments.callee,!1)});return{position:f,x:b,y:c,isClicked:a,isDown:h,clicks:m,isClickedOn:function(a){a=Render.render(a);var b=Elm.Signal.constant(!1);Value.addListener(a,"click",function(){Dispatcher.notify(b.id,!0);Dispatcher.notify(b.id,!1)});return Value.Tuple(Value.wrap(a),b)}}}(); -Elm.Random=function(){return{inRange:function(d){return function(f){return Elm.Signal.constant(Math.floor(Math.random()*(f-d+1))+d)}},randomize:function(d){return function(f){return function(b){return Elm.Signal.lift(function(){return Math.floor(Math.random()*(f-d+1))+d})(b)}}}}}(); -Elm.Time=function(){function d(){return(new window.Date).getTime()}function f(b){return function(c){var f=1E3/b,a=d(),m=a,j=0,l=!0,g=Elm.Signal.constant(j),e=0;return Elm.Signal.lift2(function(b){return function(c){if(b){var n=!l&&b;e=setTimeout(function(){m=d();j=n?0:m-a;a=m;Dispatcher.notify(g.id,j)},f)}else l&&clearTimeout(e);l=b;return c}})(c)(g)}}Elm.Signal.constant(!0);return{fpsWhen:f,fps:function(b){return f(b)(Elm.Signal.constant(!0))},every:function(b){var c=Elm.Signal.constant(d());setInterval(function(){Dispatcher.notify(c.id, -d())},b);return c},delay:Elm.Signal.delay,since:function(b){return function(c){var d=Elm.Signal.count(Elm.Signal.delay(b)(c));return Elm.Signal.lift2(function(a){return function(b){return!Value.eq(a,b)}})(Elm.Signal.count(c))(d)}},after:function(b){b*=1E3;var c=Elm.Signal.constant(!1);setTimeout(function(){Dispatcher.notify(c.id,!0)},b);return c},before:function(b){b*=1E3;var c=Elm.Signal.constant(!0);setTimeout(function(){Dispatcher.notify(c.id,!1)},b);return c},hour:36E5,minute:6E4,second:1E3,ms:1, -inHours:function(b){return b/36E5},inMinutes:function(b){return b/6E4},inSeconds:function(b){return b/1E3},inMss:function(b){return b},toDate:function(b){return new window.Date(b)},read:function(b){b=window.Date.parse(b);return isNaN(b)?["Nothing"]:["Just",b]}}}(); -Elm.Window=function(){var d=Elm.Signal.constant(Value.Tuple(window.innerWidth,window.innerHeight));d.defaultNumberOfKids=2;var f=Elm.Signal.lift(function(b){return b[1]})(d);f.defaultNumberOfKids=0;var b=Elm.Signal.lift(function(b){return b[2]})(d);b.defaultNumberOfKids=0;Value.addListener(window,"resize",function(b){var f=document.getElementById("widthChecker").offsetWidth;Dispatcher.notify(d.id,Value.Tuple(f,window.innerHeight))||this.removeEventListener("resize",arguments.callee,!1)});return{dimensions:d, -width:f,height:b}}(); -Elm.Date=function(){var d="Sun Mon Tue Wed Thu Fri Sat".split(" "),f="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");return{read:function(b){b=new window.Date(Elm.JavaScript.castStringToJSString(b));return isNaN(b.getTime())?["Nothing"]:["Just",b]},year:function(b){return b.getFullYear()},month:function(b){return[f[b.getMonth()]]},day:function(b){return b.getDate()},hour:function(b){return b.getHours()},minute:function(b){return b.getMinutes()},second:function(b){return b.getSeconds()},dayOfWeek:function(b){return[d[b.getDay()]]}, -toTime:function(b){return b.getTime()},Mon:["Mon"],Tue:["Tue"],Wed:["Wed"],Thu:["Thu"],Fri:["Fri"],Sat:["Sat"],Sun:["Sun"],Jan:["Jan"],Feb:["Feb"],Mar:["Mar"],Apr:["Apr"],May:["May"],Jun:["Jun"],Jul:["Jul"],Aug:["Aug"],Sep:["Sep"],Oct:["Oct"],Nov:["Nov"],Dec:["Dec"]}}();Value.addListener(document,"elm_log",function(d){console.log(d.value)});Value.addListener(document,"elm_title",function(d){document.title=d.value}); -Value.addListener(document,"elm_redirect",function(d){0<d.value.length&&(window.location=d.value)});Value.addListener(document,"elm_viewport",function(d){var f=document.getElementById("elm_viewport");f||(f=document.createElement("meta"),f.id="elm_viewport",f.name="viewport",document.head.appendChild(f));f.content=d.value;Dispatcher.notify(Elm.Window.dimensions.id,Value.Tuple(window.innerWidth,window.innerHeight))}); -Elm.Prelude=function(){function d(b){return function(c){if(b instanceof Array&&c instanceof Array){var f=b.length;if(f==c.length){for(var a=1;a<f;++a){var m=d(b[a])(c[a]);if("EQ"!==m[0])return m}return["EQ"]}return[1==c.length?"GT":"LT"]}return[b===c?"EQ":b<c?"LT":"GT"]}}var f=function(b){return function(c){var d=b%c,d=0==b?0:0<c?0<=b?d:d+c:-f(-b)(-c);return d==c?0:d}};return{eq:Value.eq,id:function(b){return b},not:function(b){return!b},xor:function(b){return function(c){return b!=c}},fst:function(b){return b[1]}, -snd:function(b){return b[2]},rem:function(b){return function(c){return b%c}},div:function(b){return function(c){return~~(b/c)}},otherwise:!0,compare:d,toFloat:function(b){return b},round:function(b){return Math.round(b)},floor:function(b){return Math.floor(b)},ceiling:function(b){return Math.ceil(b)},truncate:function(b){return~~b},readInt:function(b){b=Elm.JavaScript.castStringToJSString(b);var c=b.length;if(0===c)return["Nothing"];var d=0;if("-"==b[0]){if(1===c)return["Nothing"];d=1}for(;d<c;++d)if(!Elm.Char.isDigit(b[d]))return["Nothing"]; -return["Just",parseInt(b)]},readFloat:function(b){b=Elm.JavaScript.castStringToJSString(b);var c=b.length;if(0===c)return["Nothing"];var d=0;if("-"==b[0]){if(1===c)return["Nothing"];d=1}for(var a=0;d<c;++d)if(!Elm.Char.isDigit(b[d])){if("."===b[d]&&(a+=1,1>=a))continue;return["Nothing"]}return["Just",parseFloat(b)]},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,e:Math.E,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,atan2:function(b){return function(c){return Math.atan2(b, -c)}},mod:f,min:function(b){return function(c){return Math.min(b,c)}},max:function(b){return function(c){return Math.max(b,c)}},flip:function(b){return function(c){return function(d){return b(d)(c)}}},clamp:function(b){return function(c){return function(d){return Math.min(c,Math.max(b,d))}}},curry:function(b){return function(c){return function(d){return b(["Tuple2",c,d])}}},uncurry:function(b){return function(c){if("Tuple2"!==c[0])throw"Function was uncurry'd but was not given a pair.";return b(c[1])(c[2])}}, -logBase:function(b){return function(c){return Math.log(c)/Math.log(b)}},Just:Elm.Maybe.Just,Nothing:Elm.Maybe.Nothing,maybe:Elm.Maybe.maybe,map:Elm.List.map,zip:Elm.List.zip,zipWith:Elm.List.zipWith,filter:Elm.List.filter,head:Elm.List.head,tail:Elm.List.tail,last:Elm.List.last,length:Elm.List.length,reverse:Elm.List.reverse,foldr:Elm.List.foldr,foldr1:Elm.List.foldr1,foldl:Elm.List.foldl,foldl1:Elm.List.foldl1,and:Elm.List.and,or:Elm.List.or,all:Elm.List.all,any:Elm.List.any,sum:Elm.List.sum,product:Elm.List.product, -concat:Elm.List.concat,concatMap:Elm.List.concatMap,maximum:Elm.List.maximum,minimum:Elm.List.minimum,scanl:Elm.List.scanl,scanl1:Elm.List.scanl1,take:Elm.List.take,drop:Elm.List.drop,zip:Elm.List.zip,unzip:Elm.List.unzip,lift:Elm.Signal.lift,lift2:Elm.Signal.lift2,lift3:Elm.Signal.lift3,lift4:Elm.Signal.lift4,lift5:Elm.Signal.lift5,lift6:Elm.Signal.lift6,lift7:Elm.Signal.lift7,lift8:Elm.Signal.lift8,foldp:Elm.Signal.foldp,foldp1:Elm.Signal.foldp1,foldp$:Elm.Signal.foldp$,constant:Elm.Signal.constant, -merge:Elm.Signal.merge,merges:Elm.Signal.merges,mergeEither:Elm.Signal.mergeEither,count:Elm.Signal.count,countIf:Elm.Signal.countIf,average:Elm.Signal.average,keepIf:Elm.Signal.keepIf,dropIf:Elm.Signal.dropIf,keepWhen:Elm.Signal.keepWhen,dropWhen:Elm.Signal.dropWhen,dropRepeats:Elm.Signal.dropRepeats,sampleOn:Elm.Signal.sampleOn,timestamp:Elm.Signal.timestamp,timeOf:Elm.Signal.timeOf}}(); -(function(){var d=function(d){for(var b in d)Elm.Prelude[b]=d[b]};d(Elm.Color);d(Elm.Text);d(Elm.Graphics);d(Elm.Time);show=Value.show})(); -Elm.Touch=function(){function d(b){b=j.remove(b.identifier);Date.now()-b.t<h&&(a=!0,m={_:[!0],x:[b.x],y:[b.y]})}function f(a,b){function d(f){for(var g=f.changedTouches.length;g--;)b(f.changedTouches[g]);for(var h=Array(f.touches.length),g=f.touches.length;g--;){var l=h,m=g,r=f.touches[g],q=j.lookup(r.identifier);l[m]={_:[!0],id:[r.identifier],x:[r.pageX],y:[r.pageY],x0:[q.x],y0:[q.y],t0:[q.t]}}if(!Dispatcher.notify(c.id,h))return document.removeEventListener(a,d);f.preventDefault()}Value.addListener(document, -a,d)}function b(a){a=Elm.Signal.lift(a)(c);c.defaultNumberOfKids+=1;a.defaultNumberOfKids=0;return a}var c=Elm.Signal.constant([]),h=500,a=!1,m={_:[!0],x:[0],y:[0]},j=new function(){this.keys=[];this.values=[];this.insert=function(a,b){this.keys.push(a);this.values.push(b)};this.lookup=function(a){a=this.keys.indexOf(a);return 0<=a?this.values[a]:{x:0,y:0,t:0}};this.remove=function(a){a=this.keys.indexOf(a);if(!(0>a)){var b=this.values[a];this.keys.splice(a,1);this.values.splice(a,1);return b}}}; -f("touchstart",function(a){j.insert(a.identifier,{x:a.pageX,y:a.pageY,t:Date.now()})});f("touchmove",function(){});f("touchend",d);f("touchcancel",d);f("touchleave",d);var l=b(function(a){return Elm.JavaScript.castJSArrayToList(a)}),g=b(function(){return m});g.defaultNumberOfKids=1;g=Elm.Signal.keepIf(function(){var b=a;a=!1;return b})({_:[!0],x:[0],y:[0]})(g);g.defaultNumberOfKids=0;return{touches:l,taps:g}}(); -Elm.Dict=function(){function d(a){return function(b){return function(c){return function(d){return function(e){return["RBNode",a,b,c,d,e]}}}}}function f(a){a:{switch(a[0]){case "RBEmpty":throw"(min RBEmpty) is not defined";case "RBNode":switch(a[4][0]){case "RBEmpty":a=["Tuple2",a[2],a[3]];break a}a=f(a[4]);break a}throw"Non-exhaustive pattern match in case";}return a}function b(a){return function(c){var d;a:{switch(c[0]){case "RBEmpty":d=w;break a;case "RBNode":d=function(){switch(q(a)(c[2])[0]){case "EQ":return z(c[3]); -case "GT":return b(a)(c[5]);case "LT":return b(a)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case";}return d}}function c(a){return function(b){return function(d){var e;a:{switch(d[0]){case "RBEmpty":e=a;break a;case "RBNode":e=function(){switch(q(b)(d[2])[0]){case "EQ":return d[3];case "GT":return c(a)(b)(d[5]);case "LT":return c(a)(b)(d[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case"; -}return e}}}function h(a){return function(c){return F(b(a)(c))}}function a(a){a:{switch(a[0]){case "RBNode":switch(a[5][0]){case "RBNode":a=d(a[1])(a[5][2])(a[5][3])(d(B)(a[2])(a[3])(a[4])(a[5][4]))(a[5][5]);break a}}throw"rotateLeft of a node without enough children";}return a}function m(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":a=d(a[1])(a[4][2])(a[4][3])(a[4][4])(d(B)(a[2])(a[3])(a[4][5])(a[5]));break a}}throw"rotateRight of a node without enough children";}return a}function j(a){a:{switch(a[0]){case "Black":a= -B;break a;case "Red":a=E;break a}throw"Non-exhaustive pattern match in case";}return a}function l(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[5][0]){case "RBNode":a=d(j(a[1]))(a[2])(a[3])(d(j(a[4][1]))(a[4][2])(a[4][3])(a[4][4])(a[4][5]))(d(j(a[5][1]))(a[5][2])(a[5][3])(a[5][4])(a[5][5]));break a}}}throw"color_flip called on a RBEmpty or RBNode with a RBEmpty child";}return a}function g(b){a:switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":b= -a(b);break a}}}a:switch(b[0]){case "RBNode":switch(b[4][0]){case "RBNode":switch(b[4][1][0]){case "Red":switch(b[4][4][0]){case "RBNode":switch(b[4][4][1][0]){case "Red":b=m(b);break a}}}}}a:switch(b[0]){case "RBNode":switch(b[4][0]){case "RBNode":switch(b[4][1][0]){case "Red":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":b=l(b);break a}}}}}return b}function e(a){a:switch(a[0]){case "RBNode":switch(a[1][0]){case "Red":a=d(E)(a[2])(a[3])(a[4])(a[5]);break a}}return a}function k(a){return function(b){return function(c){var f= -function(c){var e;a:{switch(c[0]){case "RBEmpty":e=d(B)(a)(b)(A)(A);break a;case "RBNode":e=function(){switch(q(a)(c[2])[0]){case "EQ":return d(c[1])(c[2])(b)(c[4])(c[5]);case "GT":return d(c[1])(c[2])(c[3])(c[4])(f(c[5]));case "LT":return d(c[1])(c[2])(c[3])(f(c[4]))(c[5])}throw"Non-exhaustive pattern match in case";}();e=g(e);break a}throw"Non-exhaustive pattern match in case";}return e};return e(f(c))}}}function x(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":a= -!0;break a}}}a=!1}return a}function n(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][4][0]){case "RBNode":switch(a[4][4][1][0]){case "Red":a=!0;break a}}}}a=!1}return a}function p(b){if(y(x(b))&&y(n(b))){b=l(b);a:switch(b[0]){case "RBNode":b:switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":b=l(a(d(b[1])(b[2])(b[3])(b[4])(m(b[5]))));break b}}}break a}}return b}function s(a){return function(b){var c=function(b){a:{switch(b[0]){case "RBEmpty":b= -A;break a;case "RBNode":if("LT"===q(a)(b[2])[0])b:{b=p(b);switch(b[0]){case "RBEmpty":throw"delLT on RBEmpty";case "RBNode":b=g(d(b[1])(b[2])(b[3])(c(b[4]))(b[5]));break b}break}else{var h=x(b)?m(b):b,j;b:{switch(h[0]){case "RBNode":switch(h[5][0]){case "RBEmpty":j=D(a,h[2]);break b}}j=!1}if(j)b=h[4];else{h=y;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":j=!0;break b}}}j=!1}if(h=h(j)){h=y;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":j= -!0;break b}}}}j=!1}h=h(j)}h&&(b=l(b),b=n(b)?l(m(b)):b);b:{switch(b[0]){case "RBNode":h=D(a,b[2]);break b}h=!1}if(h)b:{switch(b[0]){case "RBEmpty":throw"delEQ called on a RBEmpty";case "RBNode":j=f(b[5]);c:{switch(j[0]){case "Tuple2":h=j[1];break c}break}c:{switch(j[0]){case "Tuple2":j=j[2];break c}break}var h=d(b[1])(h)(j)(b[4]),k=function(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBEmpty":a=A;break a}}b:{a=p(a);switch(a[0]){case "RBEmpty":a=A;break b;case "RBNode":a=g(d(a[1])(a[2])(a[3])(k(a[4]))(a[5])); -break b}throw"Non-exhaustive pattern match in case";}}return a};b=e(k(b[5]));b=g(h(b));break b}break}else b:{switch(b[0]){case "RBEmpty":throw"delGT called on a RBEmpty";case "RBNode":b=g(d(b[1])(b[2])(b[3])(b[4])(c(b[5])));break b}break}}}break a}throw"Non-exhaustive pattern match in case";}return b};return h(a)(b)?e(c(b)):b}}function v(a){return function(b){a:{switch(b[0]){case "RBEmpty":b=A;break a;case "RBNode":b=d(b[1])(b[2])(a(b[3]))(v(a)(b[4]))(v(a)(b[5]));break a}throw"Non-exhaustive pattern match in case"; -}return b}}function t(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=t(a)(a(c[2])(c[3])(t(a)(b)(c[4])))(c[5]);break a}throw"Non-exhaustive pattern match in case";}return c}}}function r(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=r(a)(a(c[2])(c[3])(r(a)(b)(c[5])))(c[4]);break a}throw"Non-exhaustive pattern match in case";}return c}}}var q=Elm.Prelude.compare,u=Elm.Prelude.uncurry,w=Elm.Prelude.Nothing, -z=Elm.Prelude.Just,y=Elm.Prelude.not,D=Elm.Prelude.eq,F=Elm.Maybe.isJust,B=["Red"],E=["Black"],A=["RBEmpty"],C=A;return{$op:{},empty:C,lookup:b,findWithDefault:c,member:h,insert:k,singleton:function(a){return function(b){return k(a)(b)(A)}},remove:s,map:v,foldl:t,foldr:r,union:function(a){return function(b){return t(k)(b)(a)}},intersect:function(a){return function(b){return t(function(a){return function(c){return function(d){return h(a)(b)?k(a)(c)(d):d}}})(C)(a)}},diff:function(a){return function(b){return t(function(a){return function(){return function(b){return s(a)(b)}}})(a)(b)}}, -keys:function(a){return r(function(a){return function(){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},values:function(a){return r(function(){return function(a){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},toList:function(a){return r(function(a){return function(b){return function(c){return["Cons",["Tuple2",a,b],c]}}})(["Nil"])(a)},fromList:function(a){return Elm.List.foldl(u(k))(C)(a)}}}(); -Elm.Set=function(){var d=Elm.Dict.empty,f=Elm.Dict.remove,b=Elm.Dict.member,c=Elm.Dict.union,h=Elm.Dict.intersect,a=Elm.Dict.diff,m=Elm.Dict.keys,j=Elm.List.foldl(function(a){return function(b){return Elm.Dict.insert(a)(["Tuple0"])(b)}})(d);return{empty:d,singleton:function(a){return Elm.Dict.singleton(a)(["Tuple0"])},insert:function(a){return Elm.Dict.insert(a)(["Tuple0"])},remove:f,member:b,union:c,intersect:h,diff:a,toList:m,fromList:j,foldl:function(a){return Elm.Dict.foldl(function(b){return function(){return function(c){return a(b)(c)}}})}, -foldr:function(a){return Elm.Dict.foldr(function(b){return function(){return function(c){return a(b)(c)}}})},map:function(a){return function(b){b=m(b);return j(Elm.List.map(a)(b))}}}}(); -(function(){try{var d={};for(this.i in Elm)eval("var "+this.i+"=Elm[this.i];");if(Elm.Automaton)throw"Module name collision, 'Automaton' is already defined.";Elm.Automaton=function(){function b(a){return["Automaton",a]}function c(a){return b(function(b){var d=unzip(map(function(a){a:{switch(a[0]){case "Automaton":a=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return a})(a)),e;a:{switch(d[0]){case "Tuple2":e=d[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(d[0]){case "Tuple2":d= -d[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",e,c(d)]})}function f(a){return b(function(b){return["Tuple2",a(b),f(a)]})}function a(c){return function(d){return b(function(b){b=d(b)(c);return["Tuple2",b,a(b)(d)]})}}function m(a){return function(c){return b(function(b){var d=c(b)(a);a:{switch(d[0]){case "Tuple2":b=d[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(d[0]){case "Tuple2":d=d[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2", -b,m(d)(c)]})}}function j(a){return function(b){a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":b=["Tuple2",a[1]-b[1],a[2]-b[2]];break b}break}break a}throw"Non-exhaustive pattern match in case";}return b}}function l(a){return function(b){var c;a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":var d=function(a){return["Tuple2",b[2],["Tuple2",a,b[2]]]};c=function(){switch(b[1][0]){case "DragFrom":var c;a[1]?c=["Tuple2",uncurry(move)(j(a[2])(b[1][1]))(b[2]),["Tuple2",["DragFrom", -b[1][1]],b[2]]]:(c=uncurry(move)(j(a[2])(b[1][1]))(b[2]),c=["Tuple2",c,["Tuple2",k,c]]);return c;case "Ignore":return d(a[1]?x:k);case "Listen":return d(not(a[1])?k:isWithin(a[2])(b[2])?["DragFrom",a[2]]:x)}throw"Non-exhaustive pattern match in case";}();break b}break}break a}throw"Non-exhaustive pattern match in case";}return c}}try{if(!(Elm.Prelude instanceof Object))throw"module not found";}catch(g){throw"Module 'Prelude' is missing. Compile with --make flag or load missing module in a separate JavaScript file."; -}var e={};for(this.i in Elm.Prelude)e[this.i]||eval("var "+this.i+" = Elm.Prelude[this.i];");var k=["Listen"],x=["Ignore"];d[">>>"]=function(a){return function(c){var e;a:{switch(a[0]){case "Automaton":e=a[1];break a}throw"Non-exhaustive pattern match in case";}var f;a:{switch(c[0]){case "Automaton":f=c[1];break a}throw"Non-exhaustive pattern match in case";}return b(function(a){a=e(a);var b;a:{switch(a[0]){case "Tuple2":b=a[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(a[0]){case "Tuple2":a= -a[2];break a}throw"Non-exhaustive pattern match in case";}var c=f(b);a:{switch(c[0]){case "Tuple2":b=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c=c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",b,d[">>>"](a)(c)]})}};d["<<<"]=function(a){return function(b){return d[">>>"](b)(a)}};d["^>>"]=function(a){return function(b){return d[">>>"](f(a))(b)}};d[">>^"]=function(a){return function(b){return d[">>>"](a)(f(b))}};d["^<<"]=function(a){return function(b){return d[">>>"](b)(f(a))}}; -d["<<^"]=function(a){return function(b){return d[">>>"](f(b))(a)}};e=a(0)(function(){return function(a){return 1+a}});return{$op:{">>>":d[">>>"],"<<<":d["<<<"],"^>>":d["^>>"],">>^":d[">>^"],"^<<":d["^<<"],"<<^":d["<<^"]},run:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=lift(fst)(foldp$(function(a){return function(b){a:{switch(b[0]){case "Tuple2":switch(b[2][0]){case "Automaton":b=b[2][1](a);break a}}throw"Non-exhaustive pattern match in case";}return b}})(a[1])(b));break a}throw"Non-exhaustive pattern match in case"; -}return b}},step:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return b}},combine:c,pure:f,init:a,init$:m,count:e,draggable:function(a){return m(["Tuple2",k,a])(l)}}}();Elm.main=function(){return Elm.Automaton.main}}catch(f){Elm.main=function(){document.body.innerHTML=Elm.Text.monospace('<br/><h2>Your browser may not be supported. Are you using a modern browser?</h2><br/><span style="color:grey">Runtime Error in Automaton module:<br/>'+ -f+"</span>");throw f;}}})(); \ No newline at end of file diff --git a/elm/elm-runtime-0.7.2.js b/elm/elm-runtime-0.7.2.js deleted file mode 100644 index 65ce33f..0000000 --- a/elm/elm-runtime-0.7.2.js +++ /dev/null @@ -1,4522 +0,0 @@ - -Elm = {}; - -var Guid = function() { - var counter = 0; - var guid = function() { counter += 1; return counter; }; - return {guid : guid}; -}(); -Elm.JavaScript = function() { - function castJSBoolToBool(b) { return b; } - function castBoolToJSBool(b) { return b; } - - function castJSNumberToFloat(n) { return n; } - function castFloatToJSNumber(n) { return n; } - - function castJSNumberToInt(n) { return ~~n; } - function castIntToJSNumber(n) { return n; } - - function castJSElementToElement(w) { - return function(h) { - return function(node) { - return ["Element",Guid.guid(), - ["EExternalHtml",node], - w,h,1,["Nothing"],["Nothing"]]; - } - } - } - function castElementToJSElement(elem) { return Render.render(elem); } - - function castJSArrayToList(arr) { - var list = ["Nil"]; - for (var i = arr.length; i--; ) { - list = [ "Cons", arr[i], list ]; - } - return list; - } - function castListToJSArray(list) { - var a = []; - while (list[0] === "Cons") { - a.push(list[1]); - list = list[2]; - } - return a; - } - - var castJSStringToString = castJSArrayToList; - function castStringToJSString(str) { - if (typeof str === "string") return str; - return castListToJSArray(str).join(''); - } - - function fromTuple(t) { return t.slice(1); } - function toTuple(a) { return ["Tuple" + a.length].concat(a); } - - return {castJSBoolToBool:castJSBoolToBool, - castBoolToJSBool:castBoolToJSBool, - castJSNumberToFloat:castJSNumberToFloat, - castFloatToJSNumber:castFloatToJSNumber, - castJSNumberToInt:castJSNumberToInt, - castIntToJSNumber:castIntToJSNumber, - Experimental : {castJSElementToElement:castJSElementToElement, - castElementToJSElement:castElementToJSElement}, - castJSArrayToList:castJSArrayToList, - castListToJSArray:castListToJSArray, - castJSStringToString:castJSStringToString, - castStringToJSString:castStringToJSString, - castTupleToJSTuple2:fromTuple, - castTupleToJSTuple3:fromTuple, - castTupleToJSTuple4:fromTuple, - castTupleToJSTuple5:fromTuple, - castJSTupleToTuple2:toTuple, - castJSTupleToTuple3:toTuple, - castJSTupleToTuple4:toTuple, - castJSTupleToTuple5:toTuple - }; -}(); - -var JSjson = window.JSON; -Elm.JSON = function() { - var JS = Elm.JavaScript; - var empty = ['JSON',{}]; - function singleton(k) { return function(v) { - var obj = {}; - obj[JS.castStringToJSString(k)] = v; - return ['JSON', obj ]; - }; - } - function insert(k) { return function(v) { return function(inObj) { - var obj = inObj[1]; - var outObj = {}; - for (var i in obj) { - outObj[i] = obj[i]; - } - outObj[JS.castStringToJSString(k)] = v; - return ['JSON', outObj ]; - }; - }; - } - - function lookup(key) { return function(obj) { - var k = JS.castStringToJSString(key); - return (k in obj[1]) ? ["Just", obj[1][k]] : ["Nothing"] ; - }; - } - function find(tipe,base) { return function (key) { return function(obj) { - var k = JS.castStringToJSString(key); - if (k in obj[1]) { - var v = obj[1][k]; - if (v[0] === tipe) { return v[1]; } - } - return base; - }; - } - } - function lookupWithDefault(base) { return function(key) { return function(obj) { - var k = JS.castStringToJSString(key); - return (k in obj[1]) ? obj[1][k] : base ; - }; - }; - } - - function remove(k) { return function(inObj) { - var obj = inObj[1]; - var outObj = {}; - for (var i in obj) { - outObj[i] = obj[i]; - } - delete outObj[JS.castStringToJSString(k)]; - return ['JSON', outObj]; - }; - } - - function JsonString(v) { return [ "JsonString", v ]; } - function JsonNumber(v) { return [ "JsonNumber", v ]; } - function JsonBool(v) { return [ "JsonBool", v ]; } - var JsonNull = [ "JsonNull" ]; - function JsonArray(v) { return [ "JsonArray", v ]; } - function JsonObject(v) { return [ "JsonObject", v ]; } - - function toList(json) { - var obj = json[1]; - var arr = []; - for (var i in obj) { - arr.push(Value.Tuple(JS.castJSStringToString(i), obj[i])); - } - return JS.castJSArrayToList(arr); - } - function fromList(list) { - var arr = JS.castListToJSArray(list); - var obj = {}; - for (var i = arr.length; i--; ) { - obj[JS.castStringToJSString(arr[i][1])] = arr[i][2]; - } - return [ "JSON", obj ]; - } - - function toPrettyJSString(sep) { return function (obj) { - function fromValue(v) { - switch (v[0]) { - case 'JsonNull' : return null; - case 'JsonString' : return JS.castStringToJSString(v[1]); - case 'JsonObject' : - var o = {}; - var from = v[1][1]; - for (var i in from) { - o[i] = fromValue(from[i]); - } - return o; - case 'JsonArray' : - var a = JS.castListToJSArray(v[1]); - for (var i = a.length; i--; ) { - a[i] = fromValue(a[i]); - } - return a; - default : - return v[1]; - } - } - return JSjson.stringify(fromValue([ 'JsonObject', obj ]), null, JS.castStringToJSString(sep)); - }; - } - function fromJSString(str) { - var obj; - try { - obj = JSjson.parse(str); - } catch (e) { - return Elm.Maybe.Nothing; - } - function toValue(v) { - switch (typeof v) { - case 'string' : return [ "JsonString", JS.castJSStringToString(v) ]; - case 'number' : return [ "JsonNumber", JS.castJSNumberToFloat(v) ]; - case 'boolean' : return [ "JsonBool", JS.castJSBoolToBool(v) ]; - case 'object' : - if (v === null) return [ "JsonNull" ]; - for (var i in v) { - v[i] = toValue(v[i]); - } - if (v instanceof Array) return [ "JsonArray", JS.castJSArrayToList(v) ]; - return [ "JsonObject", [ "JSON", v ] ]; - } - } - for (var i in obj) { - obj[i] = toValue(obj[i]); - } - return Elm.Maybe.Just( ['JSON',obj] ); - } - return {empty : empty, - singleton : singleton, - insert : insert, - lookup : lookup, - findNumber : find("JsonNumber",0), - findString : find("JsonString",["Nil"]), - findObject : find("JsonObject", empty ), - findArray : find("JsonArray" ,["Nil"]), - findWithDefault : lookupWithDefault, - remove : remove, - toPrettyJSString : toPrettyJSString, - toJSString : toPrettyJSString(''), - fromJSString : fromJSString, - toPrettyString : function(sep) { return function(v) { - return JS.castJSStringToString(toPrettyJSString(sep)(v)); }; }, - toString : function(v) { return JS.castJSStringToString(toPrettyJSString('')(v)); }, - fromString : function(v) { return fromJSString(JS.castStringToJSString(v)); }, - toList : toList, - fromList : fromList, - JsonString : JsonString, - JsonNumber : JsonNumber, - JsonBool : JsonBool, - JsonNull : JsonNull, - JsonArray : JsonArray, - JsonObject : JsonObject - }; -}(); - -var Value = function(){ - - var eq = function(x,y) { - if (typeof x === "object") { - if (x !== null && '_' in x) { - for (var i in x) { if (x[i] != y[i]) return false; } - for (var i in y) { if (!(i in x)) return false; } - return true; - } - if (x === y) return true; - if (x.length !== y.length) return false; - for (var i = x.length; i--; ) { - if (!eq(x[i],y[i])) return false; - } - return true; - } - return x === y; - }; - - var Tuple = function() { - var len = arguments.length; - var arr = new Array(len+1); - arr[0] = "Tuple" + arguments.length; - for (var i = len; i--; ) { - arr[i+1] = arguments[i]; - } - return arr; - }; - - var listToArray = function(list) { - var arr = []; - while (list[0] === "Cons") { - arr.push(list[1]); - list = list[2]; - } - return arr; - }; - - function makeSpaces(s) { - if (s.length == 0) { return s; } - var arr = s.split(''); - if (arr[0] == ' ') { arr[0] = " " } - for (var i = arr.length; --i; ) { - if (arr[i][0] == ' ' && arr[i-1] == ' ') { - arr[i-1] = arr[i-1] + arr[i]; - arr[i] = ''; - } - } - for (var i = arr.length; i--; ) { - if (arr[i].length > 1 && arr[i][0] == ' ') { - var spaces = arr[i].split(''); - for (var j = spaces.length - 2; j >= 0; j -= 2) { - spaces[j] = ' '; - } - arr[i] = spaces.join(''); - } - } - arr = arr.join(''); - if (arr[arr.length-1] === " ") { - return arr.slice(0,-1) + ' '; - } - return arr; - } - - function properEscape(str) { - if (str.length == 0) return str; - str = str //.replace(/&/g, "&") - .replace(/"/g, /*"*/ """) - .replace(/'/g, /*'*/ "'") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/\n/g, "<br/>"); - var arr = str.split('<br/>'); - for (var i = arr.length; i--; ) { - arr[i] = makeSpaces(arr[i]); - } - return arr.join('<br/>'); - } - - var toText = function(elmList) { - if (typeof elmList === "string") return properEscape(elmList); - var a = []; - while (elmList[0] === "Cons") { - a.push(elmList[1]); - elmList = elmList[2]; - } - return properEscape(a.join('')); - }; - - function getTextSize(w,h,txt) { - var t = document.createElement('div'); - t.innerHTML = txt; - t.style.textAlign = 'left'; - if (w > 0) { t.style.width = w + "px"; } - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var cStyle = window.getComputedStyle(t,null); - var realW = cStyle.getPropertyValue("width").slice(0,-2) - 0; - var realH = cStyle.getPropertyValue("height").slice(0,-2) - 0; - document.body.removeChild(t); - //delete t; - return [Math.ceil(realW),Math.ceil(Math.max(h,realH))]; - } - - function getSize(e) { - var t = e.cloneNode(true); - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var w = t.offsetWidth; - var h = t.offsetHeight; - document.body.removeChild(t); - //delete t; - return [w,h]; - } - - function getExcess(e) { - var t = e.cloneNode(true); - - t.style.visibility = "hidden"; - t.style.styleFloat = "left"; - t.style.cssFloat = "left"; - - document.body.appendChild(t); - var ow = t.offsetWidth; - var oh = t.offsetHeight; - var cStyle = window.getComputedStyle(t,null); - var w = cStyle.getPropertyValue("width").slice(0,-2) - 0; - var h = cStyle.getPropertyValue("height").slice(0,-2) - 0; - document.body.removeChild(t); - //delete t; - return [ow-w,oh-h]; - } - - - function groupForms(forms) { - forms = Elm.JavaScript.castListToJSArray(forms); - var groups = []; - var arr = []; - for (var i = forms.length; i--; ) { - var f = forms[i]; - switch(f[4][0]) { - case "FElement": - if (arr.length > 0) { - groups.push(arr); - arr = []; - } - groups.push(f); - break; - default: - arr.push(f); - } - } - if (arr.length > 0) groups.push(arr); - return groups; - } - - var toString = function(v) { - if (typeof v === "function") { - return "<function>"; - } else if (typeof v === "boolean") { - return v ? "True" : "False"; - } else if (typeof v === "number") { - return v+""; - } else if (typeof v === "string" && v.length < 2) { - return "'"+v+"'"; - } else if (typeof v === "object" && ('_' in v)) { - var output = []; - for (var k in v._) { - console.log(k,v._[k]); - for (var i = v._[k].length; i--; ) { - output.push(k + " = " + toString(v._[k][i])); - } - } - for (var k in v) { - if (k === '_') continue; - output.push(k + " = " + toString(v[k])); - } - if (output.length === 0) return "{}"; - return "{ " + output.join(", ") + " }"; - } else if (v[0]) { - if (v[0].substring(0,5) === "Tuple") { - var output = new Array(v.length-1); - for (var i = v.length; --i; ) { output[i-1] = toString(v[i]); } - return "(" + output.join(",") + ")"; - } else if (v[0] === "Cons") { - var start = (typeof v[1] === "string") ? '"' : "["; - var end = (typeof v[1] === "string") ? '"' : "]"; - var div = (typeof v[1] === "string") ? "" : ","; - var f = (typeof v[1] === "string") ? function(x){return x} : toString; - var output = start + f(v[1]); - v = v[2]; - while (true) { - if (v[0] === "Cons") { - output += div + f(v[1]); - v = v[2]; - } else { - return output + end; - } - } - } else if (v[0] === "Nil") { - return "[]"; - } else if (v[0] === "JSON") { - return "(JSON.fromList " + toString(Elm.JSON.toList(v)) + ")"; - } else if (v[0] === "RBNode" || v[0] === "RBEmpty") { - function cons(k){ return function(v) { return function(acc) { return ["Cons",["Tuple2",k,v],acc]; }; }; } - var list = Elm.Dict.foldr(cons)(["Nil"])(v); - var name = "Dict"; - if (list[0] === "Cons" && list[1][2][0] === "Tuple0") { - name = "Set"; - list = Elm.List.map(function(x) { return x[1]; })(list); - } - return "(" + name + ".fromList " + toString(list) + ")"; - } else { - var output = ""; - for (var i = v.length; --i; ) { output = ' ' + toString(v[i]) + output; } - output = v[0] + output; - return (v.length > 1) ? "(" + output + ")" : output; - } - } - return v+""; - }; - var show = function(v) { return str(toString(v)); }; - var append = function(xs,ys) { - if (typeof xs === "string" && typeof ys === "string") { - return xs.concat(ys); - } - if (xs[0] === "Nil") { - return ys; - } - var root = ["Cons", xs[1], ["Nil"]]; - var curr = root; - xs = xs[2]; - while (xs[0]==="Cons") { - curr[2] = ["Cons", xs[1], ["Nil"]]; - xs = xs[2]; - curr = curr[2]; - } - curr[2] = ys; - return root; - }; - - var str = function(s) { - var out = ["Nil"]; - for (var i = s.length; i--; ) { - out = ["Cons", s[i], out]; - } - return out; - }; - - function wrap(elem) { - var p = Value.getSize(elem); - return ["Element", Guid.guid(), ["EHtml",elem], - p[0], p[1], 1, ["Nothing"], ["Nothing"]]; - } - var addListener = function() { - if(document.addEventListener) { - return function(element, event, handler) { - element.addEventListener(event, handler, false); - }; - } else { - return function(element, event, handler) { - element.attachEvent('on' + event, handler); - }; - } - }(); - - return {eq:eq, - str:str, - show:show, - Tuple:Tuple, - append:append, - listToArray:listToArray, - toText : toText, - properEscape : properEscape, - getTextSize : getTextSize, - getSize : getSize, - getExcess : getExcess, - groupForms : groupForms, - wrap : wrap, - addListener : addListener - }; -}();Elm.List = function() { - - var throwError = function(f) { - throw new Error("Function '" + f + "' expecting a list!"); - } - - function length(xs) { - var out = 0; - while (xs[0] === "Cons") { - out += 1; - xs = xs[2]; - } - return out; - }; - var reverse = foldl(function(x_72) { - return function(y_73) { - return["Cons", x_72, y_73] - } - })(["Nil"]); - var concat = foldr(function(x_74) { - return function(y_75) { - return Value.append(x_74, y_75) - } - })(["Nil"]); - var and = foldl(function(x_77) { - return function(y_78) { - return x_77 && y_78 - } - })(true); - var or = foldl(function(x_79) { - return function(y_80) { - return x_79 || y_80 - } - })(false); - var sum = foldl(function(x_89) { - return function(y_90) { - return x_89 + y_90 - } - })(0); - var product = foldl(function(x_91) { - return function(y_92) { - return x_91 * y_92 - } - })(1); - var maximum = foldl1(function(x) { return function(y) { return Math.max(x,y) } }); - var minimum = foldl1(function(x) { return function(y) { return Math.min(x,y) } }); - function head(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'head' only accepts lists of length greater than one."); - } - return v[1]; - } - function tail(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'tail' only accepts lists of length greater than one."); - } - return v[2]; - } - function last(v) { - if (v[0] !== "Cons") { - throw new Error("Error: 'last' only accepts lists of length greater than one."); - } - var out = v[1]; - while (v[0] === "Cons") { - out = v[1]; - v = v[2]; - } - return out; - } - function map(f) { - return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('map'); } - var root = ["Cons", f(xs[1]), ["Nil"]]; - var curr = root; - xs = xs[2]; - while (xs[0]==="Cons") { - curr[2] = ["Cons", f(xs[1]), ["Nil"]]; - xs = xs[2]; - curr = curr[2]; - } - return root; - } - } - function foldl(f) { - return function(b) { - return function(xs) { - var acc = b; - if (xs[0] === "Nil") { return acc; } - if (xs[0] !== "Cons") { throwError('foldl'); } - while (xs[0] === "Cons") { - acc = f(xs[1])(acc); - xs = xs[2]; - } - return acc; - } - } - } - function foldr(f) { - return function(b) { - return function(xs) { - var acc = b; - if (xs[0] === "Nil") { return acc; } - if (xs[0] !== "Cons") { throwError('foldr'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - } - function foldl1(f_49) { - return function(_temp_50) { - return function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var x_51 = v[1]; - var xs_52 = v[2]; - return foldl(f_49)(x_51)(xs_52) - } - }(_temp_50) - } - } - function foldr1(f) { - return function(xs) { - if (xs[0] === "Nil") { throw new Error("'foldr1' requires an non-empty list.") } - if (xs[0] !== "Cons") { throwError('foldr1'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - var acc = arr.pop(); - for (var i = arr.length; i--; ) { - acc = f(arr[i])(acc); - } - return acc; - } - } - function scanl(f) { - return function(b) { - return function(xs) { - if (xs[0] === "Nil") { return ["Cons",b,["Nil"]]; } - if (xs[0] !== "Cons") { throwError('scanl'); } - var arr = [b]; - while (xs[0] === "Cons") { - b = f(xs[1])(b); - arr.push(b); - xs = xs[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - } - function scanl1(f) { - return function(xs) { - if (xs[0] !== "Cons") { - throw new Error("Error: 'scanl1' requires a list of at least length 1."); - } - return scanl(f)(xs[1])(xs[2]); - } - } - function filter(pred) { - return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('filter'); } - var arr = []; - while (xs[0] === "Cons") { - if (pred(xs[1])) { arr.push(xs[1]); } - xs = xs[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - function concatMap(f_76) { - return function(x) { - return concat(map(f_76)(x)) - } - } - function all(pred) { - return foldl(function(x) { return function(acc) { - return acc && pred(x); - };})(true); - } - function any(pred) { - return foldl(function(x) { return function(acc) { - return acc || pred(x); - };})(false); - } - function partition(pred_93) { - return function(lst_94) { - return function() { - var v = lst_94; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Tuple2", ["Nil"], ["Nil"]] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var x_95 = v[1]; - var xs_96 = v[2]; - return function(v) { - if("Tuple2" !== v[0]) { - return undefined - }else { - var as_97 = v[1]; - var bs_98 = v[2]; - return pred_93(x_95) ? ["Tuple2", ["Cons", x_95, as_97], bs_98] : ["Tuple2", as_97, ["Cons", x_95, bs_98]] - } - }(partition(pred_93)(xs_96)) - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function zipWith(f) { - return function(listA) { - return function(listB) { - if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; } - if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zipWith'); } - var arr = []; - while (listA[0] === "Cons" && listB[0] === "Cons") { - arr.push(f(listA[1])(listB[1])); - listA = listA[2]; - listB = listB[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - } - function zip(listA) { - return function(listB) { - if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; } - if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zip'); } - var arr = []; - while (listA[0] === "Cons" && listB[0] === "Cons") { - arr.push(["Tuple2", listA[1], listB[1]]); - listA = listA[2]; - listB = listB[2]; - } - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = ["Cons", arr[i], out]; - } - return out; - } - } - function unzip(pairs_112) { - return function() { - var v = pairs_112; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Tuple2", ["Nil"], ["Nil"]] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var p_113 = v[1]; - var ps_114 = v[2]; - return function(v) { - if("Tuple2" !== v[0]) { - return undefined - }else { - if("Tuple2" !== v[1][0]) { - return undefined - }else { - var x_115 = v[1][1]; - var y_116 = v[1][2]; - if("Tuple2" !== v[2][0]) { - return undefined - }else { - var xs_117 = v[2][1]; - var ys_118 = v[2][2]; - return["Tuple2", ["Cons", x_115, xs_117], ["Cons", y_116, ys_118]] - } - } - } - }(["Tuple2", p_113, unzip(ps_114)]) - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - function intersperse(sep_119) { - return function(xs_120) { - return function() { - var v = xs_120; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Nil"] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_124 = v[1]; - if("Nil" !== v[2][0]) { - return undefined - }else { - return["Cons", a_124, ["Nil"]] - } - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_121 = v[1]; - if("Cons" !== v[2][0]) { - return undefined - }else { - var b_122 = v[2][1]; - var cs_123 = v[2][2]; - return["Cons", a_121, ["Cons", sep_119, intersperse(sep_119)(["Cons", b_122, cs_123])]] - } - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function intercalate(sep_125) { - return function(xs_126) { - return function() { - var v = xs_126; - var c = [function(v) { - if("Nil" !== v[0]) { - return undefined - }else { - return["Nil"] - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_130 = v[1]; - if("Nil" !== v[2][0]) { - return undefined - }else { - return a_130 - } - } - }, function(v) { - if("Cons" !== v[0]) { - return undefined - }else { - var a_127 = v[1]; - if("Cons" !== v[2][0]) { - return undefined - }else { - var b_128 = v[2][1]; - var cs_129 = v[2][2]; - return Value.append(a_127, Value.append(sep_125, intercalate(sep_125)(["Cons", b_128, cs_129]))) - } - } - }]; - for(var i = c.length;i--;) { - var r = c[i](v); - if(r !== undefined) { - return r - } - } - }() - } - } - function sort(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('sort'); } - var arr = []; - while (xs[0] === "Cons") { - arr.push(xs[1]); - xs = xs[2]; - } - arr.sort(function(a,b) { return a - b}); - var out = ["Nil"]; - for (var i = arr.length; i--; ) { - out = [ "Cons", arr[i], out ]; - } - return out; - } - function take(n) { return function(xs) { - if (n <= 0) { return ["Nil"]; } - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('take'); } - var out = [ "Cons", xs[1], ["Nil"] ]; - var temp = out; - xs = xs[2]; - --n; - while (xs[0] === "Cons" && n > 0) { - temp[2] = [ "Cons", xs[1], ["Nil"] ]; - temp = temp[2]; - xs = xs[2]; - --n; - } - return out; - }; - } - function drop(n) { return function(xs) { - if (xs[0] === "Nil") { return xs; } - if (xs[0] !== "Cons") { throwError('drop'); } - while (xs[0] === "Cons" && n > 0) { - xs = xs[2]; - --n; - } - return xs; - }; - } - return {head:head, - tail:tail, - last:last, - map:map, - foldl:foldl, - foldr:foldr, - foldl1:foldl1, - foldr1:foldr1, - scanl:scanl, - scanl1:scanl1, - filter:filter, - length:length, - reverse:reverse, - concat:concat, - concatMap:concatMap, - and:and, - or:or, - all:all, - any:any, - sum:sum, - product:product, - maximum:maximum, - minimum:minimum, - partition:partition, - zipWith:zipWith, - zip:zip, - unzip:unzip, - intersperse:intersperse, - intercalate:intercalate, - sort:sort, - take:take, - drop:drop}; -}();/*! Maybe -!*/ - -/*[Definition]*/ - -/** data Maybe a = Just a | Nothing - The Maybe datatype. Useful when a computation may or may not - result in a value (e.g. logarithm is defined only for positive numbers). -**/ - -/*[Basic Utilities]*/ - -/** maybe : b -> (a -> b) -> Maybe a -> b - Apply a function to the contents of a `Maybe`. - Return default when given `Nothing`. -**/ -/** isJust : Maybe a -> Bool - Check if constructed with `Just`. -**/ -/** isNothing : Maybe a -> Bool - Check if constructed with `Nothing`. -**/ - -/*[Maybe with Lists]*/ - -/** cons : Maybe a -> [a] -> [a] - If `Just`, adds the value to the front of the list. - If `Nothing`, list is unchanged. -**/ -/** justs : [Maybe a] -> [a] - Filters out Nothings and extracts the remaining values. -**/ - -Elm.Maybe = function() { - function consMaybe(x) { return function(xs) { - if (x[0] === "Just") return ["Cons", x[1], xs]; - return xs; - }; - } - function mapCons(f) { return function(y) { return function(xs) { - var x = f(y); - if (x[0] === "Just") return ["Cons", x[1], xs]; - return xs; - }; - }; - } - function maybe(b) { return function(f) { return function(m) { - if (m[0] === "Just") return f(m[1]); - return b; - }; - }; - } - - return {Just : function(x) { return ["Just",x]; }, - Nothing : ["Nothing"], - justs : Elm.List.foldr(consMaybe)(["Nil"]), - isJust : function(m) { return m[0] === "Just"; }, - isNothing : function(m) { return m[0] === "Nothing"; }, - cons : consMaybe, - maybe : maybe - }; -}(); -/*! Either -!*/ - - -Elm.Either = function() { - /*[Definition]*/ - - /** data Either a b = Left a | Right b - Represents any data that can take two different types. - - This can also be used for error handling (`Either String a`) where - error messages are stored on the left, and the correct values - ("right" values) are stored on the right. - **/ - function Left(a1) { return ['Left',a1]; } - function Right(a1){ return ['Right',a1]; } - - /*[Basics]*/ - - /** either : (a -> c) -> (b -> c) -> Either a b -> c - Apply the first function to a `Left` and the second function to a `Right`. - This allows the extraction of a value from an `Either`. - **/ - function either(f){ return function(g){ return function(e){ - switch(e[0]){ - case 'Left': return f(e[1]); - case 'Right': return g(e[1]); - } - };};} - - /** isLeft : Either a b -> Bool - True if the value is a `Left`. - **/ - function isLeft(e) { return e[0] == 'Left'; } - - /** isRight : Either a b -> Bool - True if the value is a `Right`. - **/ - function isRight(e) { return e[0] == 'Right'; } - - /*[With Lists]*/ - - function get(es) { return Elm.List.map(function(x){return x[1];})(es); } - - /** lefts : [Either a b] -> [a] - Keep only the values held in `Left` values. - **/ - function lefts(es) { return get(Elm.List.filter(isLeft)(es)); } - - /** rights : [Either a b] -> [a] - Keep only the values held in `Right` values. - **/ - function rights(es) { return get(Elm.List.filter(isRight)(es)); } - - /** partition : [Either a b] -> ([a],[b]) - Split into two lists, lefts on the left and rights on the right. - So we have the equivalence: - - partition es == (lefts es, rights es) - **/ - function partition(es) { - var lrs = Elm.List.partition(isLeft)(es); - lrs[1] = get(lrs[1]); - lrs[2] = get(lrs[2]); - return lrs; - } - return {Left:Left, - Right:Right, - either:either, - isLeft:isLeft, - isRight:isRight, - lefts:lefts, - rights:rights, - partition:partition}; -}(); -/*! Char !*/ - -/*[Classification]*/ - -/** isUpper : Char -> Bool - Selects upper case letters. -**/ -/** isLower : Char -> Bool - Selects lower case letters. -**/ -/** isDigit : Char -> Bool - Selects ASCII digits (0..9). -**/ -/** isOctDigit : Char -> Bool - Selects ASCII octal digits (0..7). -**/ -/** isHexDigit : Char -> Bool - Selects ASCII hexadecimal digits (0..9a..fA..F). -**/ - -/*[Conversion]*/ - -/** toUpper : Char -> Char - Convert to upper case. -**/ -/** toLower : Char -> Char - Convert to lower case. -**/ -/** toLocaleUpper : Char -> Char - Convert to upper case, according to any locale-specific case mappings. -**/ -/** toLocaleLower : Char -> Char - Convert to lower case, according to any locale-specific case mappings. -**/ -/** toCode : Char -> Int - Convert to unicode. -**/ -/** fromCode : Int -> Char - Convert from unicode. -**/ - -Elm.Char = function() { - function isBetween(lo,hi) { return function(chr) { - var c = chr.charCodeAt(0); - return lo <= c && c <= hi; - }; - } - var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0)); - var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0)); - var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0)); - - return {fromCode : function(c) { return String.fromCharCode(c); }, - toCode : function(c) { return c.charCodeAt(0); }, - toUpper : function(c) { return c.toUpperCase(); }, - toLower : function(c) { return c.toLowerCase(); }, - toLocaleUpper : function(c) { return c.toLocaleUpperCase(); }, - toLocaleLower : function(c) { return c.toLocaleLowerCase(); }, - isLower : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)), - isUpper : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)), - isDigit : isDigit, - isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)), - isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); } - }; -}(); -Elm.Color = function() { - -function Color_0(a1) { - return function(a2) { - return function(a3) { - return function(a4) { - return["Color", a1, a2, a3, a4] - } - } - } -} -var rgba_1 = Color_0; -var red_3 = ["Color",255,0,0,1]; -var green_4 = ["Color",0,255,0,1]; -var blue_5 = ["Color",0,0,255,1]; -var yellow_6 = ["Color",255,255,0,1]; -var cyan_7 = ["Color",0,255,255,1]; -var magenta_8 = ["Color",255,0,255,1]; -var black_9 = ["Color",0,0,0,1]; -var white_10 = ["Color",255,255,255,1]; -var gray_11 = ["Color",128,128,128,1]; -var grey_12 = ["Color",128,128,128,1]; -function rgb_2(r_13) { - return function(g_14) { - return function(b_15) { - return ["Color",r_13,g_14,b_15,1] - } - } -} -function extract(c) { - if (c[4] === 1) { return 'rgb(' + c[1] + ',' + c[2] + ',' + c[3] + ')'; } - return 'rgba(' + c[1] + ',' + c[2] + ',' + c[3] + ',' + c[4] + ')'; -} -function complement(rgb) { - var hsv = toHSV(rgb); - hsv.hue = (hsv.hue + 180) % 360; - return toRGB(hsv); -} - -function hsva(h) { return function(s) { return function(v) { return function(a) { - var clr = toRGB({hue:h, saturation:s, value:v}); - clr[4] = a; - return clr; - }; }; }; -} - -function hsv(h) { return function(s) { return function(v) { - return toRGB({hue:h, saturation:s, value:v}); }; }; } - -function toHSV(rgb) { - var hsv = {}; - var r = rgb[1] / 255.0, g = rgb[2] / 255.0, b = rgb[3] / 255.0; - var M = Math.max(r,g,b); - var m = Math.min(r,g,b); - var c = M - m; - - var h = 0; - if (c === 0) { h = 0; } - else if (M === r) { h = ((g - b) / c) % 6; } - else if (M === g) { h = ((b - r) / c) + 2; } - else if (M === b) { h = ((r - g) / c) + 4; } - h *= 60; - - return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) }; -} - -function between(lo,hi,x) { return lo <= x && x < hi; } -function norm(n) { return Math.round(n*255); } - -function toRGB(hsv) { - var c = hsv.value * hsv.saturation; - var hue = hsv.hue / 60; - var x = c * (1 - Math.abs((hue % 2) - 1)); - var r = 0, g = 0, b = 0; - if (between(0,1,hue)) { r = c; g = x; b = 0; } - else if (between(1,2,hue)) { r = x; g = c; b = 0; } - else if (between(2,3,hue)) { r = 0; g = c; b = x; } - else if (between(3,4,hue)) { r = 0; g = x; b = c; } - else if (between(4,5,hue)) { r = x; g = 0; b = c; } - else if (between(5,6,hue)) { r = c; g = 0; b = x; } - - var m = hsv.value - c; - return ["Color", norm(r+m), norm(g+m), norm(b+m), 1 ]; -} - return{rgba:rgba_1, rgb:rgb_2, hsva:hsva, hsv:hsv, red:red_3, green:green_4, blue:blue_5, yellow:yellow_6, cyan:cyan_7, magenta:magenta_8, black:black_9, white:white_10, gray:gray_11, grey:grey_12,complement:complement,extract:extract} -}(); -var Collage = function() { - -var JS = Elm.JavaScript; - -function tracePoints(ctx,points) { - var i = points.length - 1; - if (i <= 0) return; - ctx.moveTo(points[i][1], points[i][2]); - while (i--) { ctx.lineTo(points[i][1], points[i][2]); } -} - -function solid(ctx,color,points) { - tracePoints(ctx,points); - ctx.strokeStyle = Elm.Color.extract(color); - ctx.stroke(); -}; - -function filled(ctx,color,points) { - tracePoints(ctx,points); - ctx.fillStyle = Elm.Color.extract(color); - ctx.fill(); -} - -function textured(redo,ctx,src,points) { - var img = new Image(); - img.src = JS.castStringToJSString(src); - img.onload = redo; - - tracePoints(ctx,points); - ctx.fillStyle = ctx.createPattern(img,'repeat'); - ctx.fill(); -} - -function customLine(pattern,ctx,color,points) { - if (pattern.length === 0) { pattern = [8,4]; } - customLineHelp(ctx, pattern, points); - ctx.strokeStyle = Elm.Color.extract(color); - ctx.stroke(); -}; - -var customLineHelp = function(ctx, pattern, points) { - var i = points.length - 1; - if (i <= 0) return; - var x0 = points[i][1], y0 = points[i][2]; - var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0; - var pindex = 0, plen = pattern.length; - var draw = true, segmentLength = pattern[0]; - ctx.moveTo(x0,y0); - while (i--) { - x1 = points[i][1]; y1 = points[i][2]; - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - while (segmentLength <= remaining) { - x0 += dx * segmentLength / remaining; - y0 += dy * segmentLength / remaining; - ctx[draw ? 'lineTo' : 'moveTo'](x0, y0); - // update starting position - dx = x1 - x0; dy = y1 - y0; - remaining = Math.sqrt(dx * dx + dy * dy); - // update pattern - draw = !draw; - pindex = (pindex + 1) % plen; - segmentLength = pattern[pindex]; - } - if (remaining > 0) { - ctx[draw ? 'lineTo' : 'moveTo'](x1, y1); - segmentLength -= remaining; - } - x0 = x1; y0 = y1; - } -}; - -function drawLine(ctx,form) { - var points = form[3][1]; - switch(form[1][0]) { - case "Solid" : return solid(ctx,form[2],points); - case "Dotted": return customLine([3,3],ctx,form[2],points); - case "Dashed": return customLine([8,4],ctx,form[2],points); - case "Custom": return customLine(form[1][1],ctx,form[2],points); - } -}; - -function drawShape(redo,ctx,shapeStyle,color,points) { - switch(shapeStyle[0]) { - case "Filled": return filled(ctx,color,points); - case "Outlined": return solid(ctx,color,points); - case "Textured": return textured(redo,ctx,shapeStyle[1],points); - case "CustomOutline": - return customLine(shapeStyle[1],ctx,color,points); - } -}; - -function drawImage(redo,ctx,w,h,src) { - var img = new Image(); - img.onload = redo; - img.src = JS.castStringToJSString(src); - ctx.drawImage(img,-w/2,-h/2,w,h); -} - -function renderForm(redo,ctx,theta,scale,x,y,form) { - ctx.save(); - if (x !== 0 || y !== 0) ctx.translate(x,y); - if (theta !== ~~theta) ctx.rotate(2*Math.PI*theta); - if (scale !== 1) ctx.scale(scale,scale); - ctx.beginPath(); - switch(form[0]) { - case "FLine": drawLine(ctx,form); break; - case "FShape": drawShape(redo,ctx,form[1],form[2],form[3][1]); break; - case "FImage": drawImage(redo,ctx,form[1],form[2],form[3]); break; - } - ctx.restore(); -}; - -function renderForms(redo,ctx,w,h,forms) { - ctx.clearRect(0,0,w,h); - for (var i = forms.length; i--; ) { - var f = forms[i]; - renderForm(redo,ctx,f[1],f[2],f[3][1],f[3][2],f[4]); - } -} - -function collageForms(w,h,forms) { - var canvas = Render.newElement('canvas'); - w = ~~w; - h = ~~h; - canvas.style.width = w + 'px'; - canvas.style.height = h + 'px'; - canvas.style.display = "block"; - canvas.width = w; - canvas.height = h; - if (canvas.getContext) { - var ctx = canvas.getContext('2d'); - function redo() { renderForms(this,ctx,w,h,forms); } - renderForms(redo,ctx,w,h,forms); - return canvas; - } - canvas.innerHTML = "Your browser does not support the canvas element."; - return canvas; -}; - -function applyTransforms(theta,scale,x,y,w,h,e) { - var t = "translate(" + (x - w / 2) + "px,"+ (y - h / 2) + "px)"; - var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)"; - var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")"; - var transforms = t + " " + s + " " + r; - e.style.transform = transforms; - e.style.msTransform = transforms; - e.style.MozTransform = transforms; - e.style.webkitTransform = transforms; - e.style.OTransform = transforms; -} - -function collageElement(w,h,theta,scale,x,y,elem) { - var e = Render.render(elem); - applyTransforms(theta,scale,x,y,elem[3],elem[4],e); - var div = Render.newElement('div'); - Render.addTo(div,e); - div.style.width = (~~w) + "px"; - div.style.height = (~~h) + "px"; - div.style.overflow = "hidden"; - return div; -} - -function collage(w,h,formss) { - if (formss.length === 0) { return collageForms(w,h,[]); } - var elems = new Array(formss.length); - for (var i = formss.length; i--; ) { - var f = formss[i]; - if (typeof f[0] === "string") { - elems[i] = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]); - } else { - elems[i] = collageForms(w,h,f); - } - } - if (formss.length === 1) { return elems[0]; } - return Render.flowWith(Render.goIn,function(x){return x},elems); -} - -function updateFormSet(node,currSet,nextSet) { - if (Value.eq(nextSet,currSet)) return; - var w = node.style.width.slice(0,-2) - 0; - var h = node.style.height.slice(0,-2) - 0; - if (typeof nextSet[0] === "object") { - if (typeof currSet[0] === "object") { - if (node.getContext) { - var ctx = node.getContext('2d'); - function redo() { renderForms(this,ctx,w,h,nextSet); } - return renderForms(redo,ctx,w,h,nextSet); - } - } - var newNode = collageForms(w,h,nextSet); - newNode.style.position = 'absolute'; - return node.parentNode.replaceChild(newNode,node); - } - node.style.width = (~~w) + "px"; - node.style.height = (~~h) + "px"; - var f = nextSet; - var next = nextSet[4][1]; - Render.update(node.firstChild, currSet[4][1], next); - applyTransforms(f[1],f[2],f[3][1],f[3][2],next[3],next[4],node.firstChild); -} - -// assumes that the form sets are the same length. -function updateCollage(node,currs,nexts) { - if (nexts.length === 1) { - return updateFormSet(node,currs[0],nexts[0]); - } - var kids = node.childNodes; - var len = kids.length; - for (var i = len; i--; ) { - updateFormSet(kids[len-i-1], currs[i], nexts[i]); - } -} - -function style(clr,n,list) { - return ["Tuple2", - '<span style="font-size:100%;color:' + clr + ';">' + n + '</span>', - list]; -} - -function insideForm(point) { return function(form) { - if (!inBoundsOf(point[1],point[2],form)) return false; - var hw, hh; - switch (form[4][0]) { - case "FShape": return insideShape(point,form[1],form[2],form[3],form[4][3][1]); - case "FLine": return false; - case "FImage": - hw = form[4][1] / 2; - hh = form[4][2] / 2; - break; - case "FElement": - hw = form[4][1][3] / 2; - hh = form[4][1][4] / 2; - break; - } - return insideShape(point,form[1],form[2],form[3], - [ [null, hw, hh], - [null,-hw, hh], - [null,-hw,-hh], - [null, hw,-hh], - [null, hw, hh] ]); - }; -} - -function inBoundsOf(px,py,form) { - if (form.length < 6) { - var fx = form[3][1], fy = form[3][2]; - var radiusSquared = 0; - var scale = form[2]; - switch (form[4][0]) { - case "FShape": - var points = form[4][3][1]; - for (var i = points.length; --i; ) { - var p = points[i]; - radiusSquared = Math.max(radiusSquared, p[1]*p[1] + p[2]*p[2]); - } - radiusSquared *= scale * scale; - break; - case "FLine": - break; - case "FImage": - var x = scale * form[4][1] / 2; - var y = scale * form[4][2] / 2; - radiusSquared = x*x + y*y; - break; - case "FElement": - var x = scale * form[4][1][3] / 2; - var y = scale * form[4][1][4] / 2; - radiusSquared = x*x + y*y; - break; - } - form.push(function(px,py) { - var dx = px - fx; - var dy = py - fy; - return dx*dx + dy*dy < radiusSquared + 1; - }); - } - return form[5](px,py); -} - -function insideShape(point,theta,scale,pos,points) { - var counter = 0; - var list = ["Nil"]; - var p1,p2; - - var x = (point[1] - pos[1]) / scale; - var y = (point[2] - pos[2]) / scale; - if (theta !== 0) { - var t = -2 * Math.PI * theta; - var nx = x * Math.cos(t) - y * Math.sin(t); - y = x * Math.sin(t) + y * Math.cos(t); - x = nx; - } - - if (points.length === 0) { return false; } - p1 = points[0]; - for (var i = points.length - 1; i--; ) { - p2 = points[i]; - var p1x = p1[1], p1y = p1[2], p2x = p2[1], p2y = p2[2]; - - if (p1y < p2y) {var ymin=p1y, ymax=p2y;} else {var ymin=p2y, ymax=p1y;} - if (p1x < p2x) {var xmin=p1x, xmax=p2x;} else {var xmin=p2x, xmax=p1x;} - - if (ymin < y && y <= ymax && x <= xmax) { - if (x <= xmin || x <= ((y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x)) { - ++counter; - } - } - p1 = p2; - } - return (counter % 2) === 1; -} - -return {collage:collage, updateCollage:updateCollage, insideForm:insideForm}; - -}();Elm.Graphics = function() { - for (this['i'] in Elm.List) { - eval('var ' + this['i'] + ' = Elm.List[this.i];'); - } - var JS = Elm.JavaScript; - var DLeft_0 = ["DLeft"]; - var DRight_1 = ["DRight"]; - var DUp_2 = ["DUp"]; - var DDown_3 = ["DDown"]; - var DIn_4 = ["DIn"]; - var DOut_5 = ["DOut"]; - function Absolute_12(a1) { - return["Absolute", a1] - } - function Relative_13(a1) { - return["Relative", a1] - } - var Near_14 = ["Near"]; - var Mid_15 = ["Mid"]; - var Far_16 = ["Far"]; - function Position_17(a1) { - return function(a2) { - return["Position", a1, a2] - } - } - function PositionTL_18(a1) { - return function(a2) { - return["PositionTL", a1, a2] - } - } - function PositionTR_19(a1) { - return function(a2) { - return["PositionTR", a1, a2] - } - } - function PositionBL_20(a1) { - return function(a2) { - return["PositionBL", a1, a2] - } - } - function PositionBR_21(a1) { - return function(a2) { - return["PositionBR", a1, a2] - } - } - function Element_37(id,e,w,h,o,c,l) { - return["Element", id, e, w, h, o, c, l ] - } - function EText_39(a1) { - return function(a2) { - return["EText", a1, a2] - } - } - function EImage_40(a1) { - return["EImage", JS.castStringToJSString(a1)] - } - function EVideo_41(a1) { - return["EVideo", JS.castStringToJSString(a1)] - } - function EFittedImage_42(a1) { - return["EFittedImage", JS.castStringToJSString(a1)] - } - function EFlow_43(a1) { - return function(a2) { - return["EFlow", a1, JS.castListToJSArray(a2)] - } - } - function ECollage_44(a1) { - return function(a2) { - return function(a3) { - return["ECollage", a1, a2, Value.groupForms(a3)] - } - } - } - var EEmpty_45 = ["EEmpty"]; - function EContainer_46(a1) { - return function(a2) { - return["EContainer", a1, a2] - } - } - var Solid_68 = ["Solid"]; - var Dotted_69 = ["Dotted"]; - var Dashed_70 = ["Dashed"]; - function Custom_71(a1) { - return["Custom", JS.castListToJSArray(a1)] - } - var Filled_72 = ["Filled"]; - var Outlined_73 = ["Outlined"]; - function CustomOutline_74(a1) { - return["CustomOutline", JS.castListToJSArray(a1)] - } - function Line_75(a1) { - return["Line", JS.castListToJSArray(a1)] - } - function Shape_78(a1) { - return function(a2) { - var points = JS.castListToJSArray(a1); - if (points.length > 0) { points.push(points[0]); } - return["Shape", points, a2]; - } - } - function Form_84(a1) { - return function(a2) { - return function(a3) { - return function(a4) { - return["Form", a1, a2, a3, a4] - } - } - } - } - function FLine_85(a1) { - return function(a2) { - return function(a3) { - return["FLine", a1, a2, a3] - } - } - } - function FShape_86(a1) { - return function(a2) { - return function(a3) { - return["FShape", a1, a2, a3] - } - } - } - function FImage_87(a1) { - return function(a2) { - return function(a3) { - return["FImage", a1, a2, JS.castStringToJSString(a3)] - } - } - } - function FElement_88(a1) { - return["FElement", a1] - } - var left_6 = DLeft_0; - var right_7 = DRight_1; - var down_8 = DDown_3; - var up_9 = DUp_2; - var inward_10 = DIn_4; - var outward_11 = DOut_5; - var topLeft_22 = Position_17(Near_14)(Near_14); - var topRight_23 = Position_17(Far_16)(Near_14); - var bottomLeft_24 = Position_17(Near_14)(Far_16); - var bottomRight_25 = Position_17(Far_16)(Far_16); - var midLeft_26 = Position_17(Near_14)(Mid_15); - var midRight_27 = Position_17(Far_16)(Mid_15); - var midTop_28 = Position_17(Mid_15)(Near_14); - var midBottom_29 = Position_17(Mid_15)(Far_16); - var middle_30 = Position_17(Mid_15)(Mid_15); - function middleAt(a1) { - return function(a2) { - return["PositionAt", a1, a2] - } - } - var topLeftAt_31 = PositionTL_18; - var topRightAt_32 = PositionTR_19; - var bottomLeftAt_33 = PositionBL_20; - var bottomRightAt_34 = PositionBR_21; - var absolute_35 = Absolute_12; - var relative_36 = Relative_13; - function newElement_38(e,w,h,o,c,l) { return Element_37(Guid.guid(),e,w,h,o,c,l); } - function basicNewElement(e,w,h) { return Element_37(Guid.guid(),e,w,h,1,["Nothing"],["Nothing"]); } - var line_76 = Line_75; - var polygon_79 = Shape_78; - function sprite_96(src) { - return function(w) { - return function(h) { - return function(pos) { - return Form_84(0)(1)(pos)(FImage_87(w)(h)(src)) - } - } - } - } - function toForm_97(pos) { - return function(e) { - return Form_84(0)(1)(pos)(FElement_88(e)) - } - } - function width_47(w__101) { - return function(e) { - var be = e[2]; - switch(be[0]) { - case "EImage": - case "EVideo": - return newElement_38(e[2],w__101,e[4] * w__101 / e[3], e[5], e[6], e[7]); - case "EText": - var p = Value.getTextSize(w__101,e[4],be[2]); - return newElement_38(e[2], w__101, p[1], e[5], e[6], e[7]); - } - return newElement_38(e[2], w__101, e[4], e[5], e[6], e[7]); - } - } - function height_48(h__108) { - return function(e) { - var be = e[2]; - switch(be[0]) { - case "EImage": - case "EVideo": - return newElement_38(e[2], e[3] * h__108 / e[4], h__108, e[5], e[6], e[7]); - } - return newElement_38(e[2], e[3], h__108, e[5], e[6], e[7]); - } - } - function size_49(w) { - return function(h) { - return function(e) { - return newElement_38(e[2], w, h, e[5], e[6], e[7]); - } - } - } - function opacity_50(o) { - return function(e) { - return newElement_38(e[2], e[3], e[4], o, e[6], e[7]); - } - } - function color_51(c) { - return function(e) { - return newElement_38(e[2], e[3], e[4], e[5], ["Just",c], e[7]); - } - } - function link(lnk) { - return function(e) { - return newElement_38(e[2], e[3], e[4], e[5], e[6], ["Just", JS.castStringToJSString(lnk)]); - } - } - function widthOf_52(e) { return ~~e[3]; } - function heightOf_53(e) { return ~~e[4]; } - function sizeOf_54(e) { return["Tuple2", ~~e[3], ~~e[4]] } - function text_56(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt), p[0], p[1]) - } - function plainText(str) { - var txt = Value.toText(str); - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt),p[0],p[1]) - } - function asText(v) { - var txt = Elm.Text.monospace(Value.toText(Value.show(v))); - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("left")(txt),p[0],p[1]) - } - function centeredText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("center")(txt),p[0],p[1]) - } - function justifiedText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("justify")(txt),p[0],p[1]) - } - function rightedText(txt) { - var p = Value.getTextSize(0,0,txt); - return basicNewElement(EText_39("right")(txt),p[0],p[1]) - } - function image_57(w) { - return function(h) { - return function(src) { - return basicNewElement(EImage_40(src),w,h) - } - } - } - function images(srcs) { - var pics = Elm.Signal.constant(spacer_66(0)(0)); - var update = Elm.Signal.lift(function(src) { - src = JS.castStringToJSString(src); - var img = new Image(); - img.onload = function() { - Dispatcher.notify(pics.id, - image_57(this.width)(this.height)(src)); - }; - img.src = src; - })(srcs); - function f(x) { return function(y) { return x; } } - var combine = Elm.Signal.lift2(f)(pics)(update); - return combine; - } - function video_58(w) { - return function(h) { - return function(src) { - return basicNewElement(EVideo_41(src),w,h) - } - } - } - function fittedImage_59(w_147) { - return function(h_148) { - return function(s_149) { - return basicNewElement(EFittedImage_42(s_149),w_147,h_148) - } - } - } - function flow_60(dir_150) { - return function(es_151) { - return function() { - var w_152 = function() { - var ws_154 = map(widthOf_52)(es_151); - return function(case1) { - var case0 = case1; - switch(case0[0]) { - case "DLeft": - return sum(ws_154); - case "DRight": - return sum(ws_154) - } - return maximum(ws_154) - }(dir_150) - }(); - var h_153 = function() { - var hs_155 = map(heightOf_53)(es_151); - return function(case3) { - var case2 = case3; - switch(case2[0]) { - case "DDown": - return sum(hs_155); - case "DUp": - return sum(hs_155) - } - return maximum(hs_155) - }(dir_150) - }(); - return basicNewElement(EFlow_43(dir_150)(es_151), w_152, h_153) - }() - } - } - function above_61(e1_156) { - return function(e2_157) { - return basicNewElement(EFlow_43(DDown_3)(["Cons", e1_156, ["Cons", e2_157, ["Nil"]]]), Math.max(widthOf_52(e1_156),widthOf_52(e2_157)), heightOf_53(e1_156) + heightOf_53(e2_157)); - } - } - function below_62(e1_158) { - return function(e2_159) { - return basicNewElement(EFlow_43(DDown_3)(["Cons", e2_159, ["Cons", e1_158, ["Nil"]]]), Math.max(widthOf_52(e1_158),widthOf_52(e2_159)), heightOf_53(e1_158) + heightOf_53(e2_159)); - } - } - function beside_63(e1_160) { - return function(e2_161) { - return basicNewElement(EFlow_43(DRight_1)(["Cons", e1_160, ["Cons", e2_161, ["Nil"]]]), widthOf_52(e1_160) + widthOf_52(e2_161), Math.max(heightOf_53(e1_160),heightOf_53(e2_161))); - } - } - function layers_64(es_162) { - return basicNewElement(EFlow_43(DOut_5)(es_162), maximum(map(widthOf_52)(es_162)), maximum(map(heightOf_53)(es_162))) - } - function collage_65(w_163) { - return function(h_164) { - return function(forms_165) { - return basicNewElement(ECollage_44(w_163)(h_164)(forms_165),w_163,h_164) - } - } - } - function spacer_66(w_166) { - return function(h_167) { - return basicNewElement(EEmpty_45,w_166,h_167) - } - } - function container_67(w_169) { - return function(h_170) { - return function(pos_168) { - return function(e_171) { - return basicNewElement(EContainer_46(pos_168)(e_171),w_169,h_170) - } - } - } - } - function segment_77(p1_172) { - return function(p2_173) { - return Line_75(["Cons", p1_172, ["Cons", p2_173, ["Nil"]]]) - } - } - function rect_80(w_174) { - return function(h_175) { - return function(pos_176) { - return Shape_78(["Cons", ["Tuple2", 0 - w_174 / 2, 0 - h_175 / 2], - ["Cons", ["Tuple2", 0 - w_174 / 2, h_175 / 2], - ["Cons", ["Tuple2", w_174 / 2, h_175 / 2], - ["Cons", ["Tuple2", w_174 / 2, 0 - h_175 / 2], ["Nil"]]]]])(pos_176) - } - } - } - function oval_81(w_177) { - return function(h_178) { - return function(pos_179) { - return function() { - var n_180 = 50; - return function() { - function f_181(i_182) { - return["Tuple2", w_177 / 2 * Math.cos(2 * (Math.PI / n_180) * i_182), h_178 / 2 * Math.sin(2 * (Math.PI / n_180) * i_182)]; - } - return Shape_78(map(f_181)(function() { - var lo = 0; - var hi = n_180 - 1; - var lst = ["Nil"]; - if(lo <= hi) { - do { - lst = ["Cons", hi, lst] - }while(hi-- > lo) - } - return lst - }()))(pos_179) - }() - }() - } - } - } - function circle_82(r_183) { - return oval_81(2 * r_183)(2 * r_183) - } - function ngon_83(n_184) { - return function(r_185) { - return function(pos_186) { - return function() { - var m_187 = n_184; - return function() { - function f_188(i_189) { - return["Tuple2", r_185 * Math.cos(2 * (Math.PI / m_187) * i_189), r_185 * Math.sin(2 * (Math.PI / m_187) * i_189)]; - } - return Shape_78(map(f_188)(function() { - var lo = 0; - var hi = n_184 - 1; - var lst = ["Nil"]; - if(lo <= hi) { - do { - lst = ["Cons", hi, lst] - }while(hi-- > lo) - } - return lst - }()))(pos_186) - }() - }() - } - } - } - function solid_89(clr_190) { - return function(ln_191) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Solid_68)(clr_190)(ln_191)) - } - } - function dotted_90(clr_192) { - return function(ln_193) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Dotted_69)(clr_192)(ln_193)) - } - } - function dashed_91(clr_194) { - return function(ln_195) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Dashed_70)(clr_194)(ln_195)) - } - } - function customLine_92(pattern_196) { - return function(clr_197) { - return function(ln_198) { - return Form_84(0)(1)(["Tuple2", 0, 0])(FLine_85(Custom_71(pattern_196))(clr_197)(ln_198)) - } - } - } - function filled_93(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(Filled_72)(clr)(shape)); - } - } - function outlined_94(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(Outlined_73)(clr)(shape)); - } - } - function customOutline_95(pattern) { - return function(clr) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(CustomOutline_74(pattern))(clr)(shape)); - } - } - } - function textured(src) { - return function(shape) { - return Form_84(0)(1)(shape[2])(FShape_86(["Textured",src])(null)(shape)); - } - } - function rotate_98(t_212) { - return function(Form$thetascaleposform_213) { - return function(case5) { - var case0 = case5; - switch(case0[0]) { - case "Form": - var case1 = case0[1], case2 = case0[2], case3 = case0[3], case4 = case0[4]; - return Form_84(t_212 + case1)(case2)(case3)(case4) - } - throw new Error("Non-exhaustive pattern match in case"); - }(Form$thetascaleposform_213) - } - } - function scale_99(s) { - return function(form) { - return Form_84(form[1])(s * form[2])(form[3])(form[4]) - } - } - function move_100(x_224) { - return function(y_225) { - return function(Form$thetascaleTuple2$pxpyform_226) { - return function(case7) { - var case0 = case7; - switch(case0[0]) { - case "Form": - var case1 = case0[1], case2 = case0[2], case3 = case0[3], case4 = case0[4]; - switch(case3[0]) { - case "Tuple2": - var case5 = case3[1], case6 = case3[2]; - return Form_84(case1)(case2)(["Tuple2", x_224 + case5, y_225 + case6])(case4) - } - break - } - throw new Error("Non-exhaustive pattern match in case"); - }(Form$thetascaleTuple2$pxpyform_226) - } - } - } - return{left:left_6, right:right_7, down:down_8, up:up_9, inward:inward_10, outward:outward_11, topLeft:topLeft_22, topRight:topRight_23, bottomLeft:bottomLeft_24, bottomRight:bottomRight_25, midLeft:midLeft_26, midRight:midRight_27, midTop:midTop_28, midBottom:midBottom_29, middle:middle_30, middleAt:middleAt, topLeftAt:topLeftAt_31, topRightAt:topRightAt_32, bottomLeftAt:bottomLeftAt_33, bottomRightAt:bottomRightAt_34, absolute:absolute_35, relative:relative_36, width:width_47, height:height_48, size:size_49, opacity:opacity_50, - color:color_51, link:link, widthOf:widthOf_52, heightOf:heightOf_53, sizeOf:sizeOf_54, text:text_56, asText:asText, plainText:plainText, centeredText:centeredText, justifiedText:justifiedText, rightedText:rightedText, image:image_57, images:images, video:video_58, fittedImage:fittedImage_59, flow:flow_60, above:above_61, below:below_62, beside:beside_63, layers:layers_64, collage:collage_65, spacer:spacer_66, container:container_67, line:line_76, segment:segment_77, polygon:polygon_79, rect:rect_80, oval:oval_81, circle:circle_82, ngon:ngon_83, solid:solid_89, dotted:dotted_90, dashed:dashed_91, customLine:customLine_92, filled:filled_93, - outlined:outlined_94, customOutline:customOutline_95, textured:textured, sprite:sprite_96, toForm:toForm_97, rotate:rotate_98, scale:scale_99, move:move_100, - isWithin: Collage.insideForm} -}(); -Elm.Text = function() { - function fromString(s) { return Value.toText(s); } - - var addTag = function(tag) { return function(text) { - return '<' + tag + ' style="padding:0;margin:0">' + text + '</' + tag + '>'; - }; - }; - var addStyle = function(style, value) { return function(text) { - return "<span style='" + style + ":" + value + "'>" + text + "</span>"; - }; - }; - - var typeface = function(name) { - name = Elm.JavaScript.castStringToJSString(name); - return addStyle('font-family', name); - }; - var size = function(px) { - return addStyle('font-size', px + 'px'); - }; - var header = addTag('h1'); - var height = function(h) { return addStyle('font-size', h+'em'); } - var italic = addStyle('font-style', 'italic'); - var bold = addTag('b'); - var color = function(c) { - return addStyle('color', Elm.Color.extract(c)); - }; - var underline = addStyle('text-decoration', 'underline'); - var overline = addStyle('text-decoration', 'overline'); - var strikeThrough = addStyle('text-decoration', 'line-through'); - var link = function(href) { return function(text) { - return "<a href='" + fromString(href) + "'>" + text + "</a>"; - }; - }; - - return {fromString : fromString, - toText: fromString, - header : header, - height : height, - italic : italic, - bold : bold, - underline : underline, - overline : overline, - strikeThrough : strikeThrough, - monospace : typeface('monospace'), - typeface : typeface, - color : color, - link : link }; -}(); - -var Render = function(){ - -function newElement(elementType) { - var e = document.createElement(elementType); - e.style.padding = "0"; - e.style.margin = "0"; - return e; -}; - -function addTo(container, elem) { - container.appendChild(elem); -}; - -function makeText(pos,txt) { - var e = newElement('div'); - e.innerHTML = txt; - e.style.textAlign = pos; - return e; -}; - -function image(src) { - var img = newElement('img'); - img.src = src; - img.name = src; - img.style.display = "block"; - return img; -} - -function fittedImage(w,h,src) { - var e = newElement('div'); - e.style.width = w + 'px'; - e.style.height = h + 'px'; - e.style.position = "relative"; - e.style.overflow = "hidden"; - - var img = newElement('img'); - img.onload = function() { - img.style.position = 'absolute'; - img.style.margin = 'auto'; - - var sw = w, sh = h; - if (w / h > this.width / this.height) { - sh = Math.round(this.height * w / this.width); - } else { - sw = Math.round(this.width * h / this.height); - } - img.style.width = sw + 'px'; - img.style.height = sh + 'px'; - img.style.left = ((w - sw) / 2) + 'px'; - img.style.top = ((h - sh) / 2) + 'px'; - }; - img.src = src; - img.name = src; - addTo(e,img); - return e; -}; - -var video = function(src) { - var e = newElement('video'); - e.controls = "controls"; - var source = newElement('source'); - source.src = src; - var segs = src.split('.'); - source.type = "video/" + segs[segs.length-1]; - addTo(e, source); - e.style.display = "block"; - return e; -}; - -function divify(e) { - var div = newElement('div'); - addTo(div, e); - return div; -}; -function goDown(e) { - return e //.tagName === "DIV" ? e : divify(e); -}; -function goRight(e) { - e.style.styleFloat = "left"; - e.style.cssFloat = "left"; - return e; -}; -function goIn(e) { - e.style.position = 'absolute'; - return e; -}; -function flowWith(f, prep, elist) { - var container = newElement('div'); - for (var i = elist.length; i--; ) { - addTo(container, f(prep(elist[i]))); - } - return container; -}; - -function flow(dir,elist) { - switch(dir) { - case "DDown": elist = elist.slice(0).reverse(); - case "DUp": return flowWith(goDown,render,elist); - case "DRight": elist = elist.slice(0).reverse(); - case "DLeft": return flowWith(goRight,render,elist); - case "DOut": elist = elist.slice(0).reverse(); - case "DIn": return flowWith(goIn,render,elist); - }; -}; - -function toPos(pos) { - switch(pos[0]) { - case "Absolute": return pos[1] + "px"; - case "Relative": return (pos[1] * 100) + "%"; - } -} - -function setPos(pos,e) { - e.style.position = 'absolute'; - e.style.margin = 'auto'; - switch(pos[0]) { - case "Position": - if (pos[1][0] !== "Far") e.style.left = 0; - if (pos[1][0] !== "Near") e.style.right = 0; - if (pos[2][0] !== "Far") e.style.top = 0; - if (pos[2][0] !== "Near") e.style.bottom = 0; - break; - case "PositionAt": - e.style.top = toPos(pos[2]); - e.style.left = toPos(pos[1]); - var shift = "translate(" + ~~(-e.style.width.slice(0,-2) / 2) + "px," + ~~(-e.style.height.slice(0,-2) / 2) + "px)"; - e.style.transform = shift; - e.style.msTransform = shift; - e.style.MozTransform = shift; - e.style.webkitTransform = shift; - e.style.OTransform = shift; - break; - default: - var p = pos[0].slice(-2); - e.style[p[0] === "T" ? 'top' : 'bottom'] = toPos(pos[2]); - e.style[p[1] === "L" ? 'left' : 'right'] = toPos(pos[1]); - } -} - -function container(pos,elem) { - var e = render(elem); - setPos(pos,e); - var div = newElement('div'); - div.style.position = "relative"; - div.style.overflow = "hidden"; - addTo(div,e); - return div; -}; - -function render(elem) { - var e = {}; - switch(elem[2][0]) { - case "EText": e = makeText(elem[2][1],elem[2][2]); break; - case "EImage": e = image(elem[2][1]); break; - case "EVideo": e = video(elem[2][1]); break; - case "EFittedImage": e = fittedImage(elem[3],elem[4],elem[2][1]); break; - case "EFlow": e = flow(elem[2][1][0],elem[2][2]); break; - case "ECollage": e = Collage.collage(elem[2][1],elem[2][2],elem[2][3]); break; - case "EEmpty": e = newElement('div'); break; - case "EContainer": e = container(elem[2][1],elem[2][2]); break; - case "EHtml": - e = elem[2][1]; - if (e.type !== 'button') { - var p = Value.getExcess(e); - elem[3] -= p[0]; - elem[4] -= p[1]; - } - break; - case "EExternalHtml": - e = newElement('div'); - addTo(e, elem[2][1]); - break; - } - e.id = elem[1]; - e.style.width = (~~elem[3]) + 'px'; - e.style.height = (~~elem[4]) + 'px'; - if (elem[5] !== 1) { e.style.opacity = elem[5]; } - if (elem[6][0] === "Just") { - e.style.backgroundColor = Elm.Color.extract(elem[6][1]); - } - if (elem[7][0] === "Just") { - var a = newElement('a'); - a.href = elem[7][1]; - addTo(a,e); - return a; - } - return e; -}; - -function update(node,curr,next) { - if (node.tagName === 'A') { node = node.firstChild; } - if (curr[1] === next[1]) return; - if (curr[2][0] !== next[2][0]) { - return node.parentNode.replaceChild(render(next),node); - } - var nextE = next[2], currE = curr[2]; - switch(nextE[0]) { - case "EText": - if (nextE[1] !== currE[1]) node.style.textAlign = nextE[1]; - if (nextE[2] !== currE[2]) node.innerHTML = nextE[2]; - break; - case "EImage": - if (nextE[1] !== currE[1]) node.src = nextE[1]; - break; - case "EVideo": - case "EFittedImage": - if (!Value.eq(nextE,currE) || next[3]!==curr[3] || next[4]!==curr[4]) { - return node.parentNode.replaceChild(render(next),node); - } - break; - case "ECollage": - if (nextE[1] !== currE[1] || nextE[2] !== currE[2] || nextE[3].length !== currE[3].length) { - return node.parentNode.replaceChild(render(next),node); - } - Collage.updateCollage(node,currE[3],nextE[3]); - break; - case "EFlow": - if (nextE[1] !== currE[1]) { - return node.parentNode.replaceChild(render(next),node); - } - var nexts = nextE[2]; - var kids = node.childNodes; - if (nexts.length !== kids.length) { - return node.parentNode.replaceChild(render(next),node); - } - var currs = currE[2]; - var goDir = function(x) { return x; }; - switch(nextE[1][0]) { - case "DDown": case "DUp": goDir = goDown; break; - case "DRight": case "DLeft": goDir = goRight; break; - case "DOut": case "DIn": goDir = goIn; break; - } - for (var i = kids.length; i-- ;) { - update(kids[i],currs[i],nexts[i]); - goDir(kids[i]); - } - break; - case "EContainer": - update(node.childNodes[0],currE[2],nextE[2]); - setPos(nextE[1],node.childNodes[0]); - break; - case "EEmpty": - break; - case "EHtml": - if (next[1] !== curr[1]) { - var e = render(next); - node.parentNode.replaceChild(e,node); - node = e; - } - if (e.type !== 'button') { - var p = Value.getExcess(node); - next[3] -= p[0]; - next[4] -= p[1]; - } - break; - case "EExternalHtml": - if (next[1] !== curr[1]) - node.parentNode.replaceChild(render(next),node); - break; - } - if (next[3] !== curr[3]) node.style.width = (~~next[3]) + 'px'; - if (next[4] !== curr[4]) node.style.height = (~~next[4]) + 'px'; - if (next[5] !== curr[5]) node.style.opacity = next[5]; - if (next[6].length === 2) { - var clr = Elm.Color.extract(next[6][1]); - if (clr !== node.style.backgroundColor) node.style.backgroundColor = clr; - } - if (next[7].length === 2) { - if (curr[7].length === 1 || next[7][1] !== curr[7][1]) node.parentNode.href = next[7][1]; - } - next[1] = curr[1]; -} - -return {render:render,update:update,addTo:addTo,newElement:newElement,flowWith:flowWith,goIn:goIn}; - -}(); -Elm.Signal = function() { - var send = function(node, timestep, changed) { - var kids = node.kids; - for (var i = kids.length; i--; ) { - kids[i].recv(timestep, changed, node.id); - } - }; - function input(base) { - this.id = Guid.guid(); - this.value = base; - this.kids = []; - this.defaultNumberOfKids = 0; - this.recv = function(timestep, eid, v) { - var changed = eid === this.id; - if (changed) { this.value = v; } - send(this, timestep, changed); - return changed; - }; - Dispatcher.inputs.push(this); - }; - function lift(func,args) { - this.id = Guid.guid(); - this.value = null; - this.kids = []; - this.count = 0; - this.changed = false; - - args.reverse(); - this.recalc = function() { - var f = func; - for (var i = args.length; i--; ) { - f = f(args[i].value); - } - this.value = f; - }; - this.recalc(); - - this.recv = function(timestep, changed, parentID) { - this.count += 1; - if (changed) { this.changed = true; } - if (this.count == args.length) { - if (this.changed) { this.recalc() } - send(this, timestep, this.changed); - this.changed = false; - this.count = 0; - } - }; - for (var i = args.length; i--; ) { - args[i].kids.push(this); - } - }; - function fold(func,base,baseIsFunc,input) { - this.id = Guid.guid(); - this.value = baseIsFunc ? base(input.value) : base; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - if (changed) { this.value = func(input.value)(this.value); } - send(this, timestep, changed); - }; - input.kids.push(this); - }; - - function dropIf(pred,base,input) { - this.id = Guid.guid(); - this.value = pred(input.value) ? base : input.value; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - var chng = changed && !pred(input.value); - if (chng) { this.value = input.value; } - send(this, timestep, chng); - }; - input.kids.push(this); - }; - - function dropRepeats(input) { - this.id = Guid.guid(); - this.value = input.value; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - var chng = changed && !Value.eq(this.value,input.value); - if (chng) { this.value = input.value; } - send(this, timestep, chng); - }; - input.kids.push(this); - }; - - var dropWhen = function(s1) { return function(b) { return function(s2) { - var pairs = new lift(function(x){return function(y){return [x,y];};},[s1,s2]); - var dropped = new dropIf(function(p){return p[0];},[true,b],pairs); - return new lift(function(p){return p[1];},[dropped]); }; }; - }; - - function timeIndex(pair,s) { - this.id = Guid.guid(); - var t = (new window.Date).getTime(); - this.value = pair ? Value.Tuple(t,s.value) : t; - this.kids = []; - this.recv = function(timestep, changed, parentID) { - if (changed) this.value = pair ? Value.Tuple(timestep, s.value) : timestep; - send(this, timestep, changed); - }; - s.kids.push(this); - } - - function sampleOn(s1,s2) { - this.id = Guid.guid(); - this.value = s2.value; - this.kids = []; - this.count = 0; - this.changed = false; - - this.recv = function(timestep, changed, parentID) { - if (parentID === s1.id) this.changed = changed; - this.count += 1; - if (this.count == 2) { - if (this.changed) { this.value = s2.value; } - send(this, timestep, this.changed); - this.count = 0; - this.changed = false; - } - }; - s1.kids.push(this); - s2.kids.push(this); - }; - - function delay(t) { return function(s) { - var delayed = new input(s.value); - var firstEvent = true; - function update(v) { - if (firstEvent) return; - setTimeout(function() { Dispatcher.notify(delayed.id,v); },t); - } - function first(a) { return function(b) { return a; }; } - var out = new sampleOn(delayed,new lift(first, [delayed, new lift(update,[s])])); - firstEvent = false; - return out; - }; - } - - function merge(s1,s2) { - this.id = Guid.guid(); - this.value = s1.value; - this.kids = []; - this.next = null; - this.count = 0; - this.changed = false; - - this.recv = function(timestep, changed, parentID) { - this.count += 1; - if (changed) { - this.changed = true; - if (parentID == s2.id && this.next === null) { this.next = s2.value; } - if (parentID == s1.id) { this.next = s1.value; } - } - - if (this.count == 2) { - if (this.changed) { - this.value = this.next; - this.next = null; - } - send(this, timestep, this.changed); - this.changed = false; - this.count = 0; - } - }; - s1.kids.push(this); - s2.kids.push(this); - }; - - function merges(ss) { - function mrg(x) { return function(y) { return new merge(x,y); }; } - return Elm.List.foldl1(mrg)(ss); - } - - function mergeEither(s1) { return function(s2) { - function f(s) { return function(x) { return [s,x]; }; } - return new merge(new lift(f('Left'),[s1]), new lift(f('Right'),[s2])); - }; - } - - function average(sampleSize) { return function(s) { - var sample = new Array(sampleSize); - var i = sampleSize; - while (i--) sample[i] = 0; - i = 0; - var full = false; - var total = 0; - function f(n) { - total += n - sample[i]; - sample[i] = n; - var avg = total / Math.max(1, full ? sampleSize : i); - if (++i == sampleSize) { full = true; i = 0; } - return avg; - } - return new lift(f, [s]); - }; - } - - return { - constant : function(v) { return new input(v); }, - lift : function(f){return function(e){return new lift(f,[e]);};}, - lift2 : function(f) { - return function(e1) { return function(e2) { - return new lift(f, [e1,e2]); };};}, - lift3 : function(f) { - return function(e1) { return function(e2) { - return function(e3){return new lift(f,[e1,e2,e3]);};};};}, - lift4 : function(f) { - return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return new lift(f, [e1,e2,e3,e4]);};};};};}, - lift5 : function(f) { - return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { - return new lift(f, [e1,e2,e3,e4,e5]);};};};};};}, - lift6 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return new lift(f, [e1,e2,e3,e4,e5,e6]); };};};};};};}, - lift7 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return function(e7) { - return new lift(f, [e1,e2,e3,e4,e5,e6,e7]);};};};};};};};}, - lift8 : function(f) { return function(e1) { return function(e2) { - return function(e3) { return function(e4) { - return function(e5) { return function(e6) { - return function(e7) { return function(e8) { - return new lift(f, [e1,e2,e3,e4,e5,e6,e7,e8]);};};};};};};};};}, - foldp : function(f) { return function(b) { return function(e) { - return new fold(f,b,false,e); }; }; }, - foldp$ : function(f) { return function(b) { return function(e) { - return new fold(f,b,true,e); }; }; }, - foldp1 : function(f) { return function(e) { - return new fold(f,function(x){return x;},true,e); }; }, - delay : delay, - merge : function(s1) { return function(s2) { return new merge(s1,s2)}; }, - merges : merges, - mergeEither : mergeEither, - average : average, - count : function(sig) { - var incr = function(_){return function(c){return c+1;};}; - return new fold(incr,0,false,sig) }, - countIf : function(pred) { return function(sig) { - var incr = function(x){return function(c){return pred(x) ? c+1 : c;};}; - return new fold(incr,0,false,sig) }; }, - keepIf : function(pred) { return function(base) { return function(sig) { - return new dropIf(function(x) { return !pred(x)},base,sig); }; }; }, - dropIf : function(pred) { return function(base) { return function(sig) { - return new dropIf(pred,base,sig); }; }; }, - keepWhen : function(s) { return dropWhen(new lift(function(b){return !b;},[s])); }, - dropWhen : dropWhen, - dropRepeats : function(s) { return new dropRepeats(s);}, - sampleOn : function(s1){return function(s2){return new sampleOn(s1,s2);};}, - timestamp : function(s) { return new timeIndex(true, s); }, - timeOf : function(s) { return new timeIndex(false, s); } - }; -}(); -var Dispatcher = function() { - var program = null; - var inputs = []; - var currentElement = null; - - var initialize = function() { - program = Elm.main(); - if (!('recv' in program)) { - program = Elm.Signal.constant(program); - } - - currentElement = program.value; - filterDeadInputs(); - - var content = document.getElementById('content'); - content.appendChild(Render.render(currentElement)); - var w = document.getElementById('widthChecker').offsetWidth; - if (w !== window.innerWidth) { - Dispatcher.notify(Elm.Window.dimensions.id, Value.Tuple(w, window.innerHeight)); - } - program = Elm.Signal.lift(function(value) { - var content = document.getElementById('content'); - Render.update(content.firstChild,currentElement,value); - currentElement = value; - return value; - })(program); - }; - var notify = function(id, v) { - var timestep = (new window.Date).getTime(); - var hasListener = false; - for (var i = inputs.length; i--; ) { - hasListener = inputs[i].recv(timestep, id, v) || hasListener; - } - return hasListener; - }; - - function isAlive(input) { - if (!('defaultNumberOfKids' in input)) return true; - var len = input.kids.length; - if (len == 0) return false; - if (len > input.defaultNumberOfKids) return true; - var alive = false; - for (var i = len; i--; ) { - alive = alive || isAlive(input.kids[i]); - } - return alive; - } - function filterDeadInputs() { - var temp = []; - for (var i = inputs.length; i--; ) { - if (isAlive(inputs[i])) temp.push(inputs[i]); - } - inputs = temp; - } - - return {initialize:initialize, notify:notify, inputs:inputs}; -}(); -/*! HTTP -A library for asynchronous HTTP requests (AJAX). See the -[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if -you have very strict latency requirements. -!*/ - -Elm.HTTP = function() { - var JS = Elm.JavaScript; - var toElmString = Elm.JavaScript.castJSStringToString; - - /*[Creating Requests]*/ - - /** get : String -> Request String - Create a GET request to the given url. - **/ - function get(url) { return request("GET")(url)(null)(["Nil"]); } - - /** post : String -> String -> Request String - Create a POST request to the given url, carrying the given data. - **/ - function post(url) { return function(data) { - return request("POST")(url)(data)(["Nil"]); }; } - - /** request : String -> String -> String -> [(String,String)] -> Request String - Create a customized request. Arguments are request type (get, post, put, - delete, etc.), target url, data, and a list of additional headers. - **/ - function request(verb) { return function(url) { return function(data) { - return function(headers) { - return {0 : "Request", - length : 1, - verb : JS.castStringToJSString(verb), - url : JS.castStringToJSString(url), - data : data === null ? null : JS.castStringToJSString(data), - headers : headers }; }; }; }; - } - - function registerReq(queue,responses) { return function(req) { - if (req.url !== "") { sendReq(queue,responses,req); } - }; - } - - function updateQueue(queue,responses) { - if (queue.length > 0) { - Dispatcher.notify(responses.id, queue[0].value); - if (queue[0].value[0] !== "Waiting") { - queue.shift(); - setTimeout(function() { updateQueue(queue,responses); }, 0); - } - } - } - - function sendReq(queue,responses,req) { - var response = { value: ["Waiting"] }; - queue.push(response); - - var request = null; - if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } - if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } - request.onreadystatechange = function(e) { - if (request.readyState === 4) { - response.value = (request.status === 200 - ? ["Success", toElmString(request.responseText)] - : ["Failure", request.status, - toElmString(request.statusText)]); - setTimeout(function() { updateQueue(queue,responses); }, 0); - } - }; - request.open(req.verb, req.url, true); - Elm.List.map(function(pair) { - request.setRequestHeader( - JS.castStringToJSString(pair[1]), - JS.castStringToJSString(pair[2])); - })(req.headers); - request.send(req.data); - return null; - } - - /*[Responses]*/ - - /** data Response a = Waiting | Success a | Failure Int String - The datatype for responses. Success contains only the returned message. - Failures contain both an error code and an error message. - **/ - - /*[Sending Requests]*/ - - /** send : Signal (Request a) -> Signal (Response String) - Performs an HTTP request with the given requests. Produces a signal - that carries the responses. - **/ - function send(requests) { - var responses = Elm.Signal.constant(["Waiting"]); - var sender = Elm.Signal.lift(registerReq([],responses))(requests); - function f(x) { return function(y) { return x; } } - return Elm.Signal.lift2(f)(responses)(sender); - } - - /** sendGet : Signal String -> Signal (Response String) - Performs an HTTP GET request with the given urls. Produces a signal - that carries the responses. - **/ - - return {get : get, - post : post, - request : request, - send : send, - sendGet : function(urls){return send(Elm.Signal.lift(get)(urls));} - }; -}(); -/*! WebSocket -A library for low latency HTTP communication. See the HTTP library for standard -requests like GET, POST, etc. -!*/ - -Elm.WebSocket = function() { - var JS = Elm.JavaScript; - - /** open : String -> Signal String -> Signal String - Create a web-socket. The first argument is the URL of the desired - web-socket server. The input signal holds the outgoing messages, - and the resulting signal contains the incoming ones. - **/ - function open(url) { return function(outgoing) { - var incoming = Elm.Signal.constant(["Nil"]); - var ws = new window.WebSocket(JS.castStringToJSString(url)); - - var pending = []; - var ready = false; - - ws.onopen = function(e) { - var len = pending.length; - for (var i = 0; i < len; ++i) { ws.send(pending[i]); } - ready = true; - }; - ws.onmessage = function(event) { - Dispatcher.notify(incoming.id, JS.castJSStringToString(event.data)); - }; - - function send(msg) { - var s = JS.castStringToJSString(msg); - ready ? ws.send(s) : pending.push(s); - } - - function take1(x) { return function(y) { return x; } } - return Elm.Signal.lift2(take1)(incoming)(Elm.Signal.lift(send)(outgoing)); - }; - } - - return {open:open}; -}(); - -Elm.Input = function() { - var JS = Elm.JavaScript; - var toElmString = Elm.JavaScript.castJSStringToString; - var newTextInput = function(elem, ghostText) { - elem.placeholder = JS.castStringToJSString(ghostText); - var str = Elm.Signal.constant(["Nil"]); - Value.addListener(elem, 'keyup', function(e) { - Dispatcher.notify(str.id, toElmString(elem.value)); - elem.focus(); - }); - elem.style.padding = "1px"; - return Value.Tuple(Value.wrap(elem), str); - }; - var newElement = function(name) { - var e = document.createElement(name); - e.style.padding = "0"; - e.style.margin = "0"; - return e; - }; - var textArea = function(cols) { return function(rows) { - var textarea = newElement('textarea'); - textarea.rows = rows; - textarea.cols = cols; - return newTextInput(textarea, ""); - }; - }; - var textField = function(ghostText) { - var field = newElement('input'); - field.type = 'text'; - return newTextInput(field, ghostText); - }; - var password = function(ghostText) { - var field = newElement('input'); - field.type = 'password'; - return newTextInput(field, ghostText); - }; - var checkbox = function(checked) { - var box = newElement('input'); - box.type = 'checkbox'; - box.checked = checked; - var status = Elm.Signal.constant(checked); - Value.addListener(box, 'change', function(e) { - Dispatcher.notify(status.id, box.checked); - }); - return Value.Tuple(Value.wrap(box), status); - }; - var dropDown = function(options) { - var slct = newElement('select'); - var opts = []; - while (options[0] === "Cons") { - var opt = newElement('option'); - var str = Value.toText(options[1][1]); - opt.value = str; - opt.innerHTML = str; - slct.appendChild(opt); - opts.push(options[1][2]); - options = options[2]; - } - var status = Elm.Signal.constant(opts[0]); - Value.addListener(slct, 'change', function(e) { - Dispatcher.notify(status.id, opts[slct.selectedIndex]); - }); - return Value.Tuple(Value.wrap(slct), status); - }; - var stringDropDown = function(opts) { - return dropDown(Elm.List.map (function(x) {return Value.Tuple(x,x);}) (opts)); - }; - var button = function(name) { - var b = newElement('input'); - b.type = "button"; - b.value = JS.castStringToJSString(name); - var press = Elm.Signal.constant(false); - Value.addListener(b, 'click', function(e) { - Dispatcher.notify(press.id, true); - Dispatcher.notify(press.id, false); - }); - return Value.Tuple(Value.wrap(b),press); - }; - return {textArea:textArea, textField:textField, - password:password, checkbox:checkbox, - dropDown:dropDown, stringDropDown:stringDropDown, - button:button}; -}(); - -Elm.Keyboard = { Raw : function() { - var keysDown = Elm.Signal.constant(["Nil"]); - var charPressed = Elm.Signal.constant(["Nothing"]); - - function remove(x,xs) { - if (xs[0] === "Nil") return xs; - if (xs[1] === x) return xs[2]; - return ["Cons", xs[1], remove(x,xs[2])]; - } - function has(x,xs) { - while (xs[0] !== "Nil") { - if (xs[1] === x) return true; - xs = xs[2]; - } - return false; - } - Value.addListener(document, 'keydown', function(e) { - if (has(e.keyCode, keysDown.value)) return; - var hasListener = Dispatcher.notify(keysDown.id, ["Cons", e.keyCode, keysDown.value]); - if (!hasListener) - this.removeEventListener('keydown',arguments.callee,false); - }); - Value.addListener(document, 'keyup', function(e) { - var codes = remove(e.keyCode, keysDown.value); - var hasListener = Dispatcher.notify(keysDown.id, codes); - if (!hasListener) - this.removeEventListener('keyup',arguments.callee,false); - }); - Value.addListener(window, 'blur', function(e) { - var hasListener = Dispatcher.notify(keysDown.id, ["Nil"]); - if (!hasListener) - this.removeEventListener('blur',arguments.callee,false); - }); - Value.addListener(document, 'keypress', function(e) { - var hasListener = Dispatcher.notify(charPressed.id, ["Just",e.charCode || e.keyCode]); - Dispatcher.notify(charPressed.id, ["Nothing"]); - if (!hasListener) - this.removeEventListener('keypress',arguments.callee,false); - }); - return {keysDown:keysDown, - charPressed:charPressed}; - }() -}; - -/*! Keyboard -These are nicely curated inputs from the keyboard. See the -[Keyboard.Raw library](/docs/Signal/KeyboardRaw.elm) for a -lower-level interface that will let you define more complicated behavior. -!*/ - -(function() { - function keySignal(f) { - var signal = Elm.Signal.lift(f)(Elm.Keyboard.Raw.keysDown); - Elm.Keyboard.Raw.keysDown.defaultNumberOfKids += 1; - signal.defaultNumberOfKids = 0; - return signal; - } - - function dir(left,right,up,down) { - function f(ks) { - var x = 0, y = 0; - while (ks[0] == "Cons") { - switch (ks[1]) { - case left : --x; break; - case right: ++x; break; - case up : ++y; break; - case down : --y; break; - } - ks = ks[2]; - } - return { _:[true], x:[x], y:[y] }; - } - return keySignal(f); - } - - function is(key) { - function f(ks) { - while (ks[0] == "Cons") { - if (key == ks[1]) return true; - ks = ks[2]; - } - return false; - } - return keySignal(f); - } - - /*[Directions]*/ - - /** arrows : Signal { x:Int, y:Int } - A signal of records indicating which arrow keys are pressed. - - `{ x = 0, y = 0 }` when pressing no arrows. - `{ x =-1, y = 0 }` when pressing the left arrow. - `{ x = 1, y = 1 }` when pressing the up and right arrows. - `{ x = 0, y =-1 }` when pressing the down, left, and right arrows. - **/ - Elm.Keyboard.arrows = dir(37,39,38,40); - - /** wasd : Signal { x:Int, y:Int } - Just like the arrows signal, but this uses keys w, a, s, and d, - which are common controls for many computer games. - **/ - Elm.Keyboard.wasd = dir(65,68,87,83); - - /*[Modifiers]*/ - - /** shift : Signal Bool - Whether the shift key is pressed. - **/ - Elm.Keyboard.shift = is(16); - - /** ctrl : Signal Bool - Whether the control key is pressed. - **/ - Elm.Keyboard.ctrl = is(17); - - /** space : Signal Bool - Whether the space key is pressed. - **/ - Elm.Keyboard.space = is(32); - -}()); -/*! Mouse - !*/ - -Elm.Mouse = function() { - /*[Position]*/ - - /** position : Signal (Int,Int) - The current mouse position. - **/ - var position = Elm.Signal.constant(Value.Tuple(0,0)); - position.defaultNumberOfKids = 2; - - /** x : Signal Int - The current x-coordinate of the mouse. - **/ - var x = Elm.Signal.lift(function(p){return p[1];})(position); - x.defaultNumberOfKids = 0; - - /** y : Signal Int - The current y-coordinate of the mouse. - **/ - var y = Elm.Signal.lift(function(p){return p[2];})(position); - y.defaultNumberOfKids = 0; - - /*[Button Status]*/ - - /** isDown : Signal Bool - The current state of the left mouse-button. - True when the button is down, and false otherwise. - **/ - var isDown = Elm.Signal.constant(false); - - /** isClicked : Signal Bool - True immediately after the left mouse-button has been clicked, - and false otherwise. - **/ - var isClicked = Elm.Signal.constant(false); - - /** clicks : Signal () - Always equal to unit. Event triggers on every mouse click. - **/ - var clicks = Elm.Signal.constant(Value.Tuple()); - - function getXY(e) { - var posx = 0; - var posy = 0; - if (!e) e = window.event; - if (e.pageX || e.pageY) { - posx = e.pageX; - posy = e.pageY; - } else if (e.clientX || e.clientY) { - posx = e.clientX + document.body.scrollLeft + - document.documentElement.scrollLeft; - posy = e.clientY + document.body.scrollTop + - document.documentElement.scrollTop; - } - return Value.Tuple(posx, posy); - } - - Value.addListener(document, 'click', function(e) { - var hasListener1 = Dispatcher.notify(isClicked.id, true); - var hasListener2 = Dispatcher.notify(clicks.id, Value.Tuple()); - Dispatcher.notify(isClicked.id, false); - if (!hasListener1 && !hasListener2) - this.removeEventListener('click',arguments.callee,false); - }); - Value.addListener(document, 'mousedown', function(e) { - var hasListener = Dispatcher.notify(isDown.id, true); - if (!hasListener) - this.removeEventListener('mousedown',arguments.callee,false); - }); - Value.addListener(document, 'mouseup', function(e) { - var hasListener = Dispatcher.notify(isDown.id, false); - if (!hasListener) - this.removeEventListener('mouseup',arguments.callee,false); - }); - Value.addListener(document, 'mousemove', function(e) { - var hasListener = Dispatcher.notify(position.id, getXY(e)); - if (!hasListener) - this.removeEventListener('mousemove',arguments.callee,false); - }); - - /** isClickedOn : Element -> (Element, Signal Bool) - Determine whether an element has been clicked. The resulting pair - is a signal of booleans that is true when its paired element has - been clicked. The signal is True immediately after the left - mouse-button has been clicked, and false otherwise. - **/ - var clickedOn = function(elem) { - var node = Render.render(elem); - var click = Elm.Signal.constant(false); - Value.addListener(node, 'click', function(e) { - Dispatcher.notify(click.id, true); - Dispatcher.notify(click.id, false); - }); - return Value.Tuple(Value.wrap(node), click); - }; - return {position: position, - x:x, - y:y, - isClicked: isClicked, - isDown: isDown, - clicks: clicks, - isClickedOn: clickedOn - }; - }();/*! Random - !*/ - -Elm.Random = function() { - /*[In a Range]*/ - - /** inRange : Int -> Int -> Signal Int - Given a range from low to high, this produces a random number - between 'low' and 'high' inclusive. The value in the signal does - not change after the page has loaded. - **/ - var inRange = function(min) { return function(max) { - return Elm.Signal.constant(Math.floor(Math.random() * (max-min+1)) + min); - }; - }; - - /** randomize : Int -> Int -> Signal a -> Signal Int - Given a range from low to high and a signal of values, this produces - a new signal that changes whenever the input signal changes. The new - values are random number between 'low' and 'high' inclusive. - **/ - var randomize = function(min) { return function(max) { return function(signal) { - function f(x) { return Math.floor(Math.random() * (max-min+1)) + min; } - return Elm.Signal.lift(f)(signal); - }; - }; - }; - return { inRange:inRange, randomize:randomize }; -}();/*! Time -Library for working with time. Type `Time` represents some number of -milliseconds. -!*/ - -Elm.Time = function() { - - /*[Times]*/ - - /** hour, minute, second, ms : Time - Units of time, making it easier to specify things like a - half-second `(second / 2)`. - **/ - - function timeNow() { return (new window.Date).getTime(); } - - /*[Tickers]*/ - - /** fps : Number -> Signal Time - Takes desired number of frames per second (fps). The resulting signal - gives a sequence of time deltas as quickly as possible until it reaches - the desired FPS. A time delta is the time between the last frame and the - current frame. - **/ - - /** fpsWhen : Number -> Signal Bool -> Signal Time - Same as the fps function, but you can turn it on and off. Allows you - to do brief animations based on user input without major ineffeciencies. - The first time delta after a pause is always zero, no matter how long - the pause was. This way summing the deltas will actually give the amount - of time that the output signal has been running. - **/ - function fpsWhen(desiredFPS) { return function (isOn) { - var msPerFrame = 1000 / desiredFPS; - var prev = timeNow(), curr = prev, diff = 0, wasOn = true; - var ticker = Elm.Signal.constant(diff); - function tick(zero) { return function() { - curr = timeNow(); - diff = zero ? 0 : curr - prev; - prev = curr; - Dispatcher.notify(ticker.id, diff); - }; - } - var timeoutID = 0; - function f(isOn) { return function(t) { - if (isOn) { - timeoutID = setTimeout(tick(!wasOn && isOn), msPerFrame); - } else if (wasOn) { - clearTimeout(timeoutID); - } - wasOn = isOn; - return t; - }; - } - return Elm.Signal.lift2(f)(isOn)(ticker); - }; - } - - /** every : Time -> Signal Time - Takes a time interval t. The resulting signal is the current time, - updated every t. - **/ - function everyWhen(isOn) { return function(t) { - var clock = Elm.Signal.constant(timeNow()); - function tellTime() { Dispatcher.notify(clock.id, timeNow()); } - setInterval(tellTime, t); - return clock; - }; - } - - function since(t) { return function(s) { - function cmp(a) { return function(b) { return !Value.eq(a,b); }; } - var dcount = Elm.Signal.count(Elm.Signal.delay(t)(s)); - return Elm.Signal.lift2(cmp)(Elm.Signal.count(s))(dcount); - }; - } - function after(t) { - t *= 1000; - var thread = Elm.Signal.constant(false); - setTimeout(function() { Dispatcher.notify(thread.id, true); }, t); - return thread; - } - function before(t) { - t *= 1000; - var thread = Elm.Signal.constant(true); - setTimeout(function() { Dispatcher.notify(thread.id, false); }, t); - return thread; - } - function read(s) { - var t = window.Date.parse(s); - return isNaN(t) ? ["Nothing"] : ["Just",t]; - } - return {fpsWhen : fpsWhen, - fps : function(t) { return fpsWhen(t)(Elm.Signal.constant(true)); }, - every : everyWhen(Elm.Signal.constant(true)), - delay : Elm.Signal.delay, - since : since, - after : after, - before : before, - hour : 3600000, - minute : 60000, - second : 1000, - ms : 1, - inHours : function(t) { return t / 3600000; }, - inMinutes : function(t) { return t / 60000; }, - inSeconds : function(t) { return t / 1000; }, - inMss : function(t) { return t; }, - toDate : function(t) { return new window.Date(t); }, - read : read - }; - -}();/*! Window !*/ - -Elm.Window = function() { - - /*[Dimensions]*/ - - /** dimensions : Signal (Int,Int) - The current dimensions of the window (i.e. the area viewable to the - user, not including scroll bars). - **/ - var dimensions = Elm.Signal.constant(Value.Tuple(window.innerWidth, - window.innerHeight)); - dimensions.defaultNumberOfKids = 2; - - /** width : Signal Int - The current width of the window. - **/ - var width = Elm.Signal.lift(function(p){return p[1];})(dimensions); - width.defaultNumberOfKids = 0; - - /** height : Signal Int - The current height of the window. - **/ - var height = Elm.Signal.lift(function(p){return p[2];})(dimensions); - height.defaultNumberOfKids = 0; - - Value.addListener(window, 'resize', function(e) { - var w = document.getElementById('widthChecker').offsetWidth; - var hasListener = Dispatcher.notify(dimensions.id, - Value.Tuple(w, window.innerHeight)); - if (!hasListener) - this.removeEventListener('resize',arguments.callee,false); - }); - return {dimensions:dimensions,width:width,height:height}; -}(); - -Elm.Date = function() { - - function dateNow() { return new window.Date; } - function readDate(str) { - var d = new window.Date(Elm.JavaScript.castStringToJSString(str)); - if (isNaN(d.getTime())) return ["Nothing"]; - return ["Just",d]; - } - - var dayTable = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - var monthTable = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - - return { - read : readDate, - year : function(d) { return d.getFullYear(); }, - month : function(d) { return [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(); }, - dayOfWeek : function(d) { return [dayTable[d.getDay()]]; }, - toTime : function(d) { return d.getTime(); }, - Mon : ["Mon"], Tue : ["Tue"], Wed : ["Wed"], - Thu : ["Thu"], Fri : ["Fri"], Sat : ["Sat"], Sun : ["Sun"], - Jan : ["Jan"], Feb : ["Feb"], Mar : ["Mar"], Apr : ["Apr"], - May : ["May"], Jun : ["Jun"], Jul : ["Jul"], Aug : ["Aug"], - Sep : ["Sep"], Oct : ["Oct"], Nov : ["Nov"], Dec : ["Dec"] - }; - -}(); -function elmRecordCopy(r) { - var o = {}; - for (var i in r) { o[i] = r[i]; } - return o; -} - -function elmRecordRemove(x,r) { - var o = elmRecordCopy(r); - if (x in o._) { - o[x] = o._[x][0]; - o._[x] = o._[x].slice(1); - if (o._[x].length === 0) { delete o._[x]; } - } else { - delete o[x]; - } - return o; -} - -function elmRecordReplace(kvs,r) { - var o = elmRecordCopy(r); - for (var i = kvs.length; i--; ) { - kvsi = kvs[i]; - o[kvsi[0]] = kvsi[1]; - } - return o; -} - -function elmRecordInsert(x,v,r) { - var o = elmRecordCopy(r); - if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []); - o[x] = v; - return o; -} - -Value.addListener(document, 'elm_log', function(e) { console.log(e.value); }); -Value.addListener(document, 'elm_title', function(e) {document.title = e.value;}); -Value.addListener(document, 'elm_redirect', function(e) { - if (e.value.length > 0) { window.location = e.value; } - }); -Value.addListener(document, 'elm_viewport', function(e) { - var node = document.getElementById('elm_viewport'); - if (!node) { - node = document.createElement('meta'); - node.id = 'elm_viewport'; - node.name = 'viewport'; - document.head.appendChild(node); - } - node.content = e.value; - Dispatcher.notify(Elm.Window.dimensions.id, - Value.Tuple(window.innerWidth, window.innerHeight)); - }); - -Elm.Prelude = function() { - var mod = function(x) { return function(y) { - var r = x % y; - var m = x==0 ? 0 : (y>0 ? (x>=0 ? r : r+y) : -mod(-x)(-y)); - return m == y ? 0 : m; - }; }; - - var min = function(x) { return function(y) { return Math.min(x,y); }; }; - var max = function(x) { return function(y) { return Math.max(x,y); }; }; - - var flip=function(f){return function(x){return function(y){return f(y)(x);};};}; - var clamp = function(lo) { return function(hi) { - return function(x) { return Math.min(hi, Math.max(lo, x)); }; - }; - }; - var curry = function(f) { return function(x) { return function(y) { - return f(["Tuple2",x,y]); }; }; - }; - var uncurry = function(f) { return function(p) { - if (p[0] !== "Tuple2") { - throw new Error("Function was uncurry'd but was not given a pair."); - } - return f(p[1])(p[2]); }; - }; - - var logBase=function(b){return function(x){return Math.log(x)/Math.log(b);};}; - - function readInt(str) { - var s = Elm.JavaScript.castStringToJSString(str); - var len = s.length; - if (len === 0) { return ["Nothing"]; } - var start = 0; - if (s[0] == '-') { - if (len === 1) { return ["Nothing"]; } - start = 1; - } - for (var i = start; i < len; ++i) { - if (!Elm.Char.isDigit(s[i])) { return ["Nothing"]; } - } - return ["Just", parseInt(s)]; - } - - function readFloat(str) { - var s = Elm.JavaScript.castStringToJSString(str); - var len = s.length; - if (len === 0) { return ["Nothing"]; } - var start = 0; - if (s[0] == '-') { - if (len === 1) { return ["Nothing"]; } - start = 1; - } - var dotCount = 0; - for (var i = start; i < len; ++i) { - if (Elm.Char.isDigit(s[i])) { continue; } - if (s[i] === '.') { - dotCount += 1; - if (dotCount <= 1) { continue; } - } - return ["Nothing"]; - } - return ["Just", parseFloat(s)]; - } - - function compare(x) { return function (y) { - if (x instanceof Array && y instanceof Array) { - var len = x.length; - if (len == y.length) { - for (var i = 1; i < len; ++i) { - var cmp = compare(x[i])(y[i]); - if (cmp[0] === 'EQ') continue; - return cmp; - } - return ['EQ']; - } - return [ y.length == 1 ? 'GT' : 'LT' ]; - } - return [ x === y ? 'EQ' : (x < y ? 'LT' : 'GT') ]; - }; - } - return {eq : Value.eq, - id : function(x) { return x; }, - not : function(b) { return !b; }, - xor : function(x) { return function(y) { return x != y; }; }, - fst : function(p) { return p[1]; }, - snd : function(p) { return p[2]; }, - rem : function(x) { return function(y) { return x % y; }; }, - div : function(x) { return function(y) { return ~~(x / y); }; }, - otherwise : true, - compare : compare, - toFloat : function(x) { return x; }, - round : function(n) { return Math.round(n); }, - floor : function(n) { return Math.floor(n); }, - ceiling : function(n) { return Math.ceil(n); }, - truncate : function(n) { return ~~n; }, - readInt : readInt, - readFloat : readFloat, - sqrt : Math.sqrt, - abs : Math.abs, - pi : Math.PI, - e : Math.E, - sin : Math.sin, - cos : Math.cos, - tan : Math.tan, - asin : Math.asin, - acos : Math.acos, - atan : Math.atan, - atan2 : function(y) { return function(x) { return Math.atan2(y,x); }; }, - mod : mod, - min : min, - max : max, - flip : flip, - clamp : clamp, - curry : curry, - uncurry : uncurry, - logBase : logBase, - Just : Elm.Maybe.Just, - Nothing : Elm.Maybe.Nothing, - maybe : Elm.Maybe.maybe, - map : Elm.List.map, - zip : Elm.List.zip, - zipWith : Elm.List.zipWith, - filter : Elm.List.filter, - head : Elm.List.head, - tail : Elm.List.tail, - last : Elm.List.last, - length : Elm.List.length, - reverse : Elm.List.reverse, - foldr : Elm.List.foldr, - foldr1 : Elm.List.foldr1, - foldl : Elm.List.foldl, - foldl1 : Elm.List.foldl1, - and : Elm.List.and, - or : Elm.List.or, - all : Elm.List.all, - any : Elm.List.any, - sum : Elm.List.sum, - product : Elm.List.product, - concat : Elm.List.concat, - concatMap : Elm.List.concatMap, - maximum : Elm.List.maximum, - minimum : Elm.List.minimum, - scanl : Elm.List.scanl, - scanl1 : Elm.List.scanl1, - take : Elm.List.take, - drop : Elm.List.drop, - zip : Elm.List.zip, - unzip : Elm.List.unzip, - lift : Elm.Signal.lift, - lift2 : Elm.Signal.lift2, - lift3 : Elm.Signal.lift3, - lift4 : Elm.Signal.lift4, - lift5 : Elm.Signal.lift5, - lift6 : Elm.Signal.lift6, - lift7 : Elm.Signal.lift7, - lift8 : Elm.Signal.lift8, - foldp : Elm.Signal.foldp, - foldp1 : Elm.Signal.foldp1, - foldp$ : Elm.Signal.foldp$, - constant : Elm.Signal.constant, - merge : Elm.Signal.merge, - merges : Elm.Signal.merges, - mergeEither : Elm.Signal.mergeEither, - count : Elm.Signal.count, - countIf : Elm.Signal.countIf, - average : Elm.Signal.average, - keepIf : Elm.Signal.keepIf, - dropIf : Elm.Signal.dropIf, - keepWhen : Elm.Signal.keepWhen, - dropWhen : Elm.Signal.dropWhen, - dropRepeats : Elm.Signal.dropRepeats, - sampleOn : Elm.Signal.sampleOn, - timestamp : Elm.Signal.timestamp, - timeOf : Elm.Signal.timeOf - }; - -}(); - -(function() { - var include = function(library) { - for (var i in library) { - Elm.Prelude[i] = library[i]; - } - }; - include (Elm.Color); - include (Elm.Text); - include (Elm.Graphics); - include (Elm.Time); - - show = Value.show; - -}()); -/*! Touch -This is an early version of the touch library. It will likely grow to -include gestures that would be useful for both games and web-pages. -!*/ - -Elm.Touch = function() { - - function Dict() { - this.keys = []; - this.values = []; - - this.insert = function(key,value) { - this.keys.push(key); - this.values.push(value); - }; - this.lookup = function(key) { - var i = this.keys.indexOf(key) - return i >= 0 ? this.values[i] : {x:0,y:0,t:0}; - }; - this.remove = function(key) { - var i = this.keys.indexOf(key); - if (i < 0) return; - var t = this.values[i]; - this.keys.splice(i,1); - this.values.splice(i,1); - return t; - }; - } - - var root = Elm.Signal.constant([]), - tapTime = 500, - hasTap = false, - tap = {_:[true],x:[0],y:[0]}, - dict = new Dict(); - - function touch(t) { - var r = dict.lookup(t.identifier); - return {_ : [true], id: [t.identifier], - x: [t.pageX], y: [t.pageY], - x0: [r.x], y0: [r.y], - t0: [r.t] }; - } - - function start(e) { - dict.insert(e.identifier,{x:e.pageX,y:e.pageY,t:Date.now()}); - } - function end(e) { - var t = dict.remove(e.identifier); - if (Date.now() - t.t < tapTime) { - hasTap = true; - tap = {_:[true], x:[t.x], y:[t.y]}; - } - } - - function listen(name, f) { - function update(e) { - for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); } - var ts = new Array(e.touches.length); - for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); } - var hasListener = Dispatcher.notify(root.id, ts); - if (!hasListener) return document.removeEventListener(name, update); - e.preventDefault(); - } - Value.addListener(document, name, update); - } - - listen("touchstart", start); - listen("touchmove", function(_){}); - listen("touchend", end); - listen("touchcancel", end); - listen("touchleave", end); - - function dependency(f) { - var sig = Elm.Signal.lift(f)(root); - root.defaultNumberOfKids += 1; - sig.defaultNumberOfKids = 0; - return sig; - } - - /*[Touches]*/ - - /** touches : Signal [{ x:Int, y:Int, id:Int, x0:Int, y0:Int, t0:Time }] - A list of touches. Each ongoing touch is represented by a set of - coordinates and an identifier id that allows you to distinguish - between different touches. Each touch also contains the coordinates and - time of the initial contact (x0, y0, and t0) which helps compute more - complicated gestures. - **/ - var touches = dependency(function(ts) { - return Elm.JavaScript.castJSArrayToList(ts); - }); - - /*[Gestures]*/ - - /** taps : Signal { x:Int, y:Int } - The last position that was tapped. Default value is `{x=0,y=0}`. - Updates whenever the user taps the screen. - **/ - var taps = function() { - var sig = dependency(function(_) { return tap; }); - sig.defaultNumberOfKids = 1; - function pred(_) { var b = hasTap; hasTap = false; return b; } - var sig2 = Elm.Signal.keepIf(pred)({_:[true],x:[0],y:[0]})(sig); - sig2.defaultNumberOfKids = 0; - return sig2; - }(); - - return { touches: touches, taps: taps }; -}(); -Elm.Dict=function(){ - var compare = Elm.Prelude.compare; - var uncurry = Elm.Prelude.uncurry; - var Nothing = Elm.Prelude.Nothing; - var Just = Elm.Prelude.Just; - var not = Elm.Prelude.not; - var eq = Elm.Prelude.eq; - var isJust=Elm.Maybe.isJust; - var Red_0=['Red']; - var Black_1=['Black']; - function RBNode_2(a1){ - return function(a2){ - return function(a3){ - return function(a4){ - return function(a5){ - return ['RBNode',a1,a2,a3,a4,a5];};};};};} - var RBEmpty_3=['RBEmpty']; - function min_6(t_42){ - return function(){ - switch(t_42[0]){ - case 'RBEmpty': - throw '(min RBEmpty) is not defined'; - case 'RBNode': - switch(t_42[4][0]){ - case 'RBEmpty': - return ['Tuple2',t_42[2],t_42[3]]; - } - return min_6(t_42[4]); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function lookup_7(k_46){ - return function(t_47){ - return function(){ - switch(t_47[0]){ - case 'RBEmpty': - return Nothing; - case 'RBNode': - return function(){ - var case12=compare(k_46)(t_47[2]); - switch(case12[0]){ - case 'EQ': - return Just(t_47[3]); - case 'GT': - return lookup_7(k_46)(t_47[5]); - case 'LT': - return lookup_7(k_46)(t_47[4]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function findWithDefault_8(base_52){ - return function(k_53){ - return function(t_54){ - return function(){ - switch(t_54[0]){ - case 'RBEmpty': - return base_52; - case 'RBNode': - return function(){ - var case19=compare(k_53)(t_54[2]); - switch(case19[0]){ - case 'EQ': - return t_54[3]; - case 'GT': - return findWithDefault_8(base_52)(k_53)(t_54[5]); - case 'LT': - return findWithDefault_8(base_52)(k_53)(t_54[4]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function member_9(k_59){ - return function(t_60){ - return isJust(lookup_7(k_59)(t_60));};} - function rotateLeft_10(t_61){ - return function(){ - switch(t_61[0]){ - case 'RBNode': - switch(t_61[5][0]){ - case 'RBNode': - return RBNode_2(t_61[1])(t_61[5][2])(t_61[5][3])(RBNode_2(Red_0)(t_61[2])(t_61[3])(t_61[4])(t_61[5][4]))(t_61[5][5]); - }break; - } - throw 'rotateLeft of a node without enough children';}();} - function rotateRight_11(t_71){ - return function(){ - switch(t_71[0]){ - case 'RBNode': - switch(t_71[4][0]){ - case 'RBNode': - return RBNode_2(t_71[1])(t_71[4][2])(t_71[4][3])(t_71[4][4])(RBNode_2(Red_0)(t_71[2])(t_71[3])(t_71[4][5])(t_71[5])); - }break; - } - throw 'rotateRight of a node without enough children';}();} - function rotateLeftIfNeeded_12(t_81){ - return function(){ - switch(t_81[0]){ - case 'RBNode': - switch(t_81[5][0]){ - case 'RBNode': - switch(t_81[5][1][0]){ - case 'Red': - return rotateLeft_10(t_81); - }break; - }break; - } - return t_81;}();} - function rotateRightIfNeeded_13(t_82){ - return function(){ - switch(t_82[0]){ - case 'RBNode': - switch(t_82[4][0]){ - case 'RBNode': - switch(t_82[4][1][0]){ - case 'Red': - switch(t_82[4][4][0]){ - case 'RBNode': - switch(t_82[4][4][1][0]){ - case 'Red': - return rotateRight_11(t_82); - }break; - }break; - }break; - }break; - } - return t_82;}();} - function otherColor_14(c_83){ - return function(){ - switch(c_83[0]){ - case 'Black': - return Red_0; - case 'Red': - return Black_1; - } - throw new Error("Non-exhaustive pattern match in case");}();} - function color_flip_15(t_84){ - return function(){ - switch(t_84[0]){ - case 'RBNode': - switch(t_84[4][0]){ - case 'RBNode': - switch(t_84[5][0]){ - case 'RBNode': - return RBNode_2(otherColor_14(t_84[1]))(t_84[2])(t_84[3])(RBNode_2(otherColor_14(t_84[4][1]))(t_84[4][2])(t_84[4][3])(t_84[4][4])(t_84[4][5]))(RBNode_2(otherColor_14(t_84[5][1]))(t_84[5][2])(t_84[5][3])(t_84[5][4])(t_84[5][5])); - }break; - }break; - } - throw 'color_flip called on a RBEmpty or RBNode with a RBEmpty child';}();} - function color_flipIfNeeded_16(t_98){ - return function(){ - switch(t_98[0]){ - case 'RBNode': - switch(t_98[4][0]){ - case 'RBNode': - switch(t_98[4][1][0]){ - case 'Red': - switch(t_98[5][0]){ - case 'RBNode': - switch(t_98[5][1][0]){ - case 'Red': - return color_flip_15(t_98); - }break; - }break; - }break; - }break; - } - return t_98;}();} - function fixUp_17(t_99){ - return color_flipIfNeeded_16(rotateRightIfNeeded_13(rotateLeftIfNeeded_12(t_99)));} - function ensureBlackRoot_18(t_100){ - return function(){ - switch(t_100[0]){ - case 'RBNode': - switch(t_100[1][0]){ - case 'Red': - return RBNode_2(Black_1)(t_100[2])(t_100[3])(t_100[4])(t_100[5]); - }break; - } - return t_100;}();} - function insert_19(k_105){ - return function(v_106){ - return function(t_107){ - return function(){ - function ins_108(t_109){ - return function(){ - switch(t_109[0]){ - case 'RBEmpty': - return RBNode_2(Red_0)(k_105)(v_106)(RBEmpty_3)(RBEmpty_3); - case 'RBNode': - return function(){ - var h_115=function(){ - var case114=compare(k_105)(t_109[2]); - switch(case114[0]){ - case 'EQ': - return RBNode_2(t_109[1])(t_109[2])(v_106)(t_109[4])(t_109[5]); - case 'GT': - return RBNode_2(t_109[1])(t_109[2])(t_109[3])(t_109[4])(ins_108(t_109[5])); - case 'LT': - return RBNode_2(t_109[1])(t_109[2])(t_109[3])(ins_108(t_109[4]))(t_109[5]); - } - throw new Error("Non-exhaustive pattern match in case");}(); - return fixUp_17(h_115);}(); - } - throw new Error("Non-exhaustive pattern match in case");}();} - return ensureBlackRoot_18(ins_108(t_107));}();};};} - function singleton_20(k_116){ - return function(v_117){ - return insert_19(k_116)(v_117)(RBEmpty_3);};} - function isRed_21(t_118){ - return function(){ - switch(t_118[0]){ - case 'RBNode': - switch(t_118[1][0]){ - case 'Red': - return true; - }break; - } - return false;}();} - function isRedLeft_22(t_119){ - return function(){ - switch(t_119[0]){ - case 'RBNode': - switch(t_119[4][0]){ - case 'RBNode': - switch(t_119[4][1][0]){ - case 'Red': - return true; - }break; - }break; - } - return false;}();} - function isRedLeftLeft_23(t_120){ - return function(){ - switch(t_120[0]){ - case 'RBNode': - switch(t_120[4][0]){ - case 'RBNode': - switch(t_120[4][4][0]){ - case 'RBNode': - switch(t_120[4][4][1][0]){ - case 'Red': - return true; - }break; - }break; - }break; - } - return false;}();} - function isRedRight_24(t_121){ - return function(){ - switch(t_121[0]){ - case 'RBNode': - switch(t_121[5][0]){ - case 'RBNode': - switch(t_121[5][1][0]){ - case 'Red': - return true; - }break; - }break; - } - return false;}();} - function isRedRightLeft_25(t_122){ - return function(){ - switch(t_122[0]){ - case 'RBNode': - switch(t_122[5][0]){ - case 'RBNode': - switch(t_122[5][4][0]){ - case 'RBNode': - switch(t_122[5][4][1][0]){ - case 'Red': - return true; - }break; - }break; - }break; - } - return false;}();} - function moveRedLeft_26(t_123){ - return function(){ - var t__124=color_flip_15(t_123); - return function(){ - switch(t__124[0]){ - case 'RBNode': - return function(){ - switch(t__124[5][0]){ - case 'RBNode': - switch(t__124[5][4][0]){ - case 'RBNode': - switch(t__124[5][4][1][0]){ - case 'Red': - return color_flip_15(rotateLeft_10(RBNode_2(t__124[1])(t__124[2])(t__124[3])(t__124[4])(rotateRight_11(t__124[5])))); - }break; - }break; - } - return t__124;}(); - } - return t__124;}();}();} - function moveRedRight_27(t_130){ - return function(){ - var t__131=color_flip_15(t_130); - return (isRedLeftLeft_23(t__131)?color_flip_15(rotateRight_11(t__131)):t__131);}();} - function moveRedLeftIfNeeded_28(t_132){ - return ((not(isRedLeft_22(t_132))&¬(isRedLeftLeft_23(t_132)))?moveRedLeft_26(t_132):t_132);} - function moveRedRightIfNeeded_29(t_133){ - return ((not(isRedRight_24(t_133))&¬(isRedRightLeft_25(t_133)))?moveRedRight_27(t_133):t_133);} - function deleteMin_30(t_134){ - return function(){ - function del_135(t_136){ - return function(){ - switch(t_136[0]){ - case 'RBNode': - switch(t_136[4][0]){ - case 'RBEmpty': - return RBEmpty_3; - }break; - } - return function(){ - var case198=moveRedLeftIfNeeded_28(t_136); - switch(case198[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return fixUp_17(RBNode_2(case198[1])(case198[2])(case198[3])(del_135(case198[4]))(case198[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();}();} - return ensureBlackRoot_18(del_135(t_134));}();} - function remove_31(k_142){ - return function(t_143){ - return function(){ - function eq_and_noRightNode_144(t_150){ - return function(){ - switch(t_150[0]){ - case 'RBNode': - switch(t_150[5][0]){ - case 'RBEmpty': - return eq(k_142,t_150[2]); - }break; - } - return false;}();} - function eq_145(t_152){ - return function(){ - switch(t_152[0]){ - case 'RBNode': - return eq(k_142,t_152[2]); - } - return false;}();} - function delLT_146(t_154){ - return function(){ - var case216=moveRedLeftIfNeeded_28(t_154); - switch(case216[0]){ - case 'RBEmpty': - throw 'delLT on RBEmpty'; - case 'RBNode': - return fixUp_17(RBNode_2(case216[1])(case216[2])(case216[3])(del_149(case216[4]))(case216[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function delEQ_147(t_160){ - return function(){ - switch(t_160[0]){ - case 'RBEmpty': - throw 'delEQ called on a RBEmpty'; - case 'RBNode': - return function(){ - var Tuple2$k_v__164=min_6(t_160[5]); - var k__165=function(){ - switch(Tuple2$k_v__164[0]){ - case 'Tuple2': - return Tuple2$k_v__164[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var v__166=function(){ - switch(Tuple2$k_v__164[0]){ - case 'Tuple2': - return Tuple2$k_v__164[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return fixUp_17(RBNode_2(t_160[1])(k__165)(v__166)(t_160[4])(deleteMin_30(t_160[5])));}(); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function delGT_148(t_171){ - return function(){ - switch(t_171[0]){ - case 'RBEmpty': - throw 'delGT called on a RBEmpty'; - case 'RBNode': - return fixUp_17(RBNode_2(t_171[1])(t_171[2])(t_171[3])(t_171[4])(del_149(t_171[5]))); - } - throw new Error("Non-exhaustive pattern match in case");}();} - function del_149(t_177){ - return function(){ - switch(t_177[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return ((compare(k_142)(t_177[2])[0] === 'LT')?delLT_146(t_177):function(){ - var u_179=(isRedLeft_22(t_177)?rotateRight_11(t_177):t_177); - return (eq_and_noRightNode_144(u_179)?u_179[4]:function(){ - var t__180=moveRedRightIfNeeded_29(t_177); - return (eq_145(t__180)?delEQ_147(t__180):delGT_148(t__180));}());}()); - } - throw new Error("Non-exhaustive pattern match in case");}();} - return (member_9(k_142)(t_143)?ensureBlackRoot_18(del_149(t_143)):t_143);}();};} - function map_32(f_181){ - return function(t_182){ - return function(){ - switch(t_182[0]){ - case 'RBEmpty': - return RBEmpty_3; - case 'RBNode': - return RBNode_2(t_182[1])(t_182[2])(f_181(t_182[3]))(map_32(f_181)(t_182[4]))(map_32(f_181)(t_182[5])); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function foldl_33(f_188){ - return function(acc_189){ - return function(t_190){ - return function(){ - switch(t_190[0]){ - case 'RBEmpty': - return acc_189; - case 'RBNode': - return foldl_33(f_188)(f_188(t_190[2])(t_190[3])(foldl_33(f_188)(acc_189)(t_190[4])))(t_190[5]); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function foldr_34(f_195){ - return function(acc_196){ - return function(t_197){ - return function(){ - switch(t_197[0]){ - case 'RBEmpty': - return acc_196; - case 'RBNode': - return foldr_34(f_195)(f_195(t_197[2])(t_197[3])(foldr_34(f_195)(acc_196)(t_197[5])))(t_197[4]); - } - throw new Error("Non-exhaustive pattern match in case");}();};};} - function union_35(t1_202){ - return function(t2_203){ - return foldl_33(insert_19)(t2_203)(t1_202);};} - function intersect_36(t1_204){ - return function(t2_205){ - return foldl_33(function(k_206){ - return function(v_207){ - return function(t_208){ - return (member_9(k_206)(t2_205)?insert_19(k_206)(v_207)(t_208):t_208);};};})(empty_4)(t1_204);};} - function diff_37(t1_209){ - return function(t2_210){ - return foldl_33(function(k_211){ - return function(v_212){ - return function(t_213){ - return remove_31(k_211)(t_213);};};})(t1_209)(t2_210);};} - function keys_38(t_214){ - return foldr_34(function(k_215){ - return function(v_216){ - return function(acc_217){ - return ['Cons',k_215,acc_217];};};})(['Nil'])(t_214);} - function values_39(t_218){ - return foldr_34(function(k_219){ - return function(v_220){ - return function(acc_221){ - return ['Cons',v_220,acc_221];};};})(['Nil'])(t_218);} - function toList_40(t_222){ - return foldr_34(function(k_223){ - return function(v_224){ - return function(acc_225){ - return ['Cons',['Tuple2',k_223,v_224],acc_225];};};})(['Nil'])(t_222);} - function fromList_41(assocs_226){ - return Elm.List.foldl(uncurry(insert_19))(empty_4)(assocs_226);} - var empty_4=RBEmpty_3; - return {$op : {}, - empty:empty_4, - lookup:lookup_7, - findWithDefault:findWithDefault_8, - member:member_9, - insert:insert_19, - singleton:singleton_20, - remove:remove_31, - map:map_32, - foldl:foldl_33, - foldr:foldr_34, - union:union_35, - intersect:intersect_36, - diff:diff_37, - keys:keys_38, - values:values_39, - toList:toList_40, - fromList:fromList_41};}(); - -Elm.Set=function(){ - var empty_0=Elm.Dict.empty; - var remove_3=Elm.Dict.remove; - var member_4=Elm.Dict.member; - var union_5=Elm.Dict.union; - var intersect_6=Elm.Dict.intersect; - var diff_7=Elm.Dict.diff; - var toList_8=Elm.Dict.keys; - var fromList_9=Elm.List.foldl(function(k_15){ - return function(t_16){ - return Elm.Dict.insert(k_15)(["Tuple0"])(t_16);};})(empty_0); - function singleton_1(k_13){ - return Elm.Dict.singleton(k_13)(["Tuple0"]);}; - function insert_2(k_14){ - return Elm.Dict.insert(k_14)(["Tuple0"]);}; - function foldl_10(f_17){ - return Elm.Dict.foldl(function(k_18){ - return function(v_19){ - return function(b_20){ - return f_17(k_18)(b_20);};};});}; - function foldr_11(f_21){ - return Elm.Dict.foldr(function(k_22){ - return function(v_23){ - return function(b_24){ - return f_21(k_22)(b_24);};};});}; - function map_12(f_25){ - return function(t_26){ - return function(x){ - return fromList_9(Elm.List.map(f_25)(x));}(toList_8(t_26));};}; - return {empty:empty_0,singleton:singleton_1,insert:insert_2,remove:remove_3,member:member_4,union:union_5,intersect:intersect_6,diff:diff_7,toList:toList_8,fromList:fromList_9,foldl:foldl_10,foldr:foldr_11,map:map_12};}(); - -(function() { -try{ - -var $op={}; -for(this['i'] in Elm){eval('var '+this['i']+'=Elm[this.i];');} -if (Elm.Automaton) throw new Error("Module name collision, 'Automaton' is already defined."); -Elm.Automaton=function(){ - try{ - if (!(Elm.Prelude instanceof Object)) throw 'module not found'; - } catch(e) { - throw ("Module 'Prelude' is missing. Compile with --make flag or load missing module in a separate JavaScript file."); - } - var hiddenVars={}; - for (this['i'] in Elm.Prelude) { - if (hiddenVars[this['i']]) continue; - eval('var ' + this['i'] + ' = Elm.Prelude[this.i];');} - function Automaton_0(a1){ - return ["Automaton",a1];} - var Listen_8=["Listen"]; - var Ignore_9=["Ignore"]; - function DragFrom_10(a1){ - return ["DragFrom",a1];} - $op['>>>'] = function(a1_24){ - return function(a2_25){ - return function(){ - var Automaton$m1_26=a1_24; - var m1_27=function(){ - switch(Automaton$m1_26[0]){ - case "Automaton": - return Automaton$m1_26[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var Automaton$m2_28=a2_25; - var m2_29=function(){ - switch(Automaton$m2_28[0]){ - case "Automaton": - return Automaton$m2_28[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return Automaton_0(function(a_32){ - return function(){ - var Tuple2$bm1__33=m1_27(a_32); - var b_34=function(){ - switch(Tuple2$bm1__33[0]){ - case "Tuple2": - return Tuple2$bm1__33[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var m1__35=function(){ - switch(Tuple2$bm1__33[0]){ - case "Tuple2": - return Tuple2$bm1__33[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return function(){ - var Tuple2$cm2__40=m2_29(b_34); - var c_41=function(){ - switch(Tuple2$cm2__40[0]){ - case "Tuple2": - return Tuple2$cm2__40[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var m2__42=function(){ - switch(Tuple2$cm2__40[0]){ - case "Tuple2": - return Tuple2$cm2__40[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",c_41,$op['>>>'](m1__35)(m2__42)];}();}();});}();};}; - $op['<<<'] = function(a2_47){ - return function(a1_48){ - return $op['>>>'](a1_48)(a2_47);};}; - $op['^>>'] = function(f_49){ - return function(a_50){ - return $op['>>>'](pure_4(f_49))(a_50);};}; - $op['>>^'] = function(a_51){ - return function(f_52){ - return $op['>>>'](a_51)(pure_4(f_52));};}; - $op['^<<'] = function(f_53){ - return function(a_54){ - return $op['>>>'](a_54)(pure_4(f_53));};}; - $op['<<^'] = function(a_55){ - return function(f_56){ - return $op['>>>'](pure_4(f_56))(a_55);};}; - var count_7=init_5(0)(function(__84){ - return function(c_85){ - return (1+c_85);};}); - function run_1(Automaton$m0_14){ - return function(input_15){ - return function(){ - switch(Automaton$m0_14[0]){ - case "Automaton": - return lift(fst)(foldp$(function(a_17){ - return function(Tuple2$bAutomaton$m_18){ - return function(){ - switch(Tuple2$bAutomaton$m_18[0]){ - case "Tuple2": - switch(Tuple2$bAutomaton$m_18[2][0]){ - case "Automaton": - return Tuple2$bAutomaton$m_18[2][1](a_17); - }break; - } - throw new Error("Non-exhaustive pattern match in case");}();};})(Automaton$m0_14[1])(input_15)); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function step_2(Automaton$m_21){ - return function(a_22){ - return function(){ - switch(Automaton$m_21[0]){ - case "Automaton": - return Automaton$m_21[1](a_22); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function combine_3(autos_57){ - return Automaton_0(function(a_58){ - return function(){ - var Tuple2$bsautos__59=unzip(map(function(Automaton$m_62){ - return function(){ - switch(Automaton$m_62[0]){ - case "Automaton": - return Automaton$m_62[1](a_58); - } - throw new Error("Non-exhaustive pattern match in case");}();})(autos_57)); - var bs_60=function(){ - switch(Tuple2$bsautos__59[0]){ - case "Tuple2": - return Tuple2$bsautos__59[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var autos__61=function(){ - switch(Tuple2$bsautos__59[0]){ - case "Tuple2": - return Tuple2$bsautos__59[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",bs_60,combine_3(autos__61)];}();});} - function pure_4(f_68){ - return Automaton_0(function(x_69){ - return ["Tuple2",f_68(x_69),pure_4(f_68)];});} - function init_5(s_70){ - return function(step_71){ - return Automaton_0(function(a_72){ - return function(){ - var s__73=step_71(a_72)(s_70); - return ["Tuple2",s__73,init_5(s__73)(step_71)];}();});};} - function init__6(s_74){ - return function(step_75){ - return Automaton_0(function(a_76){ - return function(){ - var Tuple2$bs__77=step_75(a_76)(s_74); - var b_78=function(){ - switch(Tuple2$bs__77[0]){ - case "Tuple2": - return Tuple2$bs__77[1]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - var s__79=function(){ - switch(Tuple2$bs__77[0]){ - case "Tuple2": - return Tuple2$bs__77[2]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - return ["Tuple2",b_78,init__6(s__79)(step_75)];}();});};} - function vecSub_11(Tuple2$x1y1_86){ - return function(Tuple2$x2y2_87){ - return function(){ - switch(Tuple2$x1y1_86[0]){ - case "Tuple2": - return function(){ - switch(Tuple2$x2y2_87[0]){ - case "Tuple2": - return ["Tuple2",(Tuple2$x1y1_86[1]-Tuple2$x2y2_87[1]),(Tuple2$x1y1_86[2]-Tuple2$x2y2_87[2])]; - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function stepDrag_12(Tuple2$presspos_92){ - return function(Tuple2$dsform_93){ - return function(){ - switch(Tuple2$presspos_92[0]){ - case "Tuple2": - return function(){ - switch(Tuple2$dsform_93[0]){ - case "Tuple2": - return function(){ - function wrap_98(ds__99){ - return ["Tuple2",Tuple2$dsform_93[2],["Tuple2",ds__99,Tuple2$dsform_93[2]]];} - return function(){ - switch(Tuple2$dsform_93[1][0]){ - case "DragFrom": - return (Tuple2$presspos_92[1]?["Tuple2",uncurry(move)(vecSub_11(Tuple2$presspos_92[2])(Tuple2$dsform_93[1][1]))(Tuple2$dsform_93[2]),["Tuple2",DragFrom_10(Tuple2$dsform_93[1][1]),Tuple2$dsform_93[2]]]:function(){ - var form__101=uncurry(move)(vecSub_11(Tuple2$presspos_92[2])(Tuple2$dsform_93[1][1]))(Tuple2$dsform_93[2]); - return ["Tuple2",form__101,["Tuple2",Listen_8,form__101]];}()); - case "Ignore": - return wrap_98((Tuple2$presspos_92[1]?Ignore_9:Listen_8)); - case "Listen": - return wrap_98((not(Tuple2$presspos_92[1])?Listen_8:(isWithin(Tuple2$presspos_92[2])(Tuple2$dsform_93[2])?DragFrom_10(Tuple2$presspos_92[2]):Ignore_9))); - } - throw new Error("Non-exhaustive pattern match in case");}();}(); - } - throw new Error("Non-exhaustive pattern match in case");}(); - } - throw new Error("Non-exhaustive pattern match in case");}();};} - function draggable_13(form_102){ - return init__6(["Tuple2",Listen_8,form_102])(stepDrag_12);} - return {$op : {'>>>' : $op['>>>'], '<<<' : $op['<<<'], '^>>' : $op['^>>'], '>>^' : $op['>>^'], '^<<' : $op['^<<'], '<<^' : $op['<<^']}, - run:run_1, - step:step_2, - combine:combine_3, - pure:pure_4, - init:init_5, - init$:init__6, - count:count_7, - draggable:draggable_13};}(); -Elm.main=function(){ - return Elm.Automaton.main;}; -} catch (e) { -Elm.main=function() { -var msg = ('<br/><h2>Your browser may not be supported. Are you using a modern browser?</h2>' + '<br/><span style="color:grey">Runtime Error in Automaton module:<br/>' + e + '</span>'); -document.body.innerHTML = Elm.Text.monospace(msg);throw e;};}}()); \ No newline at end of file diff --git a/elm/elm-runtime-0.7.js b/elm/elm-runtime-0.7.js deleted file mode 100644 index 539c9fc..0000000 --- a/elm/elm-runtime-0.7.js +++ /dev/null @@ -1,135 +0,0 @@ -Elm={};var Guid=function(){var e=0;return{guid:function(){return e+=1}}}(); -Elm.JavaScript=function(){function e(b){for(var a=["Nil"],m=b.length;m--;)a=["Cons",b[m],a];return a}function k(b){for(var a=[];"Cons"===b[0];)a.push(b[1]),b=b[2];return a}function b(b){return b.slice(1)}function d(b){return["Tuple"+b.length].concat(b)}return{castJSBoolToBool:function(b){return b},castBoolToJSBool:function(b){return b},castJSNumberToFloat:function(b){return b},castFloatToJSNumber:function(b){return b},castJSNumberToInt:function(b){return~~b},castIntToJSNumber:function(b){return b}, -Experimental:{castJSElementToElement:function(b){return function(a){return function(m){return["Element",Guid.guid(),["EExternalHtml",m],b,a,1,["Nothing"],["Nothing"]]}}},castElementToJSElement:function(b){return Render.render(b)}},castJSArrayToList:e,castListToJSArray:k,castJSStringToString:e,castStringToJSString:function(b){return"string"===typeof b?b:k(b).join("")},castTupleToJSTuple2:b,castTupleToJSTuple3:b,castTupleToJSTuple4:b,castTupleToJSTuple5:b,castJSTupleToTuple2:d,castJSTupleToTuple3:d, -castJSTupleToTuple4:d,castJSTupleToTuple5:d}}();var JSjson=window.JSON; -Elm.JSON=function(){function e(a,b){return function(g){return function(l){var h=d.castStringToJSString(g);return l[1].hasOwnProperty(h)&&(l=l[1][h],l[0]===a)?l[1]:b}}}function k(a){return function(b){function g(a){switch(a[0]){case "JsonNull":return null;case "JsonString":return d.castStringToJSString(a[1]);case "JsonObject":var h={};a=a[1][1];for(var c in a)h[c]=g(a[c]);return h;case "JsonArray":h=d.castListToJSArray(a[1]);for(c=h.length;c--;)h[c]=g(h[c]);return h;default:return a[1]}}return JSjson.stringify(g(["JsonObject", -b]),null,d.castStringToJSString(a))}}function b(a){function b(a){switch(typeof a){case "string":return["JsonString",d.castJSStringToString(a)];case "number":return["JsonNumber",d.castJSNumberToFloat(a)];case "boolean":return["JsonBool",d.castJSBoolToBool(a)];case "object":if(null===a)return["JsonNull"];for(var h in a)a[h]=b(a[h]);return a instanceof Array?["JsonArray",d.castJSArrayToList(a)]:["JsonObject",["JSON",a]]}}a=JSjson.parse(a);for(var g in a)a[g]=b(a[g]);return["JSON",a]}var d=Elm.JavaScript, -j=["JSON",{}];return{empty:j,singleton:function(a){return function(b){var g={};g[d.castStringToJSString(a)]=b;return["JSON",g]}},insert:function(a){return function(b){return function(g){g=g[1];var l={},h;for(h in g)l[h]=g[h];l[d.castStringToJSString(a)]=b;return["JSON",l]}}},lookup:function(a){return function(b){var g=d.castStringToJSString(a);return b[1].hasOwnProperty(g)?["Just",b[1][g]]:["Nothing"]}},findString:e("JsonString",["Nil"]),findObject:e("JsonObject",j),findArray:e("JsonArray",["Nil"]), -findWithDefault:function(a){return function(b){return function(g){var l=d.castStringToJSString(b);return g[1].hasOwnProperty(l)?g[1][l]:a}}},remove:function(a){return function(b){b=b[1];var g={},l;for(l in b)g[l]=b[l];delete g[d.castStringToJSString(a)];return["JSON",g]}},toPrettyJSString:k,toJSString:k(""),fromJSString:b,toPrettyString:function(a){return function(b){return d.castJSStringToString(k(a)(b))}},toString:function(a){return d.castJSStringToString(k("")(a))},fromString:function(a){return b(d.castStringToJSString(a))}, -toList:function(a){a=a[1];var b=[],g;for(g in a)b.push(Value.Tuple(d.castJSStringToString(g),a[g]));return d.castJSArrayToList(b)},fromList:function(a){a=d.castListToJSArray(a);for(var b={},g=a.length;g--;)b[d.castStringToJSString(a[g][1])]=a[g][2];return["JSON",b]},JsonString:function(a){return["JsonString",a]},JsonNumber:function(a){return["JsonNumber",a]},JsonBool:function(a){return["JsonBool",a]},JsonNull:["JsonNull"],JsonArray:function(a){return["JsonArray",a]},JsonObject:function(a){return["JsonObject", -a]}}}(); -var Value=function(){function e(a){if(0==a.length)return a;a=a.replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br/>");a=a.split("<br/>");for(var b=a.length;b--;){var g=a,d=b,h;h=a[b];if(0!=h.length){h=h.split("");" "==h[0]&&(h[0]=" ");for(var c=h.length;--c;)" "==h[c][0]&&" "==h[c-1]&&(h[c-1]+=h[c],h[c]="");for(c=h.length;c--;)if(1<h[c].length&&" "==h[c][0]){for(var f=h[c].split(""),v=f.length-2;0<=v;v-=2)f[v]=" ";h[c]=f.join("")}h=h.join(""); -h=" "===h[h.length-1]?h.slice(0,-1)+" ":h}g[d]=h}return a.join("<br/>")}var k=function(a,b){if("object"===typeof a){if(a.hasOwnProperty("_")){for(var g in a)if(a[g]!=b[g])return!1;for(g in b)if(a[g]!=b[g])return!1;return!0}if(a===b)return!0;if(a.length!==b.length)return!1;for(g=a.length;g--;)if(!k(a[g],b[g]))return!1;return!0}return a===b},b=function(a){if("function"===typeof a)return"<function>";if("boolean"===typeof a)return a?"True":"False";if("number"!==typeof a){if("string"===typeof a&& -2>a.length)return"'"+a+"'";if("object"===typeof a&&a.hasOwnProperty("_")){var d=[],g;for(g in a)if("_"!=g)for(var l=a[g].length;l--;)d.push(g+" = "+b(a[g][l]));return 0===d.length?"{}":"{ "+d.join(", ")+" }"}if(a[0]){if("Tuple"===a[0].substring(0,5)){d=Array(a.length-1);for(l=a.length;--l;)d[l-1]=b(a[l]);return"("+d.join(",")+")"}if("Cons"===a[0]){g="string"===typeof a[1]?'"':"]";var l="string"===typeof a[1]?"":",",h="string"===typeof a[1]?function(a){return a}:b,d=("string"===typeof a[1]?'"':"[")+ -h(a[1]);for(a=a[2];;)if("Cons"===a[0])d+=l+h(a[1]),a=a[2];else return d+g}else{if("Nil"===a[0])return"[]";if("JSON"===a[0])return"(JSON.fromList "+b(Elm.JSON.toList(a))+")";if("RBNode"===a[0]||"RBEmpty"===a[0])return a=Elm.Dict.foldr(function(a){return function(b){return function(h){return["Cons",["Tuple2",a,b],h]}}})(["Nil"])(a),d="Dict","Cons"===a[0]&&"Tuple0"===a[1][2][0]&&(d="Set",a=Elm.List.map(function(a){return a[1]})(a)),"("+d+".fromList "+b(a)+")";d=[];for(l=a.length;--l;)d.push(b(a[l])); -d=a[0]+" "+d.join(" ");return 1<a.length?"("+d+")":d}}}return a+""},d=function(a){for(var b=["Nil"],d=a.length;d--;)b=["Cons",a[d],b];return b},j;j=document.addEventListener?function(a,b,d){a.addEventListener(b,d,!1)}:function(a,b,d){a.attachEvent("on"+b,d)};return{eq:k,str:d,show:function(a){return d(b(a))},Tuple:function(){var a=arguments.length,b=Array(a+1);for(b[0]="Tuple"+arguments.length;a--;)b[a+1]=arguments[a];return b},append:function(a,b){if("string"===typeof a&&"string"===typeof b)return a.concat(b); -if("Nil"===a[0])return b;var d=["Cons",a[1],["Nil"]],l=d;for(a=a[2];"Cons"===a[0];)l[2]=["Cons",a[1],["Nil"]],a=a[2],l=l[2];l[2]=b;return d},listToArray:function(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b},toText:function(a){if("string"===typeof a)return e(a);for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return e(b.join(""))},properEscape:e,getTextSize:function(a,b,d){var l=document.createElement("div");l.innerHTML=d;l.style.textAlign="left";0<a&&(l.style.width=a+"px");l.style.visibility= -"hidden";l.style.styleFloat="left";l.style.cssFloat="left";document.body.appendChild(l);d=window.getComputedStyle(l,null);a=d.getPropertyValue("width").slice(0,-2)-0;d=d.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(l);return[Math.ceil(a),Math.ceil(Math.max(b,d))]},getSize:function(a){a=a.cloneNode(!0);a.style.visibility="hidden";a.style.styleFloat="left";a.style.cssFloat="left";document.body.appendChild(a);var b=a.offsetWidth,d=a.offsetHeight;document.body.removeChild(a);return[b, -d]},getExcess:function(b){b=b.cloneNode(!0);b.style.visibility="hidden";b.style.styleFloat="left";b.style.cssFloat="left";document.body.appendChild(b);var d=b.offsetWidth,g=b.offsetHeight,l=window.getComputedStyle(b,null),h=l.getPropertyValue("width").slice(0,-2)-0,l=l.getPropertyValue("height").slice(0,-2)-0;document.body.removeChild(b);return[d-h,g-l]},groupForms:function(b){b=Elm.JavaScript.castListToJSArray(b);for(var d=[],g=[],l=b.length;l--;){var h=b[l];switch(h[4][0]){case "FElement":0<g.length&& -(d.push(g),g=[]);d.push(h);break;default:g.push(h)}}0<g.length&&d.push(g);return d},wrap:function(b){var d=Value.getSize(b);return["Element",Guid.guid(),["EHtml",b],d[0],d[1],1,["Nothing"],["Nothing"]]},addListener:j}}(); -Elm.List=function(){function e(b){return function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&h("map");var c=["Cons",b(a[1]),["Nil"]],f=c;for(a=a[2];"Cons"===a[0];)f[2]=["Cons",b(a[1]),["Nil"]],a=a[2],f=f[2];return c}}function k(b){return function(a){return function(c){var f=a;if("Nil"===c[0])return f;for("Cons"!==c[0]&&h("foldl");"Cons"===c[0];)f=b(c[1])(f),c=c[2];return f}}}function b(b){return function(a){return function(c){var f=a;if("Nil"===c[0])return f;"Cons"!==c[0]&&h("foldr");for(var d=[];"Cons"=== -c[0];)d.push(c[1]),c=c[2];for(c=d.length;c--;)f=b(d[c])(f);return f}}}function d(b){return function(a){var h;"Cons"!==a[0]?h=void 0:(h=a[1],a=a[2],h=k(b)(h)(a));return h}}function j(b){return function(a){return function(c){if("Nil"===c[0])return["Cons",a,["Nil"]];"Cons"!==c[0]&&h("scanl");for(var f=[a];"Cons"===c[0];)a=b(c[1])(a),f.push(a),c=c[2];c=["Nil"];for(var d=f.length;d--;)c=["Cons",f[d],c];return c}}}function a(b){return function(h){a:{for(var c=[function(b){return"Nil"!==b[0]?void 0:["Tuple2", -["Nil"],["Nil"]]},function(h){if("Cons"===h[0]){var c=h[1];h=h[2];var f=a(b)(h);"Tuple2"!==f[0]?c=void 0:(h=f[1],f=f[2],c=b(c)?["Tuple2",["Cons",c,h],f]:["Tuple2",h,["Cons",c,f]]);return c}}],f=c.length;f--;){var d=c[f](h);if(void 0!==d){h=d;break a}}h=void 0}return h}}function m(b){a:{for(var a=[function(b){return"Nil"!==b[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(b){if("Cons"!==b[0])b=void 0;else if(b=["Tuple2",b[1],m(b[2])],"Tuple2"!==b[0]||"Tuple2"!==b[1][0])b=void 0;else{var a=b[1][1],h= -b[1][2];b="Tuple2"!==b[2][0]?void 0:["Tuple2",["Cons",a,b[2][1]],["Cons",h,b[2][2]]]}return b}],h=a.length;h--;){var c=a[h](b);if(void 0!==c){b=c;break a}}b=void 0}return b}function g(b){return function(a){a:{for(var h=[function(b){return"Nil"!==b[0]?void 0:["Nil"]},function(b){if("Cons"===b[0]){var a=b[1];return"Nil"!==b[2][0]?void 0:["Cons",a,["Nil"]]}},function(a){if("Cons"===a[0]){var h=a[1];if("Cons"===a[2][0]){var c=a[2][1];a=a[2][2];return["Cons",h,["Cons",b,g(b)(["Cons",c,a])]]}}}],c=h.length;c--;){var f= -h[c](a);if(void 0!==f){a=f;break a}}a=void 0}return a}}function l(b){return function(a){a:{for(var h=[function(b){return"Nil"!==b[0]?void 0:["Nil"]},function(b){if("Cons"===b[0]){var a=b[1];return"Nil"!==b[2][0]?void 0:a}},function(a){if("Cons"===a[0]){var h=a[1];if("Cons"===a[2][0]){var c=a[2][1];a=a[2][2];return Value.append(h,Value.append(b,l(b)(["Cons",c,a])))}}}],c=h.length;c--;){var f=h[c](a);if(void 0!==f){a=f;break a}}a=void 0}return a}}var h=function(b){throw"Function '"+b+"' expecting a list!"; -},c=k(function(b){return function(a){return["Cons",b,a]}})(["Nil"]),f=b(function(b){return function(a){return Value.append(b,a)}})(["Nil"]),v=k(function(b){return function(a){return b&&a}})(!0),n=k(function(b){return function(a){return b||a}})(!1),p=k(function(b){return function(a){return b+a}})(0),r=k(function(b){return function(a){return b*a}})(1),y=d(function(b){return function(a){return Math.max(b,a)}}),s=d(function(b){return function(a){return Math.min(b,a)}});return{head:function(b){if("Cons"!== -b[0])throw"Error: 'head' only accepts lists of length greater than one.";return b[1]},tail:function(b){if("Cons"!==b[0])throw"Error: 'tail' only accepts lists of length greater than one.";return b[2]},last:function(b){if("Cons"!==b[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var a=b[1];"Cons"===b[0];)a=b[1],b=b[2];return a},map:e,foldl:k,foldr:b,foldl1:d,foldr1:function(b){return function(a){if("Nil"===a[0])throw"'foldr1' requires an non-empty list.";"Cons"!==a[0]&& -h("foldr1");for(var c=[];"Cons"===a[0];)c.push(a[1]),a=a[2];a=c.pop();for(var f=c.length;f--;)a=b(c[f])(a);return a}},scanl:j,scanl1:function(b){return function(a){if("Cons"!==a[0])throw"Error: 'scanl1' requires a list of at least length 1.";return j(b)(a[1])(a[2])}},filter:function(b){return function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&h("filter");for(var c=[];"Cons"===a[0];)b(a[1])&&c.push(a[1]),a=a[2];a=["Nil"];for(var f=c.length;f--;)a=["Cons",c[f],a];return a}},length:function(b){for(var a= -0;"Cons"===b[0];)a+=1,b=b[2];return a},reverse:c,concat:f,concatMap:function(b){return function(a){return f(e(b)(a))}},and:v,or:n,all:function(b){return k(function(a){return function(h){return h&&b(a)}})(!0)},any:function(b){return k(function(a){return function(h){return h||b(a)}})(!1)},sum:p,product:r,maximum:y,minimum:s,partition:a,zipWith:function(b){return function(a){return function(c){if("Nil"===a[0]||"Nil"===c[0])return["Nil"];("Cons"!==a[0]||"Cons"!==c[0])&&h("zipWith");for(var f=[];"Cons"=== -a[0]&&"Cons"===c[0];)f.push(b(a[1])(c[1])),a=a[2],c=c[2];c=["Nil"];for(var d=f.length;d--;)c=["Cons",f[d],c];return c}}},zip:function(b){return function(a){if("Nil"===b[0]||"Nil"===a[0])return["Nil"];("Cons"!==b[0]||"Cons"!==a[0])&&h("zip");for(var c=[];"Cons"===b[0]&&"Cons"===a[0];)c.push(["Tuple2",b[1],a[1]]),b=b[2],a=a[2];a=["Nil"];for(var f=c.length;f--;)a=["Cons",c[f],a];return a}},unzip:m,intersperse:g,intercalate:l,sort:function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&h("sort");for(var a= -[];"Cons"===b[0];)a.push(b[1]),b=b[2];a.sort(function(b,a){return b-a});b=["Nil"];for(var c=a.length;c--;)b=["Cons",a[c],b];return b},take:function(b){return function(a){if(0>=b)return["Nil"];if("Nil"===a[0])return a;"Cons"!==a[0]&&h("take");var c=["Cons",a[1],["Nil"]],f=c;a=a[2];for(--b;"Cons"===a[0]&&0<b;)f[2]=["Cons",a[1],["Nil"]],f=f[2],a=a[2],--b;return c}},drop:function(b){return function(a){if("Nil"===a[0])return a;for("Cons"!==a[0]&&h("drop");"Cons"===a[0]&&0<b;)a=a[2],--b;return a}}}}(); -Elm.Maybe=function(){function e(b){return function(d){return"Just"===b[0]?["Cons",b[1],d]:d}}function k(b){return function(d){return function(j){var a=b(d);return"Just"===a[0]?["Cons",a[1],j]:j}}}return{Just:function(b){return["Just",b]},Nothing:["Nothing"],catMaybes:Elm.List.foldr(e)(["Nil"]),isJust:function(b){return"Just"===b[0]},isNothing:function(b){return"Nothing"===b[0]},fromMaybe:function(b){return function(d){return"Just"===d[0]?d[1]:b}},consMaybe:e,mapMaybe:function(b){return Elm.List.foldr(k(b))(["Nil"])}, -maybe:function(b){return function(d){return function(j){return"Just"===j[0]?d(j[1]):b}}}}}(); -Elm.Char=function(){function e(b,a){return function(d){d=d.charCodeAt(0);return b<=d&&d<=a}}var k=e(48,57),b=e(97,102),d=e(65,70);return{fromCode:function(b){return String.fromCharCode(b)},toCode:function(b){return b.charCodeAt(0)},toUpper:function(b){return b.toUpperCase()},toLower:function(b){return b.toLowerCase()},toLocaleUpper:function(b){return b.toLocaleUpperCase()},toLocaleLower:function(b){return b.toLocaleLowerCase()},isLower:e(97,122),isUpper:e(65,90),isDigit:k,isOctDigit:e(48,55),isHexDigit:function(e){return k(e)|| -b(e)||d(e)}}}(); -Elm.Color=function(){function e(e){var b=e.value*e.saturation,d=e.hue/60,j=b*(1-Math.abs(d%2-1)),a=0,m=0,g=0;0<=d&&1>d?(a=b,m=j,g=0):1<=d&&2>d?(a=j,m=b,g=0):2<=d&&3>d?(a=0,m=b,g=j):3<=d&&4>d?(a=0,m=j,g=b):4<=d&&5>d?(a=j,m=0,g=b):5<=d&&6>d&&(a=b,m=0,g=j);e=e.value-b;return["Color",Math.round(255*(a+e)),Math.round(255*(m+e)),Math.round(255*(g+e)),1]}return{rgba:function(e){return function(b){return function(d){return function(j){return["Color",e,b,d,j]}}}},rgb:function(e){return function(b){return function(d){return["Color",e, -b,d,1]}}},hsva:function(k){return function(b){return function(d){return function(j){var a=e({hue:k,saturation:b,value:d});a[4]=j;return a}}}},hsv:function(k){return function(b){return function(d){return e({hue:k,saturation:b,value:d})}}},red:["Color",255,0,0,1],green:["Color",0,255,0,1],blue:["Color",0,0,255,1],yellow:["Color",255,255,0,1],cyan:["Color",0,255,255,1],magenta:["Color",255,0,255,1],black:["Color",0,0,0,1],white:["Color",255,255,255,1],gray:["Color",128,128,128,1],grey:["Color",128,128, -128,1],complement:function(k){var b;b=k[1]/255;var d=k[2]/255;k=k[3]/255;var j=Math.max(b,d,k),a=Math.min(b,d,k),a=j-a,m=0;0===a?m=0:j===b?m=(d-k)/a%6:j===d?m=(k-b)/a+2:j===k&&(m=(b-d)/a+4);b={value:j,hue:60*m,saturation:0===j?0:a/j};b.hue=(b.hue+180)%360;return e(b)},extract:function(e){return 1===e[4]?"rgb("+e[1]+","+e[2]+","+e[3]+")":"rgba("+e[1]+","+e[2]+","+e[3]+","+e[4]+")"}}}(); -var Collage=function(){function e(b,a){var c=a.length-1;if(!(0>=c))for(b.moveTo(a[c][1],a[c][2]);c--;)b.lineTo(a[c][1],a[c][2])}function k(b,a,c,f){0===b.length&&(b=[8,4]);var d=f.length-1;if(!(0>=d)){var n=f[d][1],g=f[d][2],e=0,j=0,k=0,m=0,q=0,t=0,w=b.length,A=!0,x=b[0];for(a.moveTo(n,g);d--;){e=f[d][1];j=f[d][2];k=e-n;m=j-g;for(q=Math.sqrt(k*k+m*m);x<=q;)n+=k*x/q,g+=m*x/q,a[A?"lineTo":"moveTo"](n,g),k=e-n,m=j-g,q=Math.sqrt(k*k+m*m),A=!A,t=(t+1)%w,x=b[t];0<q&&(a[A?"lineTo":"moveTo"](e,j),x-=q);n= -e;g=j}}a.strokeStyle=Elm.Color.extract(c);a.stroke()}function b(b,a,c,f,d){a.clearRect(0,0,c,f);for(c=d.length;c--;){var n=d[c],p=b;f=a;var j=n[1],m=n[2],s=n[3][1],u=n[3][2],n=n[4];f.save();(0!==s||0!==u)&&f.translate(s,u);j!==~~j&&f.rotate(2*Math.PI*j);1!==m&&f.scale(m,m);f.beginPath();switch(n[0]){case "FLine":a:switch(p=f,j=n,n=j[3][1],j[1][0]){case "Solid":j=j[2];e(p,n);p.strokeStyle=Elm.Color.extract(j);p.stroke();break;case "Dotted":k([3,3],p,j[2],n);break a;case "Dashed":k([8,4],p,j[2],n); -break a;case "Custom":k(j[1][1],p,j[2],n)}break;case "FShape":a:switch(s=p,m=f,p=n[1],j=n[2],n=n[3][1],p[0]){case "Filled":p=m;e(p,n);p.fillStyle=Elm.Color.extract(j);p.fill();break a;case "Outlined":p=m;e(p,n);p.strokeStyle=Elm.Color.extract(j);p.stroke();break a;case "Textured":j=s;p=p[1];s=new Image;s.src=g.castStringToJSString(p);s.onload=j;e(m,n);m.fillStyle=m.createPattern(s,"repeat");m.fill();break a;case "CustomOutline":k(p[1],m,j,n)}break;case "FImage":j=f,m=n[1],s=n[2],n=n[3],u=new Image, -u.onload=p,u.src=g.castStringToJSString(n),j.drawImage(u,-m/2,-s/2,m,s)}f.restore()}}function d(a,h,c){var f=Render.newElement("canvas");a=~~a;h=~~h;f.style.width=a+"px";f.style.height=h+"px";f.style.display="block";f.width=a;f.height=h;if(f.getContext){var d=f.getContext("2d");b(function(){b(this,d,a,h,c)},d,a,h,c);return f}f.innerHTML="Your browser does not support the canvas element.";return f}function j(b,a,c,f,d,n,g){var e=Render.render(g);c="translate("+(d-g[3]/2)+"px,"+(n-g[4]/2)+"px) "+(1=== -f?"":"scale("+f+","+f+")")+" "+(c===~~c?"":"rotate("+360*c+"deg)");e.style.transform=c;e.style.msTransform=c;e.style.MozTransform=c;e.style.webkitTransform=c;e.style.OTransform=c;c=Render.newElement("div");Render.addTo(c,e);c.style.width=~~b+"px";c.style.height=~~a+"px";c.style.overflow="hidden";return c}function a(a,h,c){if(!Value.eq(c,h)){var f=a.style.width.slice(0,-2)-0,g=a.style.height.slice(0,-2)-0;if("object"===typeof c[0]){if("object"===typeof h[0]&&a.getContext){var n=a.getContext("2d"); -return b(function(){b(this,n,f,g,c)},n,f,g,c)}h=d(f,g,c);h.style.position="absolute";return a.parentNode.replaceChild(h,a)}h=j(f,g,c[1],c[2],c[3][1],c[3][2],c[4][1]);h.style.position="absolute";return a.parentNode.replaceChild(h,a)}}function m(b,a,c,f,d){var g=0,e,j=(b[1]-f[1])/c;b=(b[2]-f[2])/c;0!==a&&(a*=-2*Math.PI,c=j*Math.cos(a)-b*Math.sin(a),b=j*Math.sin(a)+b*Math.cos(a),j=c);if(0===d.length)return!1;e=d[0];for(c=d.length-1;c--;){a=d[c];f=e[1];e=e[2];var k=a[1],m=a[2];if(e<m)var u=e,q=m;else u= -m,q=e;if(f<k)var t=f,w=k;else t=k,w=f;u<b&&b<=q&&j<=w&&(j<=t||j<=(b-e)*(k-f)/(m-e)+f)&&++g;e=a}return 1===g%2}var g=Elm.JavaScript;return{collage:function(b,a,c){if(0===c.length)return d(b,a,[]);for(var f=Array(c.length),e=c.length;e--;){var g=c[e];f[e]="string"===typeof g[0]?j(b,a,g[1],g[2],g[3][1],g[3][2],g[4][1]):d(b,a,g)}return 1===c.length?f[0]:Render.flowWith(Render.goIn,function(b){return b},f)},updateCollage:function(b,h,c){if(1===c.length)return a(b,h[0],c[0]);b=b.childNodes;for(var f=b.length, -d=f;d--;)a(b[f-d-1],h[d],c[d])},insideForm:function(b){return function(a){var c=b[1],f=b[2];if(6>a.length){var d=a[3][1],g=a[3][2],e=0,j=a[2];switch(a[4][0]){case "FShape":for(var k=a[4][3][1],s=k.length;--s;)var u=k[s],e=Math.max(e,u[1]*u[1]+u[2]*u[2]);e*=j*j;break;case "FImage":k=j*a[4][1]/2;j=j*a[4][2]/2;e=k*k+j*j;break;case "FElement":k=j*a[4][1][3]/2,j=j*a[4][1][4]/2,e=k*k+j*j}a.push(function(a,b){var c=a-d,h=b-g;return c*c+h*h<e+1})}if(!a[5](c,f))return!1;var q,t;switch(a[4][0]){case "FShape":return m(b, -a[1],a[2],a[3],a[4][3][1]);case "FLine":return!1;case "FImage":q=a[4][1]/2;t=a[4][2]/2;break;case "FElement":q=a[4][1][3]/2,t=a[4][1][4]/2}return m(b,a[1],a[2],a[3],[[null,q,t],[null,-q,t],[null,-q,-t],[null,q,-t],[null,q,t]])}}}}(); -Elm.Graphics=function(){function e(a){return function(b){return["Position",a,b]}}function k(a){return function(b){return["EText",a,b]}}function b(a){return function(b){return["EFlow",a,r.castListToJSArray(b)]}}function d(a){return["Line",r.castListToJSArray(a)]}function j(a){return function(b){var c=r.castListToJSArray(a);0<c.length&&c.push(c[0]);return["Shape",c,b]}}function a(a){return function(b){return function(c){return function(h){return["Form",a,b,c,h]}}}}function m(a){return function(b){return function(c){return["FLine", -a,b,c]}}}function g(a){return function(b){return function(c){return["FShape",a,b,c]}}}function l(a,b,c,h,f,d){return["Element",Guid.guid(),a,b,c,h,f,d]}function h(a,b,c){return["Element",Guid.guid(),a,b,c,1,["Nothing"],["Nothing"]]}function c(a){return~~a[3]}function f(a){return~~a[4]}function v(a){return function(b){return function(c){return h(["EImage",r.castStringToJSString(c)],a,b)}}}function n(a){return function(b){return h(A,a,b)}}function p(a){return function(b){return function(c){var h=map(function(c){return["Tuple2", -a/2*Math.cos(2*(Math.PI/50)*c),b/2*Math.sin(2*(Math.PI/50)*c)]}),f=49,d=["Nil"];if(0<=f){do d=["Cons",f,d];while(0<f--)}return j(h(d))(c)}}}for(this.i in Elm.List)eval("var "+this.i+" = Elm.List[this.i];");var r=Elm.JavaScript,y=["DRight"],s=["DDown"],u=["DOut"],q=["Near"],t=["Mid"],w=["Far"],A=["EEmpty"],x=["Solid"],D=["Dotted"],F=["Dashed"],B=["Filled"],E=["Outlined"],z=e(q)(q),C=e(w)(q),G=e(q)(w),H=e(w)(w),I=e(q)(t),J=e(w)(t),q=e(t)(q),w=e(t)(w),t=e(t)(t);return{left:["DLeft"],right:y,down:s,up:["DUp"], -inward:["DIn"],outward:u,topLeft:z,topRight:C,bottomLeft:G,bottomRight:H,midLeft:I,midRight:J,midTop:q,midBottom:w,middle:t,middleAt:function(a){return function(b){return["PositionAt",a,b]}},topLeftAt:function(a){return function(b){return["PositionTL",a,b]}},topRightAt:function(a){return function(b){return["PositionTR",a,b]}},bottomLeftAt:function(a){return function(b){return["PositionBL",a,b]}},bottomRightAt:function(a){return function(b){return["PositionBR",a,b]}},absolute:function(a){return["Absolute", -a]},relative:function(a){return["Relative",a]},width:function(a){return function(b){var c=b[2];switch(c[0]){case "EImage":case "EVideo":return l(b[2],a,b[4]*a/b[3],b[5],b[6],b[7]);case "EText":return c=Value.getTextSize(a,b[4],c[2]),l(b[2],a,c[1],b[5],b[6],b[7])}return l(b[2],a,b[4],b[5],b[6],b[7])}},height:function(a){return function(b){switch(b[2][0]){case "EImage":case "EVideo":return l(b[2],b[3]*a/b[4],a,b[5],b[6],b[7])}return l(b[2],b[3],a,b[5],b[6],b[7])}},size:function(b){return function(a){return function(c){return l(c[2], -b,a,c[5],c[6],c[7])}}},opacity:function(b){return function(a){return l(a[2],a[3],a[4],b,a[6],a[7])}},color:function(a){return function(b){return l(b[2],b[3],b[4],b[5],["Just",a],b[7])}},link:function(b){return function(a){return l(a[2],a[3],a[4],a[5],a[6],["Just",r.castStringToJSString(b)])}},widthOf:c,heightOf:f,sizeOf:function(a){return["Tuple2",~~a[3],~~a[4]]},text:function(a){var b=Value.getTextSize(0,0,a);return h(k("left")(a),b[0],b[1])},asText:function(a){a=Elm.Text.monospace(Value.toText(Value.show(a))); -var b=Value.getTextSize(0,0,a);return h(k("left")(a),b[0],b[1])},plainText:function(a){a=Value.toText(a);var b=Value.getTextSize(0,0,a);return h(k("left")(a),b[0],b[1])},centeredText:function(a){var b=Value.getTextSize(0,0,a);return h(k("center")(a),b[0],b[1])},justifiedText:function(a){var b=Value.getTextSize(0,0,a);return h(k("justify")(a),b[0],b[1])},rightedText:function(a){var b=Value.getTextSize(0,0,a);return h(k("right")(a),b[0],b[1])},image:v,images:function(a){var b=Elm.Signal.constant(n(0)(0)); -a=Elm.Signal.lift(function(a){a=r.castStringToJSString(a);var c=new Image;c.onload=function(){Dispatcher.notify(b.id,v(this.width)(this.height)(a))};c.src=a})(a);return Elm.Signal.lift2(function(a){return function(){return a}})(b)(a)},video:function(a){return function(b){return function(c){return h(["EVideo",r.castStringToJSString(c)],a,b)}}},fittedImage:function(a){return function(b){return function(c){return h(["EFittedImage",r.castStringToJSString(c)],a,b)}}},flow:function(a){return function(d){var e; -e=map(c)(d);a:{switch(a[0]){case "DLeft":e=sum(e);break a;case "DRight":e=sum(e);break a}e=maximum(e)}var g;g=map(f)(d);a:{switch(a[0]){case "DDown":g=sum(g);break a;case "DUp":g=sum(g);break a}g=maximum(g)}return h(b(a)(d),e,g)}},above:function(a){return function(c){return h(b(s)(["Cons",a,["Cons",c,["Nil"]]]),Math.max(~~a[3],~~c[3]),~~a[4]+~~c[4])}},below:function(a){return function(c){return h(b(s)(["Cons",c,["Cons",a,["Nil"]]]),Math.max(~~a[3],~~c[3]),~~a[4]+~~c[4])}},beside:function(a){return function(c){return h(b(y)(["Cons", -a,["Cons",c,["Nil"]]]),~~a[3]+~~c[3],Math.max(~~a[4],~~c[4]))}},layers:function(a){return h(b(u)(a),maximum(map(c)(a)),maximum(map(f)(a)))},collage:function(a){return function(b){return function(c){return h(["ECollage",a,b,Value.groupForms(c)],a,b)}}},spacer:n,container:function(a){return function(b){return function(c){return function(f){return h(["EContainer",c,f],a,b)}}}},line:d,segment:function(a){return function(b){return d(["Cons",a,["Cons",b,["Nil"]]])}},polygon:j,rect:function(a){return function(b){return function(c){return j(["Cons", -["Tuple2",0-a/2,0-b/2],["Cons",["Tuple2",0-a/2,b/2],["Cons",["Tuple2",a/2,b/2],["Cons",["Tuple2",a/2,0-b/2],["Nil"]]]]])(c)}}},oval:p,circle:function(a){return p(2*a)(2*a)},ngon:function(a){return function(b){return function(c){var h=map(function(c){return["Tuple2",b*Math.cos(2*(Math.PI/a)*c),b*Math.sin(2*(Math.PI/a)*c)]}),f=a-1,d=["Nil"];if(0<=f){do d=["Cons",f,d];while(0<f--)}return j(h(d))(c)}}},solid:function(b){return function(c){return a(0)(1)(["Tuple2",0,0])(m(x)(b)(c))}},dotted:function(b){return function(c){return a(0)(1)(["Tuple2", -0,0])(m(D)(b)(c))}},dashed:function(b){return function(c){return a(0)(1)(["Tuple2",0,0])(m(F)(b)(c))}},customLine:function(b){return function(c){return function(h){return a(0)(1)(["Tuple2",0,0])(m(["Custom",r.castListToJSArray(b)])(c)(h))}}},filled:function(b){return function(c){return a(0)(1)(c[2])(g(B)(b)(c))}},outlined:function(b){return function(c){return a(0)(1)(c[2])(g(E)(b)(c))}},customOutline:function(b){return function(c){return function(h){return a(0)(1)(h[2])(g(["CustomOutline",r.castListToJSArray(b)])(c)(h))}}}, -textured:function(b){return function(c){return a(0)(1)(c[2])(g(["Textured",b])(null)(c))}},sprite:function(b){return function(c){return function(h){return function(f){return a(0)(1)(f)(["FImage",c,h,r.castStringToJSString(b)])}}}},toForm:function(b){return function(c){return a(0)(1)(b)(["FElement",c])}},rotate:function(b){return function(c){a:{switch(c[0]){case "Form":var h=c[2],f=c[3],d=c[4];c=a(b+c[1])(h)(f)(d);break a}throw"Non-exhaustive pattern match in case";}return c}},scale:function(b){return function(c){return a(c[1])(b* -c[2])(c[3])(c[4])}},move:function(b){return function(c){return function(h){var f;a:{switch(h[0]){case "Form":f=h[1];var d=h[2],e=h[3];h=h[4];switch(e[0]){case "Tuple2":var g=e[1],e=e[2];f=a(f)(d)(["Tuple2",b+g,c+e])(h);break a}}throw"Non-exhaustive pattern match in case";}return f}}},isWithin:Collage.insideForm}}(); -Elm.Text=function(){function e(a){return Value.toText(a)}var k=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},b=function(a,b){return function(f){return"<span style='"+a+":"+b+"'>"+f+"</span>"}},d=function(a){a=Elm.JavaScript.castStringToJSString(a);return b("font-family",a)},j=k("h1"),a=b("font-style","italic"),k=k("b"),m=b("text-decoration","underline"),g=b("text-decoration","overline"),l=b("text-decoration","line-through");return{fromString:e,toText:e,header:j, -height:function(a){return b("font-size",a+"em")},italic:a,bold:k,underline:m,overline:g,strikeThrough:l,monospace:d("monospace"),typeface:d,color:function(a){return b("color",Elm.Color.extract(a))},link:function(a){return function(b){return"<a href='"+e(a)+"'>"+b+"</a>"}}}}(); -var Render=function(){function e(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a}function k(a){return a}function b(a){a.style.styleFloat="left";a.style.cssFloat="left";return a}function d(a){a.style.position="absolute";return a}function j(a,b,f){for(var d=e("div"),g=f.length;g--;){var j=a(b(f[g]));d.appendChild(j)}return d}function a(a){switch(a[0]){case "Absolute":return a[1]+"px";case "Relative":return 100*a[1]+"%"}}function m(b,c){c.style.position="absolute";c.style.margin= -"auto";switch(b[0]){case "Position":"Far"!==b[1][0]&&(c.style.left=0);"Near"!==b[1][0]&&(c.style.right=0);"Far"!==b[2][0]&&(c.style.top=0);"Near"!==b[2][0]&&(c.style.bottom=0);break;case "PositionAt":c.style.top=a(b[2]);c.style.left=a(b[1]);var f="translate("+~~(-c.style.width.slice(0,-2)/2)+"px,"+~~(-c.style.height.slice(0,-2)/2)+"px)";c.style.transform=f;c.style.msTransform=f;c.style.MozTransform=f;c.style.webkitTransform=f;c.style.OTransform=f;break;default:f=b[0].slice(-2),c.style["T"===f[0]? -"top":"bottom"]=a(b[2]),c.style["L"===f[1]?"left":"right"]=a(b[1])}}function g(a){var c={};switch(a[2][0]){case "EText":var c=a[2][1],f=a[2][2],l=e("div");l.innerHTML=f;l.style.textAlign=c;c=l;break;case "EImage":c=a[2][1];f=e("img");f.src=c;f.name=c;f.style.display="block";c=f;break;case "EVideo":l=a[2][1];c=e("video");c.controls="controls";f=e("source");f.src=l;l=l.split(".");f.type="video/"+l[l.length-1];c.appendChild(f);c.style.display="block";break;case "EFittedImage":var n=a[3],p=a[4],c=a[2][1], -f=e("div");f.style.width=n+"px";f.style.height=p+"px";f.style.position="relative";f.style.overflow="hidden";var r=e("img");r.onload=function(){r.style.position="absolute";r.style.margin="auto";var a=n,b=p;n/p>this.width/this.height?b=Math.round(this.height*n/this.width):a=Math.round(this.width*p/this.height);r.style.width=a+"px";r.style.height=b+"px";r.style.left=(n-a)/2+"px";r.style.top=(p-b)/2+"px"};r.src=c;r.name=c;f.appendChild(r);c=f;break;case "EFlow":a:{c=a[2][2];switch(a[2][1][0]){case "DDown":c= -c.slice(0).reverse();case "DUp":c=j(k,g,c);break a;case "DRight":c=c.slice(0).reverse();case "DLeft":c=j(b,g,c);break a;case "DOut":c=c.slice(0).reverse();case "DIn":c=j(d,g,c);break a}c=void 0}break;case "ECollage":c=Collage.collage(a[2][1],a[2][2],a[2][3]);break;case "EEmpty":c=e("div");break;case "EContainer":f=a[2][1];c=g(a[2][2]);m(f,c);f=e("div");f.style.position="relative";f.style.overflow="hidden";f.appendChild(c);c=f;break;case "EHtml":c=a[2][1];"button"!==c.type&&(f=Value.getExcess(c),a[3]-= -f[0],a[4]-=f[1]);break;case "EExternalHtml":c=e("div"),c.appendChild(a[2][1])}c.id=a[1];c.style.width=~~a[3]+"px";c.style.height=~~a[4]+"px";1!==a[5]&&(c.style.opacity=a[5]);"Just"===a[6][0]&&(c.style.backgroundColor=Elm.Color.extract(a[6][1]));return"Just"===a[7][0]?(f=e("a"),f.href=a[7][1],f.appendChild(c),f):c}function l(a,c,f){"A"===a.tagName&&(a=a.firstChild);if(c[1]!==f[1]){if(c[2][0]!==f[2][0])return a.parentNode.replaceChild(g(f),a);var e=f[2],j=c[2];switch(e[0]){case "EText":e[1]!==j[1]&& -(a.style.textAlign=e[1]);e[2]!==j[2]&&(a.innerHTML=e[2]);break;case "EImage":e[1]!==j[1]&&(a.src=e[1]);break;case "EVideo":case "EFittedImage":if(!Value.eq(e,j)||f[3]!==c[3]||f[4]!==c[4])return a.parentNode.replaceChild(g(f),a);break;case "ECollage":if(e[1]!==j[1]||e[2]!==j[2]||e[3].length!==j[3].length)return a.parentNode.replaceChild(g(f),a);Collage.updateCollage(a,j[3],e[3]);break;case "EFlow":if(e[1]!==j[1])return a.parentNode.replaceChild(g(f),a);var p=e[2],r=a.childNodes;if(p.length!==r.length)return a.parentNode.replaceChild(g(f), -a);var j=j[2],y=function(a){return a};switch(e[1][0]){case "DDown":case "DUp":y=k;break;case "DRight":case "DLeft":y=b;break;case "DOut":case "DIn":y=d}for(e=r.length;e--;)l(r[e],j[e],p[e]),y(r[e]);break;case "EContainer":l(a.childNodes[0],j[2],e[2]);m(e[1],a.childNodes[0]);break;case "EHtml":f[1]!==c[1]&&(p=g(f),a.parentNode.replaceChild(p,a),a=p);"button"!==p.type&&(e=Value.getExcess(a),f[3]-=e[0],f[4]-=e[1]);break;case "EExternalHtml":f[1]!==c[1]&&a.parentNode.replaceChild(g(f),a)}f[3]!==c[3]&& -(a.style.width=~~f[3]+"px");f[4]!==c[4]&&(a.style.height=~~f[4]+"px");f[5]!==c[5]&&(a.style.opacity=f[5]);2===f[6].length&&(e=Elm.Color.extract(f[6][1]),e!==a.style.backgroundColor&&(a.style.backgroundColor=e));if(2===f[7].length&&(1===c[7].length||f[7][1]!==c[7][1]))a.parentNode.href=f[7][1];f[1]=c[1]}}return{render:g,update:l,addTo:function(a,b){a.appendChild(b)},newElement:e,flowWith:j,goIn:d}}(); -Elm.Signal=function(){function e(a){this.id=Guid.guid();this.value=a;this.kids=[];this.defaultNumberOfKids=0;this.recv=function(a,b,c){if(b=b===this.id)this.value=c;l(this,a,b);return b};Dispatcher.inputs.push(this)}function k(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.count=0;this.changed=!1;b.reverse();this.recalc=function(){for(var d=a,e=b.length;e--;)d=d(b[e].value);this.value=d};this.recalc();this.recv=function(a,c){this.count+=1;c&&(this.changed=!0);this.count==b.length&&(this.changed&& -this.recalc(),l(this,a,this.changed),this.changed=!1,this.count=0)};for(var d=b.length;d--;)b[d].kids.push(this)}function b(a,b,d,e){this.id=Guid.guid();this.value=d?b(e.value):b;this.kids=[];this.recv=function(b,d){d&&(this.value=a(e.value)(this.value));l(this,b,d)};e.kids.push(this)}function d(a,b,d){this.id=Guid.guid();this.value=a(d.value)?b:d.value;this.kids=[];this.recv=function(b,f){var e=f&&!a(d.value);e&&(this.value=d.value);l(this,b,e)};d.kids.push(this)}function j(a){this.id=Guid.guid(); -this.value=a.value;this.kids=[];this.recv=function(b,d){var e=d&&!Value.eq(this.value,a.value);e&&(this.value=a.value);l(this,b,e)};a.kids.push(this)}function a(a,b){this.id=Guid.guid();var d=(new window.Date).getTime();this.value=a?Value.Tuple(d,b.value):d;this.kids=[];this.recv=function(d,e){e&&(this.value=a?Value.Tuple(d,b.value):d);l(this,d,e)};b.kids.push(this)}function m(a,b){this.id=Guid.guid();this.value=b.value;this.kids=[];this.count=0;this.changed=!1;this.recv=function(d,e,g){g===a.id&& -(this.changed=e);this.count+=1;2==this.count&&(this.changed&&(this.value=b.value),l(this,d,this.changed),this.count=0,this.changed=!1)};a.kids.push(this);b.kids.push(this)}function g(a,b){this.id=Guid.guid();this.value=a.value;this.kids=[];this.next=null;this.count=0;this.changed=!1;this.recv=function(d,e,g){this.count+=1;e&&(this.changed=!0,g==b.id&&null===this.next&&(this.next=b.value),g==a.id&&(this.next=a.value));2==this.count&&(this.changed&&(this.value=this.next,this.next=null),l(this,d,this.changed), -this.changed=!1,this.count=0)};a.kids.push(this);b.kids.push(this)}var l=function(a,b,d){for(var e=a.kids,g=e.length;g--;)e[g].recv(b,d,a.id)},h=function(a){return function(b){return function(e){e=new k(function(a){return function(b){return[a,b]}},[a,e]);e=new d(function(a){return a[0]},[!0,b],e);return new k(function(a){return a[1]},[e])}}};return{constant:function(a){return new e(a)},lift:function(a){return function(b){return new k(a,[b])}},lift2:function(a){return function(b){return function(d){return new k(a, -[b,d])}}},lift3:function(a){return function(b){return function(d){return function(e){return new k(a,[b,d,e])}}}},lift4:function(a){return function(b){return function(d){return function(e){return function(g){return new k(a,[b,d,e,g])}}}}},lift5:function(a){return function(b){return function(d){return function(e){return function(g){return function(h){return new k(a,[b,d,e,g,h])}}}}}},lift6:function(a){return function(b){return function(d){return function(e){return function(g){return function(h){return function(j){return new k(a, -[b,d,e,g,h,j])}}}}}}},lift7:function(a){return function(b){return function(d){return function(e){return function(g){return function(h){return function(j){return function(l){return new k(a,[b,d,e,g,h,j,l])}}}}}}}},lift8:function(a){return function(b){return function(d){return function(e){return function(g){return function(h){return function(j){return function(l){return function(m){return new k(a,[b,d,e,g,h,j,l,m])}}}}}}}}},foldp:function(a){return function(d){return function(e){return new b(a,d,!1, -e)}}},foldp_:function(a){return function(d){return function(e){return new b(a,d,!0,e)}}},foldp1:function(a){return function(d){return new b(a,function(a){return a},!0,d)}},delay:function(a){return function(b){var d=new e(b.value),g=!0;b=new m(d,new k(function(a){return function(){return a}},[d,new k(function(b){g||setTimeout(function(){Dispatcher.notify(d.id,b)},a)},[b])]));g=!1;return b}},merge:function(a){return function(b){return new g(a,b)}},merges:function(a){return Elm.List.foldl1(function(a){return function(b){return new g(a, -b)}})(a)},average:function(a){return function(b){for(var d=Array(a),e=a;e--;)d[e]=0;var e=0,g=!1,h=0;return new k(function(b){h+=b-d[e];d[e]=b;b=h/Math.max(1,g?a:e);++e==a&&(g=!0,e=0);return b},[b])}},count:function(a){return new b(function(){return function(a){return a+1}},0,!1,a)},countIf:function(a){return function(d){return new b(function(b){return function(d){return a(b)?d+1:d}},0,!1,d)}},keepIf:function(a){return function(b){return function(e){return new d(function(b){return!a(b)},b,e)}}},dropIf:function(a){return function(b){return function(e){return new d(a, -b,e)}}},keepWhen:function(a){return h(new k(function(a){return!a},[a]))},dropWhen:h,dropRepeats:function(a){return new j(a)},sampleOn:function(a){return function(b){return new m(a,b)}},timestamp:function(b){return new a(!0,b)},timeOf:function(b){return new a(!1,b)}}}(); -var Dispatcher=function(){function e(b){if(!b.hasOwnProperty("defaultNumberOfKids"))return!0;var a=b.kids.length;if(0==a)return!1;if(a>b.defaultNumberOfKids)return!0;for(var d=!1;a--;)d=d||e(b.kids[a]);return d}var k=null,b=[],d=null;return{initialize:function(){k=Elm.main();k.hasOwnProperty("recv")||(k=Elm.Signal.constant(k));d=k.value;for(var j=[],a=b.length;a--;)e(b[a])&&j.push(b[a]);b=j;document.getElementById("content").appendChild(Render.render(d));j=document.getElementById("widthChecker").offsetWidth; -j!==window.innerWidth&&Dispatcher.notify(Elm.Window.dimensions.id,Value.Tuple(j,window.innerHeight));k=Elm.Signal.lift(function(a){var b=document.getElementById("content");Render.update(b.firstChild,d,a);return d=a})(k)},notify:function(d,a){for(var e=(new window.Date).getTime(),g=!1,k=b.length;k--;)g=b[k].recv(e,d,a)||g;return g},inputs:b}}(); -Elm.HTTP=function(){function e(b){return function(d){return function(e){return function(c){return{"0":"Request",length:1,verb:a.castStringToJSString(b),url:a.castStringToJSString(d),data:null===e?null:a.castStringToJSString(e),headers:c}}}}}function k(a){return e("GET")(a)(null)(["Nil"])}function b(b,e){return function(h){if(""!==h.url){var c={value:["Waiting"]};b.push(c);var f=null;window.ActiveXObject&&(f=new ActiveXObject("Microsoft.XMLHTTP"));window.XMLHttpRequest&&(f=new XMLHttpRequest);f.onreadystatechange= -function(){4===f.readyState&&(c.value=200===f.status?["Success",m(f.responseText)]:["Failure",f.status,m(f.statusText)],setTimeout(function(){d(b,e)},0))};f.open(h.verb,h.url,!0);Elm.List.map(function(b){f.setRequestHeader(a.castStringToJSString(b[1]),a.castStringToJSString(b[2]))})(h.headers);f.send(h.data)}}}function d(a,b){0<a.length&&(Dispatcher.notify(b.id,a[0].value),"Waiting"!==a[0].value[0]&&(a.shift(),setTimeout(function(){d(a,b)},0)))}function j(a){var d=Elm.Signal.constant(["Waiting"]); -a=Elm.Signal.lift(b([],d))(a);return Elm.Signal.lift2(function(a){return function(){return a}})(d)(a)}var a=Elm.JavaScript,m=Elm.JavaScript.castJSStringToString;return{get:k,post:function(a){return function(b){return e("POST")(a)(b)(["Nil"])}},request:e,send:j,sendGet:function(a){return j(Elm.Signal.lift(k)(a))}}}(); -Elm.Input=function(){var e=Elm.JavaScript,k=Elm.JavaScript.castJSStringToString,b=function(a,b){a.placeholder=e.castStringToJSString(b);var d=Elm.Signal.constant(["Nil"]);Value.addListener(a,"keyup",function(){Dispatcher.notify(d.id,k(a.value));a.focus()});a.style.padding="1px";return Value.Tuple(Value.wrap(a),d)},d=function(a){a=document.createElement(a);a.style.padding="0";a.style.margin="0";return a},j=function(a){for(var b=d("select"),e=[];"Cons"===a[0];){var j=d("option"),h=Value.toText(a[1][1]); -j.value=h;j.innerHTML=h;b.appendChild(j);e.push(a[1][2]);a=a[2]}var c=Elm.Signal.constant(e[0]);Value.addListener(b,"change",function(){Dispatcher.notify(c.id,e[b.selectedIndex])});return Value.Tuple(Value.wrap(b),c)};return{textArea:function(a){return function(e){var g=d("textarea");g.rows=e;g.cols=a;return b(g,"")}},textField:function(a){var e=d("input");e.type="text";return b(e,a)},password:function(a){var e=d("input");e.type="password";return b(e,a)},checkbox:function(a){var b=d("input");b.type= -"checkbox";b.checked=a;var e=Elm.Signal.constant(a);Value.addListener(b,"change",function(){Dispatcher.notify(e.id,b.checked)});return Value.Tuple(Value.wrap(b),e)},dropDown:j,stringDropDown:function(a){return j(Elm.List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var b=d("input");b.type="button";b.value=e.castStringToJSString(a);var g=Elm.Signal.constant(!1);Value.addListener(b,"click",function(){Dispatcher.notify(g.id,!0);Dispatcher.notify(g.id,!1)});return Value.Tuple(Value.wrap(b), -g)}}}(); -Elm.Keyboard={Raw:function(){function e(b,j){return"Nil"===j[0]?j:j[1]===b?j[2]:["Cons",j[1],e(b,j[2])]}var k=Elm.Signal.constant(["Nil"]),b=Elm.Signal.constant(["Nothing"]);Value.addListener(document,"keydown",function(b){var e;a:{for(e=k.value;"Nil"!==e[0];){if(e[1]===b.keyCode){e=!0;break a}e=e[2]}e=!1}e||Dispatcher.notify(k.id,["Cons",b.keyCode,k.value])||this.removeEventListener("keydown",arguments.callee,!1)});Value.addListener(document,"keyup",function(b){var j=e(b.keyCode,k.value);Dispatcher.notify(k.id, -j)||this.removeEventListener("keyup",arguments.callee,!1)});Value.addListener(window,"blur",function(b){Dispatcher.notify(k.id,["Nil"])||this.removeEventListener("blur",arguments.callee,!1)});Value.addListener(document,"keypress",function(d){var e=Dispatcher.notify(b.id,["Just",d.charCode||d.keyCode]);Dispatcher.notify(b.id,["Nothing"]);e||this.removeEventListener("keypress",arguments.callee,!1)});return{keysDown:k,charPressed:b}}()}; -Elm.Mouse=function(){function e(a){var b=0,d=0;a||(a=window.event);if(a.pageX||a.pageY)b=a.pageX,d=a.pageY;else if(a.clientX||a.clientY)b=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,d=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return Value.Tuple(b,d)}var k=Elm.Signal.constant(Value.Tuple(0,0));k.defaultNumberOfKids=2;var b=Elm.Signal.lift(function(a){return a[1]})(k);b.defaultNumberOfKids=0;var d=Elm.Signal.lift(function(a){return a[2]})(k);d.defaultNumberOfKids= -0;var j=Elm.Signal.constant(!1),a=Elm.Signal.constant(!1),m=Elm.Signal.constant(Value.Tuple());Value.addListener(document,"click",function(b){var d=Dispatcher.notify(a.id,!0),e=Dispatcher.notify(m.id,Value.Tuple());Dispatcher.notify(a.id,!1);!d&&!e&&this.removeEventListener("click",arguments.callee,!1)});Value.addListener(document,"mousedown",function(a){Dispatcher.notify(j.id,!0)||this.removeEventListener("mousedown",arguments.callee,!1)});Value.addListener(document,"mouseup",function(a){Dispatcher.notify(j.id, -!1)||this.removeEventListener("mouseup",arguments.callee,!1)});Value.addListener(document,"mousemove",function(a){Dispatcher.notify(k.id,e(a))||this.removeEventListener("mousemove",arguments.callee,!1)});return{position:k,x:b,y:d,isClicked:a,isDown:j,clicks:m,isClickedOn:function(a){a=Render.render(a);var b=Elm.Signal.constant(!1);Value.addListener(a,"click",function(){Dispatcher.notify(b.id,!0);Dispatcher.notify(b.id,!1)});return Value.Tuple(Value.wrap(a),b)}}}(); -Elm.Random=function(){return{inRange:function(e){return function(k){return Elm.Signal.constant(Math.floor(Math.random()*(k-e+1))+e)}},randomize:function(e){return function(k){return function(b){return Elm.Signal.lift(function(){return Math.floor(Math.random()*(k-e+1))+e})(b)}}}}}(); -Elm.Time=function(){function e(){return(new window.Date).getTime()}function k(b){return function(d){var j=1E3/b,a=e(),k=a,g=0,l=!0,h=Elm.Signal.constant(g),c=0;return Elm.Signal.lift2(function(b){return function(d){if(b){var n=!l&&b;c=setTimeout(function(){k=e();g=n?0:k-a;a=k;Dispatcher.notify(h.id,g)},j)}else l&&clearTimeout(c);l=b;return d}})(d)(h)}}Elm.Signal.constant(!0);return{fpsWhen:k,fps:function(b){return k(b)(Elm.Signal.constant(!0))},every:function(b){var d=Elm.Signal.constant(e());setInterval(function(){Dispatcher.notify(d.id, -e())},b);return d},delay:Elm.Signal.delay,since:function(b){return function(d){var e=Elm.Signal.count(Elm.Signal.delay(b)(d));return Elm.Signal.lift2(function(a){return function(b){return!Value.eq(a,b)}})(Elm.Signal.count(d))(e)}},after:function(b){b*=1E3;var d=Elm.Signal.constant(!1);setTimeout(function(){Dispatcher.notify(d.id,!0)},b);return d},before:function(b){b*=1E3;var d=Elm.Signal.constant(!0);setTimeout(function(){Dispatcher.notify(d.id,!1)},b);return d},hour:36E5,minute:6E4,second:1E3,ms:1, -inHours:function(b){return b/36E5},inMinutes:function(b){return b/6E4},inSeconds:function(b){return b/1E3},inMss:function(b){return b},toDate:function(b){return new window.Date(b)},read:function(b){b=window.Date.parse(b);return isNaN(b)?["Nothing"]:["Just",b]}}}(); -Elm.Window=function(){var e=Elm.Signal.constant(Value.Tuple(window.innerWidth,window.innerHeight));e.defaultNumberOfKids=2;var k=Elm.Signal.lift(function(b){return b[1]})(e);k.defaultNumberOfKids=0;var b=Elm.Signal.lift(function(b){return b[2]})(e);b.defaultNumberOfKids=0;Value.addListener(window,"resize",function(b){var j=document.getElementById("widthChecker").offsetWidth;Dispatcher.notify(e.id,Value.Tuple(j,window.innerHeight))||this.removeEventListener("resize",arguments.callee,!1)});return{dimensions:e, -width:k,height:b}}(); -Elm.Date=function(){var e="Sun Mon Tue Wed Thu Fri Sat".split(" "),k="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");return{read:function(b){b=new window.Date(Elm.JavaScript.castStringToJSString(b));return isNaN(b.getTime())?["Nothing"]:["Just",b]},year:function(b){return b.getFullYear()},month:function(b){return[k[b.getMonth()]]},day:function(b){return b.getDate()},hour:function(b){return b.getHours()},minute:function(b){return b.getMinutes()},second:function(b){return b.getSeconds()},dayOfWeek:function(b){return[e[b.getDay()]]}, -toTime:function(b){return b.getTime()},Mon:["Mon"],Tue:["Tue"],Wed:["Wed"],Thu:["Thu"],Fri:["Fri"],Sat:["Sat"],Sun:["Sun"],Jan:["Jan"],Feb:["Feb"],Mar:["Mar"],Apr:["Apr"],May:["May"],Jun:["Jun"],Jul:["Jul"],Aug:["Aug"],Sep:["Sep"],Oct:["Oct"],Nov:["Nov"],Dec:["Dec"]}}();Value.addListener(document,"elm_log",function(e){console.log(e.value)});Value.addListener(document,"elm_title",function(e){document.title=e.value}); -Value.addListener(document,"elm_redirect",function(e){0<e.value.length&&(window.location=e.value)}); -Elm.Prelude=function(){function e(b){return function(d){if(b instanceof Array&&d instanceof Array){var j=b.length;if(j==d.length){for(var a=1;a<j;++a){var k=e(b[a])(d[a]);if("EQ"!==k[0])return k}return["EQ"]}return[1==d.length?"GT":"LT"]}return[b===d?"EQ":b<d?"LT":"GT"]}}var k=function(b){return function(d){var e=b%d,e=0==b?0:0<d?0<=b?e:e+d:-k(-b)(-d);return e==d?0:e}};return{eq:Value.eq,id:function(b){return b},not:function(b){return!b},fst:function(b){return b[1]},snd:function(b){return b[2]},rem:function(b){return function(d){return b% -d}},div:function(b){return function(d){return~~(b/d)}},otherwise:!0,compare:e,toFloat:function(b){return b},round:function(b){return Math.round(b)},floor:function(b){return Math.floor(b)},ceiling:function(b){return Math.ceil(b)},truncate:function(b){return~~b},readInt:function(b){b=Elm.JavaScript.castStringToJSString(b);var d=b.length;if(0===d)return["Nothing"];var e=0;if("-"==b[0]){if(1===d)return["Nothing"];e=1}for(;e<d;++e)if(!Elm.Char.isDigit(b[e]))return["Nothing"];return["Just",parseInt(b)]}, -readFloat:function(b){b=Elm.JavaScript.castStringToJSString(b);var d=b.length;if(0===d)return["Nothing"];var e=0;if("-"==b[0]){if(1===d)return["Nothing"];e=1}for(var a=0;e<d;++e)if(!Elm.Char.isDigit(b[e])){if("."===b[e]&&(a+=1,1>=a))continue;return["Nothing"]}return["Just",parseFloat(b)]},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,e:Math.E,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,atan2:function(b){return function(d){return Math.atan2(b,d)}},mod:k,min:function(b){return function(d){return Math.min(b, -d)}},max:function(b){return function(d){return Math.max(b,d)}},flip:function(b){return function(d){return function(e){return b(e)(d)}}},clamp:function(b){return function(d){return function(e){return Math.min(d,Math.max(b,e))}}},curry:function(b){return function(d){return function(e){return b(["Tuple2",d,e])}}},uncurry:function(b){return function(d){if("Tuple2"!==d[0])throw"Function was uncurry'd but was not given a pair.";return b(d[1])(d[2])}},logBase:function(b){return function(d){return Math.log(d)/ -Math.log(b)}},Just:Elm.Maybe.Just,Nothing:Elm.Maybe.Nothing,maybe:Elm.Maybe.maybe,map:Elm.List.map,zip:Elm.List.zip,zipWith:Elm.List.zipWith,filter:Elm.List.filter,head:Elm.List.head,tail:Elm.List.tail,last:Elm.List.last,length:Elm.List.length,reverse:Elm.List.reverse,foldr:Elm.List.foldr,foldr1:Elm.List.foldr1,foldl:Elm.List.foldl,foldl1:Elm.List.foldl1,and:Elm.List.and,or:Elm.List.or,all:Elm.List.all,any:Elm.List.any,sum:Elm.List.sum,product:Elm.List.product,concat:Elm.List.concat,concatMap:Elm.List.concatMap, -maximum:Elm.List.maximum,minimum:Elm.List.minimum,scanl:Elm.List.scanl,scanl1:Elm.List.scanl1,take:Elm.List.take,drop:Elm.List.drop,zip:Elm.List.zip,unzip:Elm.List.unzip,lift:Elm.Signal.lift,lift2:Elm.Signal.lift2,lift3:Elm.Signal.lift3,lift4:Elm.Signal.lift4,lift5:Elm.Signal.lift5,lift6:Elm.Signal.lift6,lift7:Elm.Signal.lift7,lift8:Elm.Signal.lift8,foldp:Elm.Signal.foldp,foldp1:Elm.Signal.foldp1,foldp_:Elm.Signal.foldp_,constant:Elm.Signal.constant,merge:Elm.Signal.merge,count:Elm.Signal.count,countIf:Elm.Signal.countIf, -average:Elm.Signal.average,keepIf:Elm.Signal.keepIf,dropIf:Elm.Signal.dropIf,keepWhen:Elm.Signal.keepWhen,dropWhen:Elm.Signal.dropWhen,dropRepeats:Elm.Signal.dropRepeats,sampleOn:Elm.Signal.sampleOn,timestamp:Elm.Signal.timestamp,timeOf:Elm.Signal.timeOf}}();(function(){var e=function(e){for(var b in e)Elm.Prelude[b]=e[b]};e(Elm.Color);e(Elm.Text);e(Elm.Graphics);e(Elm.Time);show=Value.show})(); -Elm.Dict=function(){function e(a){return function(b){return function(c){return function(e){return function(d){return["RBNode",a,b,c,e,d]}}}}}function k(a){a:{switch(a[0]){case "RBEmpty":throw"(min RBEmpty) is not defined";case "RBNode":switch(a[4][0]){case "RBEmpty":a=["Tuple2",a[2],a[3]];break a}a=k(a[4]);break a}throw"Non-exhaustive pattern match in case";}return a}function b(a){return function(c){var e;a:{switch(c[0]){case "RBEmpty":e=w;break a;case "RBNode":e=function(){switch(q(a)(c[2])[0]){case "EQ":return A(c[3]); -case "GT":return b(a)(c[5]);case "LT":return b(a)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case";}return e}}function d(a){return function(b){return function(c){var e;a:{switch(c[0]){case "RBEmpty":e=a;break a;case "RBNode":e=function(){switch(q(b)(c[2])[0]){case "EQ":return c[3];case "GT":return d(a)(b)(c[5]);case "LT":return d(a)(b)(c[4])}throw"Non-exhaustive pattern match in case";}();break a}throw"Non-exhaustive pattern match in case"; -}return e}}}function j(a){return function(c){return F(b(a)(c))}}function a(a){a:{switch(a[0]){case "RBNode":switch(a[5][0]){case "RBNode":a=e(a[1])(a[5][2])(a[5][3])(e(B)(a[2])(a[3])(a[4])(a[5][4]))(a[5][5]);break a}}throw"rotateLeft of a node without enough children";}return a}function m(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":a=e(a[1])(a[4][2])(a[4][3])(a[4][4])(e(B)(a[2])(a[3])(a[4][5])(a[5]));break a}}throw"rotateRight of a node without enough children";}return a}function g(a){a:{switch(a[0]){case "Black":a= -B;break a;case "Red":a=E;break a}throw"Non-exhaustive pattern match in case";}return a}function l(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[5][0]){case "RBNode":a=e(g(a[1]))(a[2])(a[3])(e(g(a[4][1]))(a[4][2])(a[4][3])(a[4][4])(a[4][5]))(e(g(a[5][1]))(a[5][2])(a[5][3])(a[5][4])(a[5][5]));break a}}}throw"color_flip called on a RBEmpty or RBNode with a RBEmpty child";}return a}function h(b){a:switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":b= -a(b);break a}}}a:switch(b[0]){case "RBNode":switch(b[4][0]){case "RBNode":switch(b[4][1][0]){case "Red":switch(b[4][4][0]){case "RBNode":switch(b[4][4][1][0]){case "Red":b=m(b);break a}}}}}a:switch(b[0]){case "RBNode":switch(b[4][0]){case "RBNode":switch(b[4][1][0]){case "Red":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":b=l(b);break a}}}}}return b}function c(a){a:switch(a[0]){case "RBNode":switch(a[1][0]){case "Red":a=e(E)(a[2])(a[3])(a[4])(a[5]);break a}}return a}function f(a){return function(b){return function(d){var f= -function(c){var d;a:{switch(c[0]){case "RBEmpty":d=e(B)(a)(b)(z)(z);break a;case "RBNode":d=function(){switch(q(a)(c[2])[0]){case "EQ":return e(c[1])(c[2])(b)(c[4])(c[5]);case "GT":return e(c[1])(c[2])(c[3])(c[4])(f(c[5]));case "LT":return e(c[1])(c[2])(c[3])(f(c[4]))(c[5])}throw"Non-exhaustive pattern match in case";}();d=h(d);break a}throw"Non-exhaustive pattern match in case";}return d};return c(f(d))}}}function v(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][1][0]){case "Red":a= -!0;break a}}}a=!1}return a}function n(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBNode":switch(a[4][4][0]){case "RBNode":switch(a[4][4][1][0]){case "Red":a=!0;break a}}}}a=!1}return a}function p(b){if(x(v(b))&&x(n(b))){b=l(b);a:switch(b[0]){case "RBNode":b:switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":b=l(a(e(b[1])(b[2])(b[3])(b[4])(m(b[5]))));break b}}}break a}}return b}function r(a){return function(b){var d=function(b){a:{switch(b[0]){case "RBEmpty":b= -z;break a;case "RBNode":if("LT"===q(a)(b[2])[0])b:{b=p(b);switch(b[0]){case "RBEmpty":throw"delLT on RBEmpty";case "RBNode":b=h(e(b[1])(b[2])(b[3])(d(b[4]))(b[5]));break b}break}else{var f=v(b)?m(b):b,g;b:{switch(f[0]){case "RBNode":switch(f[5][0]){case "RBEmpty":g=D(a,f[2]);break b}}g=!1}if(g)b=f[4];else{f=x;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][1][0]){case "Red":g=!0;break b}}}g=!1}if(f=f(g)){f=x;b:{switch(b[0]){case "RBNode":switch(b[5][0]){case "RBNode":switch(b[5][4][0]){case "RBNode":switch(b[5][4][1][0]){case "Red":g= -!0;break b}}}}g=!1}f=f(g)}f&&(b=l(b),b=n(b)?l(m(b)):b);b:{switch(b[0]){case "RBNode":f=D(a,b[2]);break b}f=!1}if(f)b:{switch(b[0]){case "RBEmpty":throw"delEQ called on a RBEmpty";case "RBNode":g=k(b[5]);c:{switch(g[0]){case "Tuple2":f=g[1];break c}break}c:{switch(g[0]){case "Tuple2":g=g[2];break c}break}var f=e(b[1])(f)(g)(b[4]),j=function(a){a:{switch(a[0]){case "RBNode":switch(a[4][0]){case "RBEmpty":a=z;break a}}b:{a=p(a);switch(a[0]){case "RBEmpty":a=z;break b;case "RBNode":a=h(e(a[1])(a[2])(a[3])(j(a[4]))(a[5])); -break b}throw"Non-exhaustive pattern match in case";}}return a};b=c(j(b[5]));b=h(f(b));break b}break}else b:{switch(b[0]){case "RBEmpty":throw"delGT called on a RBEmpty";case "RBNode":b=h(e(b[1])(b[2])(b[3])(b[4])(d(b[5])));break b}break}}}break a}throw"Non-exhaustive pattern match in case";}return b};return j(a)(b)?c(d(b)):b}}function y(a){return function(b){a:{switch(b[0]){case "RBEmpty":b=z;break a;case "RBNode":b=e(b[1])(b[2])(a(b[3]))(y(a)(b[4]))(y(a)(b[5]));break a}throw"Non-exhaustive pattern match in case"; -}return b}}function s(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=s(a)(a(c[2])(c[3])(s(a)(b)(c[4])))(c[5]);break a}throw"Non-exhaustive pattern match in case";}return c}}}function u(a){return function(b){return function(c){a:{switch(c[0]){case "RBEmpty":c=b;break a;case "RBNode":c=u(a)(a(c[2])(c[3])(u(a)(b)(c[5])))(c[4]);break a}throw"Non-exhaustive pattern match in case";}return c}}}var q=Elm.Prelude.compare,t=Elm.Prelude.uncurry,w=Elm.Prelude.Nothing, -A=Elm.Prelude.Just,x=Elm.Prelude.not,D=Elm.Prelude.eq,F=Elm.Maybe.isJust,B=["Red"],E=["Black"],z=["RBEmpty"],C=z;return{$op:{},empty:C,lookup:b,findWithDefault:d,member:j,insert:f,singleton:function(a){return function(b){return f(a)(b)(z)}},remove:r,map:y,foldl:s,foldr:u,union:function(a){return function(b){return s(f)(b)(a)}},intersect:function(a){return function(b){return s(function(a){return function(c){return function(d){return j(a)(b)?f(a)(c)(d):d}}})(C)(a)}},diff:function(a){return function(b){return s(function(a){return function(){return function(b){return r(a)(b)}}})(a)(b)}}, -keys:function(a){return u(function(a){return function(){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},values:function(a){return u(function(){return function(a){return function(b){return["Cons",a,b]}}})(["Nil"])(a)},toList:function(a){return u(function(a){return function(b){return function(c){return["Cons",["Tuple2",a,b],c]}}})(["Nil"])(a)},fromList:function(a){return Elm.List.foldl(t(f))(C)(a)}}}(); -Elm.Set=function(){var e=Elm.Dict.empty,k=Elm.Dict.remove,b=Elm.Dict.member,d=Elm.Dict.union,j=Elm.Dict.intersect,a=Elm.Dict.diff,m=Elm.Dict.keys,g=Elm.List.foldl(function(a){return function(b){return Elm.Dict.insert(a)(["Tuple0"])(b)}})(e);return{empty:e,singleton:function(a){return Elm.Dict.singleton(a)(["Tuple0"])},insert:function(a){return Elm.Dict.insert(a)(["Tuple0"])},remove:k,member:b,union:d,intersect:j,diff:a,toList:m,fromList:g,foldl:function(a){return Elm.Dict.foldl(function(b){return function(){return function(c){return a(b)(c)}}})}, -foldr:function(a){return Elm.Dict.foldr(function(b){return function(){return function(c){return a(b)(c)}}})},map:function(a){return function(b){b=m(b);return g(Elm.List.map(a)(b))}}}}(); -(function(){try{var e={};for(this.i in Elm)eval("var "+this.i+"=Elm[this.i];");if(Elm.Automaton)throw"Module name collision, 'Automaton' is already defined.";Elm.Automaton=function(){function b(a){return["Automaton",a]}function d(a){return b(function(b){var c=unzip(map(function(a){a:{switch(a[0]){case "Automaton":a=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return a})(a)),e;a:{switch(c[0]){case "Tuple2":e=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c= -c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",e,d(c)]})}function j(a){return b(function(b){return["Tuple2",a(b),j(a)]})}function a(c){return function(d){return b(function(b){b=d(b)(c);return["Tuple2",b,a(b)(d)]})}}function k(a){return function(c){return b(function(b){var d=c(b)(a);a:{switch(d[0]){case "Tuple2":b=d[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(d[0]){case "Tuple2":d=d[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2", -b,k(d)(c)]})}}function g(a){return function(b){a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":b=["Tuple2",a[1]-b[1],a[2]-b[2]];break b}break}break a}throw"Non-exhaustive pattern match in case";}return b}}function l(a){return function(b){var c;a:{switch(a[0]){case "Tuple2":b:{switch(b[0]){case "Tuple2":var d=function(a){return["Tuple2",b[2],["Tuple2",a,b[2]]]};c=function(){switch(b[1][0]){case "DragFrom":var c;a[1]?c=["Tuple2",uncurry(move)(g(a[2])(b[1][1]))(b[2]),["Tuple2",["DragFrom", -b[1][1]],b[2]]]:(c=uncurry(move)(g(a[2])(b[1][1]))(b[2]),c=["Tuple2",c,["Tuple2",f,c]]);return c;case "Ignore":return d(a[1]?v:f);case "Listen":return d(not(a[1])?f:isWithin(a[2])(b[2])?["DragFrom",a[2]]:v)}throw"Non-exhaustive pattern match in case";}();break b}break}break a}throw"Non-exhaustive pattern match in case";}return c}}try{if(!(Elm.Prelude instanceof Object))throw"module not found";}catch(h){throw"Module 'Prelude' is missing. Compile with --make flag or load missing module in a separate JavaScript file."; -}var c={};for(this.i in Elm.Prelude)c[this.i]||eval("var "+this.i+" = Elm.Prelude[this.i];");var f=["Listen"],v=["Ignore"];e[">>>"]=function(a){return function(c){var d;a:{switch(a[0]){case "Automaton":d=a[1];break a}throw"Non-exhaustive pattern match in case";}var f;a:{switch(c[0]){case "Automaton":f=c[1];break a}throw"Non-exhaustive pattern match in case";}return b(function(a){a=d(a);var b;a:{switch(a[0]){case "Tuple2":b=a[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(a[0]){case "Tuple2":a= -a[2];break a}throw"Non-exhaustive pattern match in case";}var c=f(b);a:{switch(c[0]){case "Tuple2":b=c[1];break a}throw"Non-exhaustive pattern match in case";}a:{switch(c[0]){case "Tuple2":c=c[2];break a}throw"Non-exhaustive pattern match in case";}return["Tuple2",b,e[">>>"](a)(c)]})}};e["<<<"]=function(a){return function(b){return e[">>>"](b)(a)}};e["^>>"]=function(a){return function(b){return e[">>>"](j(a))(b)}};e[">>^"]=function(a){return function(b){return e[">>>"](a)(j(b))}};e["^<<"]=function(a){return function(b){return e[">>>"](b)(j(a))}}; -e["<<^"]=function(a){return function(b){return e[">>>"](j(b))(a)}};c=a(0)(function(){return function(a){return 1+a}});return{$op:{">>>":e[">>>"],"<<<":e["<<<"],"^>>":e["^>>"],">>^":e[">>^"],"^<<":e["^<<"],"<<^":e["<<^"]},run:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=lift(fst)(foldp_(function(a){return function(b){a:{switch(b[0]){case "Tuple2":switch(b[2][0]){case "Automaton":b=b[2][1](a);break a}}throw"Non-exhaustive pattern match in case";}return b}})(a[1])(b));break a}throw"Non-exhaustive pattern match in case"; -}return b}},step:function(a){return function(b){a:{switch(a[0]){case "Automaton":b=a[1](b);break a}throw"Non-exhaustive pattern match in case";}return b}},combine:d,pure:j,init:a,init_:k,count:c,draggable:function(a){return k(["Tuple2",f,a])(l)}}}();Elm.main=function(){return Elm.Automaton.main}}catch(k){Elm.main=function(){document.body.innerHTML=Elm.Text.monospace('<br/><h2>Your browser may not be supported. Are you using a modern browser?</h2><br/><span style="color:grey">Runtime Error in Automaton module:<br/>'+ -k+"</span>");throw k;}}})(); \ No newline at end of file diff --git a/elm/src/Gen/CompileToJS.hs b/elm/src/Gen/CompileToJS.hs deleted file mode 100644 index 366e4c2..0000000 --- a/elm/src/Gen/CompileToJS.hs +++ /dev/null @@ -1,323 +0,0 @@ -module CompileToJS (showErr, jsModule) where - -import Ast -import Context -import Control.Arrow (first,second) -import Control.Monad (liftM,(<=<),join,ap) -import Data.Char (isAlpha,isDigit) -import Data.List (intercalate,sortBy,inits,foldl') -import qualified Data.Map as Map -import Data.Either (partitionEithers) -import qualified Text.Pandoc as Pan - -import Initialize -import Rename (derename) -import Cases -import Guid -import Parse.Library (isOp) -import Rename (deprime) - -showErr :: String -> String -showErr err = mainEquals $ "Elm.Graphics.text(Elm.Text.monospace(" ++ msg ++ "))" - where msg = show . concatMap (++"<br>") . lines $ err - -indent = concatMap f - where f '\n' = "\n " - f c = [c] - -parens s = "(" ++ s ++ ")" -braces s = "{" ++ s ++ "}" -jsList ss = "["++ intercalate "," ss ++"]" -jsFunc args body = "function(" ++ args ++ "){" ++ indent body ++ "}" -assign x e = "\nvar " ++ x ++ "=" ++ e ++ ";" -ret e = "\nreturn "++ e ++";" -iff a b c = a ++ "?" ++ b ++ ":" ++ c -quoted s = "'" ++ concatMap f s ++ "'" - where f '\n' = "\\n" - f '\'' = "\\'" - f '\t' = "\\t" - f '\"' = "\\\"" - f '\\' = "\\\\" - f c = [c] - -mainEquals s = globalAssign "Elm.main" (jsFunc "" (ret s)) -globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";" - -tryBlock escapees names e = - concat [ "\ntry{\n" ++ e ++ "\n} catch (e) {" - , "\nElm.main=function() {" - , "\nvar msg = ('<br/><h2>Your browser may not be supported. " ++ - "Are you using a modern browser?</h2>' +" ++ - " '<br/><span style=\"color:grey\">Runtime Error in " ++ - intercalate "." names ++ " module:<br/>' + e + '" ++ msg ++ "</span>');" - , "\ndocument.body.innerHTML = Elm.Text.monospace(msg);" - , "throw e;" - , "};}" - ] - where msg | escapees /= [] = concat [ "<br/><br/>The problem may stem from an improper usage of:<br/>" - , intercalate ", " $ map (concatMap escape) escapees ] - | otherwise = "" - escape '\'' = "\\'" - escape '"' = "\\\"" - escape c = [c] - - -jsModule (escapees, Module names exports imports stmts) = - tryBlock escapees (tail modNames) $ concat - [ concatMap (\n -> globalAssign n $ n ++ " || {}") . - map (intercalate ".") . drop 2 . inits $ - take (length modNames - 1) modNames - , "\nif (" ++ modName ++ ") throw new Error(\"Module name collision, '" ++ - intercalate "." (tail modNames) ++ "' is already defined.\"); " - , globalAssign modName $ jsFunc "" (defs ++ includes ++ body ++ export) ++ "()" - , mainEquals $ modName ++ ".main" ] - where modNames = if null names then ["Elm", "Main"] - else "Elm" : names - modName = intercalate "." modNames - includes = concatMap jsImport $ map (first ("Elm."++)) imports - body = stmtsToJS stmts - export = getExports exports stmts - exps = if null exports then ["main"] else exports - defs = concat [ assign "$op" "{}" - , "\nfor(Elm['i'] in Elm){eval('var '+Elm['i']+'=Elm[Elm.i];');}" ] - -getExports names stmts = ret . braces $ intercalate ",\n" (op : map fnPair fns) - where exNames n = either derename id n `elem` names - exports | null names = concatMap get stmts - | otherwise = filter exNames (concatMap get stmts) - - (fns,ops) = partitionEithers exports - - opPair op = "'" ++ op ++ "' : $op['" ++ op ++ "']" - fnPair fn = let fn' = derename fn in fn' ++ ":" ++ fn - - op = ("$op : "++) . braces . intercalate ", " $ map opPair ops - - get' (FnDef x _ _) = Left x - get' (OpDef op _ _ _) = Right op - get s = case s of Definition d -> [ get' d ] - Datatype _ _ tcs -> map (Left . fst) tcs - ImportEvent _ _ x _ -> [ Left x ] - ExportEvent _ _ _ -> [] - TypeAlias _ _ _ -> [] - TypeAnnotation _ _ -> [] - - -jsImport (modul, how) = - concat [ "\ntry{\n if (!(" ++ modul ++ " instanceof Object)) throw new Error('module not found');\n} catch(e) {\n throw new Error(\"Module '" - , drop 1 (dropWhile (/='.') modul) - , "' is missing. Compile with --make flag or load missing " - , "module in a separate JavaScript file.\");\n}" ] ++ - jsImport' (modul, how) - -jsImport' (modul, As name) = assign name modul -jsImport' (modul, Importing vs) = concatMap def vs - where def [] = [] - def (o:p) | isOp o = let v = "$op['" ++ o:p ++ "']" in - "\n" ++ v ++ " = " ++ modul ++ "." ++ v ++ ";" - | otherwise = let v = deprime (o:p) in - assign v $ modul ++ "." ++ v - -jsImport' (modul, Hiding vs) = - concat [ assign "hiddenVars" . ("{"++) . (++"}") . intercalate "," $ - map (\v -> v ++ ":true") (map deprime vs) - , "\nfor (Elm['i'] in " ++ modul ++ ") " - , braces . indent . concat $ - [ "\nif (hiddenVars[Elm['i']]) continue;" - , "\neval('var ' + Elm['i'] + ' = " - , modul, "[Elm.i];');" ] - ] - -stmtsToJS :: [Statement] -> String -stmtsToJS stmts = run (concat `liftM` mapM toJS (sortBy cmpStmt stmts)) - where cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2) - valueOf s = case s of - Datatype _ _ _ -> 1 - ImportEvent _ _ _ _ -> 2 - Definition (FnDef f [] _) -> - if derename f == "main" then 5 else 4 - Definition _ -> 3 - ExportEvent _ _ _ -> 6 - TypeAlias _ _ _ -> 0 - TypeAnnotation _ _ -> 0 - -class ToJS a where - toJS :: a -> GuidCounter String - -instance ToJS Def where - toJS (FnDef x [] e) = assign x `liftM` toJS' e - toJS (FnDef f (a:as) e) = - do body <- toJS' (foldr (\x e -> noContext (Lambda x e)) e as) - return $ concat ["\nfunction ",f,parens a, braces . indent $ ret body] - toJS (OpDef op a1 a2 e) = - do body <- toJS' (foldr (\x e -> noContext (Lambda x e)) e [a1,a2]) - return $ concat [ "\n$op['", op, "'] = ", body, ";" ] - -instance ToJS Statement where - toJS (Definition d) = toJS d - toJS (Datatype _ _ tcs) = concat `liftM` mapM (toJS . toDef) tcs - where toDef (name,args) = Definition . FnDef name vars . noContext $ - Data (derename name) (map (noContext . Var) vars) - where vars = map (('a':) . show) [1..length args] - toJS (ImportEvent js base elm _) = - do v <- toJS' base - return $ concat [ "\nvar " ++ elm ++ "=Elm.Signal.constant(" ++ v ++ ");" - , "\nValue.addListener(document, '" ++ js - , "', function(e) { Dispatcher.notify(" ++ elm - , ".id, e.value); });" ] - toJS (ExportEvent js elm _) = - return $ concat [ "\nlift(function(v) { " - , "var e = document.createEvent('Event');" - , "e.initEvent('", js, "', true, true);" - , "e.value = v;" - , "document.dispatchEvent(e); return v; })(", elm, ");" ] - toJS (TypeAnnotation _ _) = return "" - toJS (TypeAlias _ _ _) = return "" - -toJS' :: CExpr -> GuidCounter String -toJS' (C txt span expr) = - case expr of - MultiIf ps -> multiIfToJS span ps - Case e cases -> caseToJS span e cases - _ -> toJS expr - -remove x e = "elmRecordRemove('" ++ x ++ "', " ++ e ++ ")" -addField x v e = "elmRecordInsert('" ++ x ++ "', " ++ v ++ ", " ++ e ++ ")" -setField fs e = "elmRecordReplace(" ++ jsList (map f fs) ++ ", " ++ e ++ ")" - where f (x,v) = "['" ++ x ++ "'," ++ v ++ "]" -access x e = parens e ++ "." ++ x -makeRecord kvs = record `liftM` collect kvs - where - combine r (k,v) = Map.insertWith (++) k v r - collect = liftM (foldl' combine Map.empty) . mapM prep - prep (k, as, e@(C t s _)) = - do v <- toJS' (foldr (\x e -> C t s $ Lambda x e) e as) - return (k,[v]) - fields fs = - braces ("\n "++intercalate ",\n " (map (\(k,v) -> k++":"++v) fs)) - hidden = fields . map (second jsList) . - filter (not . null . snd) . Map.toList . Map.map tail - record kvs = fields . (("_", hidden kvs) :) . Map.toList . Map.map head $ kvs - - -instance ToJS Expr where - toJS expr = - case expr of - IntNum n -> return $ show n - FloatNum n -> return $ show n - Var x -> return $ x - Chr c -> return $ quoted [c] - Str s -> return $ "Value.str" ++ parens (quoted s) - Boolean b -> return $ if b then "true" else "false" - Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi - Access e x -> access x `liftM` toJS' e - Remove e x -> remove x `liftM` toJS' e - Insert e x v -> addField x `liftM` toJS' v `ap` toJS' e - Modify e fs -> do fs' <- (mapM (\(x,v) -> (,) x `liftM` toJS' v) fs) - setField fs' `liftM` toJS' e - Record fs -> makeRecord fs - Binop op e1 e2 -> binop op `liftM` toJS' e1 `ap` toJS' e2 - - If eb et ef -> - parens `liftM` (iff `liftM` toJS' eb `ap` toJS' et `ap` toJS' ef) - - Lambda v e -> liftM (jsFunc v . ret) (toJS' e) - - App (C _ _ (Var "toText")) (C _ _ (Str s)) -> - return $ "toText" ++ parens (quoted s) - - App (C _ _ (Var "link")) (C _ _ (Str s)) -> - return $ "link(" ++ quoted s ++ ")" - - App (C _ _ (Var "plainText")) (C _ _ (Str s)) -> - return $ "plainText(" ++ quoted s ++ ")" - - App e1 e2 -> (++) `liftM` (toJS' e1) `ap` (parens `liftM` toJS' e2) - Let defs e -> jsLet defs e - Data name es -> (\ss -> jsList $ quoted name : ss) `liftM` mapM toJS' es - - Markdown doc -> return $ "text('" ++ pad ++ md ++ pad ++ "')" - where pad = "<div style=\"height:0;width:0;\"> </div>" - md = formatMarkdown $ Pan.writeHtmlString Pan.def doc - -formatMarkdown = concatMap f - where f '\'' = "\\'" - f '\n' = "\\n" - f '"' = "\"" - f c = [c] - -multiIfToJS span ps = format `liftM` mapM f ps - where format cs = foldr (\c e -> parens $ c ++ " : " ++ e) err cs - err = concat [ "(function(){throw new Error(\"Non-exhaustive " - , "multi-way-if expression (", show span, ")\");}())" ] - f (b,e) = do b' <- toJS' b - e' <- toJS' e - return (b' ++ " ? " ++ e') - -jsLet defs e' = do - body <- (++) `liftM` jsDefs defs `ap` (ret `liftM` toJS' e') - return $ jsFunc "" body ++ "()" - -jsDefs defs = concat `liftM` mapM toJS (sortBy f defs) - where f a b = compare (valueOf a) (valueOf b) - valueOf (FnDef _ args _) = min 1 (length args) - valueOf (OpDef _ _ _ _) = 1 - -caseToJS span e ps = do - match <- caseToMatch ps - e' <- toJS' e - (match',stmt) <- case (match,e) of - (Match name _ _, C _ _ (Var x)) -> return (matchSubst [(name,x)] match, "") - (Match name _ _, _) -> return (match, assign name e') - _ -> liftM (\n -> (match, e')) guid - matches <- matchToJS span match' - return $ concat [ "function(){", stmt, matches, "}()" ] - -matchToJS span (Match name clauses def) = do - cases <- concat `liftM` mapM (clauseToJS span name) clauses - finally <- matchToJS span def - return $ concat [ "\nswitch(", name, "[0]){", indent cases, "\n}", finally ] -matchToJS span Fail = return ("\nthrow new Error(\"Non-exhaustive pattern match " ++ - "in case expression (" ++ show span ++ ")\");") -matchToJS span Break = return "break;" -matchToJS span (Other e) = ret `liftM` toJS' e -matchToJS span (Seq ms) = concat `liftM` mapM (matchToJS span) ms - -clauseToJS span var (Clause name vars e) = do - let vars' = map (\n -> var ++ "[" ++ show n ++ "]") [ 1 .. length vars ] - s <- matchToJS span $ matchSubst (zip vars vars') e - return $ concat [ "\ncase ", quoted name, ":", s ] - -jsNil = "[\"Nil\"]" -jsCons e1 e2 = jsList [ quoted "Cons", e1, e2 ] -jsRange e1 e2 = (++"()") . jsFunc "" $ - assign "lo" e1 ++ assign "hi" e2 ++ assign "lst" jsNil ++ - "if(lo<=hi){do{lst=" ++ (jsCons "hi" "lst") ++ "}while(hi-->lo)}" ++ - ret "lst" - -binop (o:p) e1 e2 - | isAlpha o || '_' == o = (o:p) ++ parens e1 ++ parens e2 - | otherwise = - let ops = ["+","-","*","/","&&","||"] in - case o:p of - "::" -> jsCons e1 e2 - "++" -> append e1 e2 - "$" -> e1 ++ parens e2 - "." -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x") - "^" -> "Math.pow(" ++ e1 ++ "," ++ e2 ++ ")" - "==" -> "eq(" ++ e1 ++ "," ++ e2 ++ ")" - "/=" -> "not(eq(" ++ e1 ++ "," ++ e2 ++ "))" - "<" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'LT')" - ">" -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'GT')" - "<=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ - e2 ++ ")[0]; return ord==='LT' || ord==='EQ'; }()" - ">=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ - e2 ++ ")[0]; return ord==='GT' || ord==='EQ'; }()" - "<~" -> "lift" ++ parens e1 ++ parens e2 - "~" -> "lift2(function(f){return function(x){return f(x);};})" ++ - parens e1 ++ parens e2 - _ | elem (o:p) ops -> parens (e1 ++ (o:p) ++ e2) - | otherwise -> concat [ "$op['", o:p, "']" - , parens e1, parens e2 ] - -append e1 e2 = "Value.append" ++ parens (e1 ++ "," ++ e2) diff --git a/elm/src/Gen/GenerateHtml.hs b/elm/src/Gen/GenerateHtml.hs deleted file mode 100644 index b18645d..0000000 --- a/elm/src/Gen/GenerateHtml.hs +++ /dev/null @@ -1,89 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -module GenerateHtml (generateHtml, - body, css, widgetBody, - modulesToHtml, linkedHtml, - JSStyle (..) - ) where - -import Data.List (intercalate) -import Text.Blaze (preEscapedToMarkup) -import Text.Blaze.Html (Html) -import qualified Text.Blaze.Html5 as H -import Text.Blaze.Html5 ((!)) -import qualified Text.Blaze.Html5.Attributes as A - -import Text.Jasmine (minify) -import qualified Data.ByteString.Lazy.Char8 as BS - -import Ast -import Initialize -import CompileToJS -import ExtractNoscript - -css = H.style ! A.type_ "text/css" $ preEscapedToMarkup - ("html,head,body { padding:0; margin:0; }\ - \body { font-family: helvetica, arial, sans-serif; }" :: String) - -data JSStyle = Minified | Readable - -makeScript :: JSStyle -> Either String String -> H.Html -makeScript _ (Left s) = - H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ "" -makeScript jsStyle (Right s) = - H.script ! A.type_ "text/javascript" $ preEscapedToMarkup content - where content = case jsStyle of - Minified -> BS.unpack . minify . BS.pack $ s - Readable -> s - --- |This function compiles Elm code into simple HTML. --- --- Usage example: --- --- > generateHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|] -generateHtml :: String -- ^ Location of elm-min.js as expected by the browser - -> String -- ^ The page title - -> String -- ^ The elm source code. - -> Html -generateHtml libLoc title source = - case buildFromSource source of - Left err -> createHtml Readable libLoc title (Right $ showErr err) (H.noscript "") - Right (escs, modul) -> modulesToHtml Readable title libLoc [] True [(escs,modul)] - - -modulesToHtml jsStyle title libLoc jss nscrpt pairs = - createHtml jsStyle libLoc title' js noscript - where modules = map snd pairs - js = Right $ jss ++ concatMap jsModule pairs - noscript = if nscrpt then extractNoscript $ last modules else "" - title' = if null title then altTitle else title - altTitle = (\(Module names _ _ _) -> intercalate "." names) $ - last modules - - -linkedHtml rtLoc jsLoc modules = - createHtml Readable rtLoc title (Left jsLoc) (H.noscript "") - where title = (\(Module names _ _ _) -> intercalate "." names) $ - snd (last modules) - - -createHtml jsStyle libLoc title js noscript = - H.docTypeHtml $ do - H.head $ do - H.meta ! A.charset "UTF-8" - H.title . H.toHtml $ title - css - H.body $ do - makeScript Readable (Left libLoc) - makeScript jsStyle js - body noscript - -body noscript = do - H.div ! A.id "widthChecker" ! A.style "width:100%; height:1px; position:absolute; top:-1px;" $ "" - H.div ! A.id "content" $ "" - H.script ! A.type_ "text/javascript" $ "Dispatcher.initialize()" - H.noscript $ preEscapedToMarkup noscript - -widgetBody noscript = do - H.div ! A.id "widthChecker" ! A.style "width:100%; height:1px; position:absolute; top:-1px;" $ "" - H.div ! A.id "content" $ "" - H.noscript $ preEscapedToMarkup noscript diff --git a/elm/src/Initialize.hs b/elm/src/Initialize.hs deleted file mode 100644 index 253de6a..0000000 --- a/elm/src/Initialize.hs +++ /dev/null @@ -1,95 +0,0 @@ -module Initialize (build,buildFromSource) where - -import Control.Applicative ((<$>)) -import Control.Monad.Error -import Data.List (lookup) - -import Ast -import Data.Either (lefts,rights) -import Data.List (intercalate,partition) -import Parse.Parser (parseProgram) -import Rename -import Types.Types ((-:)) -import Types.Hints (hints) -import Types.Unify -import Types.Alias -import Optimize - -checkMistakes :: Module -> Either String Module -checkMistakes modul@(Module name ex im stmts) = - case mistakes stmts of - m:ms -> Left (unlines (m:ms)) - [] -> return modul - -checkTypes :: Module -> Either String ([String], Module) -checkTypes (Module name ex im stmts) = - let stmts' = dealias stmts - modul = Module name ex im stmts' - in do (escapees, subs) <- unify hints modul - let im' | any ((=="Prelude") . fst) im = im - | otherwise = ("Prelude", Hiding []) : im - modul' = optimize . renameModule $ Module name ex im' stmts' - subs `seq` return (escapees, modul') - -check :: Module -> Either String ([String], Module) -check = checkMistakes >=> checkTypes - -buildFromSource :: String -> Either String ([String],Module) -buildFromSource = parseProgram >=> check - -build :: Bool -> FilePath -> IO (Either String ([String],[Module])) -build make root = do - proj <- parse make root - return $ do - ms <- proj - (escapeess, modules) <- unzip `liftM` mapM check ms - sortedModules <- (if make then sort else return) modules - return (concat escapeess, sortedModules) - -parse :: Bool -> FilePath -> IO (Either String [Module]) -parse make root = parseProject [] make root - -parseProject :: [FilePath] -> Bool -> FilePath -> IO (Either String [Module]) -parseProject seen make root = do - txt <- readFile root - case parseProgram txt of - Left err -> return (Left err) - Right modul@(Module names exs ims stmts) -> - let allDeps = map toFilePath (getDeps modul) - newDeps = if make then filter (`notElem` seen) allDeps else [] - name = intercalate "." names - in do ps <- mapM (parseProject (name : seen ++ newDeps) make) newDeps - return $ case unlines (lefts ps) of - c:cs -> Left (c:cs) - _ -> Right (modul : concat (rights ps)) - -toFilePath :: String -> FilePath -toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm" - -getDeps :: Module -> [String] -getDeps (Module _ _ is _) = filter (`notElem` builtInModules) (map fst is) - where - builtInModules = - ["List","Char","Either","Maybe","Dict","Set","Automaton","Date", - "Signal","Mouse","Keyboard.Raw","Keyboard","Touch", - "WebSocket","Window","Time","HTTP","Input","Random", - "Graphics","Text","Color","JavaScript", - "JavaScript.Experimental","Prelude","JSON"] - - -sort :: [Module] -> Either String [Module] -sort = go [] - where - msg = "A cyclical or missing module dependency or was detected in: " - getName (Module names _ _ _) = intercalate "." names - - has name modul = name == getName modul - within ms name = any (has name) ms - - go :: [Module] -> [Module] -> Either String [Module] - go sorted [] = Right sorted - go sorted unsorted = - case partition (all (within sorted) . getDeps) unsorted of - ([],m:ms) -> Left (msg ++ intercalate ", " (map getName (m:ms))) - (srtd,unsrtd) -> go (sorted ++ srtd) unsrtd - \ No newline at end of file diff --git a/elm/src/Language/Elm.hs b/elm/src/Language/Elm.hs deleted file mode 100644 index a57076e..0000000 --- a/elm/src/Language/Elm.hs +++ /dev/null @@ -1,82 +0,0 @@ -{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} -{- | This module exports the functions necessary for compiling Elm code into the - respective HTML, JS and CSS code. - - The type class @'ElmSource'@ requires an instance for all types that the Elm compiler - understands. The provided instances for String, Text and QuasiQuoted Elm source code - should be sufficient. - - The documentation for the Elm language is available at <http://elm-lang.org/Documentation.elm>, - and many interactive examples are available at <http://elm-lang.org/Examples.elm> - - Example implementations using Yesod and Happstack are available at <https://github.com/tazjin/Elm/tree/master/Examples> --} -module Language.Elm ( - ElmSource (..), - runtimeLocation - ) where - -import Data.Version (showVersion) -import CompileToJS -import ExtractNoscript -import GenerateHtml -import Initialize -import Text.Blaze.Html (Html) -import Language.Elm.Quasi -import Paths_Elm - -import qualified Data.Text as TS -import qualified Data.Text.Lazy as TL - --- |The absolute path to Elm's runtime system. -runtimeLocation :: IO FilePath -runtimeLocation = - getDataFileName ("elm-runtime-" ++ showVersion version ++ ".js") - -class ElmSource a where - -- |This function compiles Elm code to three separate parts: HTML, CSS, - -- and JavaScript. The HTML is only the contents of the body, so the three - -- parts must be combined in a basic HTML skeleton. - toParts :: a -> (Html, Html, String) - - -- |This function compiles Elm code into a full HTML page. - toHtml :: String -- ^ Location of elm-min.js as expected by the browser - -> String -- ^ The page title - -> a -- ^ The elm source code - -> Html - -instance ElmSource String where - toParts = toPartsHelper - toHtml = generateHtml - -instance ElmSource Elm where - toParts = toPartsHelper . TL.unpack . renderElm - toHtml elmL title = generateHtml elmL title . TL.unpack . renderElm - --- |Strict text -instance ElmSource TS.Text where - toParts = toPartsHelper . TS.unpack - toHtml elmL title = generateHtml elmL title . TS.unpack - --- |Lazy text -instance ElmSource TL.Text where - toParts = toPartsHelper . TL.unpack - toHtml elmL title = generateHtml elmL title . TL.unpack - --- | (urlRenderFn, urlRenderFn -> Elm) -instance ElmSource (t, t -> Elm) where - toParts (f, s) = toPartsHelper $ TL.unpack $ renderElm $ s f - toHtml elmL title (f, s) = generateHtml elmL title $ TL.unpack $ renderElm $ s f - --- | to be used without URL interpolation -instance ElmSource (t -> Elm) where - toParts s = toPartsHelper $ TL.unpack $ renderElm $ s undefined - toHtml l t s = generateHtml l t $ TL.unpack $ renderElm $ s undefined - - --- build helper to avoid boilerplate repetition -toPartsHelper :: String -> (Html, Html, String) -toPartsHelper source = (html, css, js) - where modul = buildFromSource source - js = either showErr jsModule modul - html = widgetBody $ either id (extractNoscript . snd) modul diff --git a/elm/src/Types/Hints.hs b/elm/src/Types/Hints.hs deleted file mode 100644 index 1f8d5d4..0000000 --- a/elm/src/Types/Hints.hs +++ /dev/null @@ -1,446 +0,0 @@ -module Types.Hints (hints) where - -import Context -import Control.Arrow (first) -import Control.Monad (liftM,mapM) -import Types.Types -import Types.Substitutions (rescheme) - -ctx str = C (Just str) NoSpan -prefix pre xs = map (first (\x -> pre ++ "." ++ x)) xs -hasType t = map (-: t) - - --------- Text and Elements -------- - -textToText = [ "header", "italic", "bold", "underline" - , "overline", "strikeThrough", "monospace" ] - -textAttrs = [ "toText" -: string ==> text - , "Text.typeface" -: string ==> text ==> text - , "Text.link" -:: string ==> text ==> text - , numScheme (\t -> t ==> text ==> text) "Text.height" - ] ++ prefix "Text" (hasType (text ==> text) textToText) - -elements = - let iee = int ==> element ==> element in - [ "plainText" -: string ==> element - , "link" -:: string ==> element ==> element - , "flow" -: direction ==> listOf element ==> element - , "layers" -: listOf element ==> element - , "text" -: text ==> element - , "image" -: int ==> int ==> string ==> element - , "video" -: int ==> int ==> string ==> element - , "opacity" -: float ==> element ==> element - , "width" -: iee - , "height" -: iee - , "size" -: int ==> iee - , "widthOf" -: element ==> int - , "heightOf"-: element ==> int - , "sizeOf" -: element ==> pairOf int - , "color" -: color ==> element ==> element - , "container" -: int ==> int ==> position ==> element ==> element - , "spacer" -: int ==> int ==> element - , "rightedText" -: text ==> element - , "centeredText" -: text ==> element - , "justifiedText" -: text ==> element - , "asText" -:: a ==> element - , "collage" -: int ==> int ==> listOf form ==> element - , "fittedImage" -: int ==> int ==> string ==> element - ] - -directions = hasType direction ["up","down","left","right","inward","outward"] -positions = - hasType position ["topLeft","midLeft","bottomLeft","midTop","middle" - ,"midBottom","topRight","midRight","bottomRight"] ++ - hasType (location ==> location ==> position) - ["topLeftAt","bottomLeftAt","middleAt","topRightAt","bottomRightAt"] ++ - [ "absolute" -: int ==> location, "relative" -: float ==> location ] - -lineTypes = [ numScheme (\n -> listOf (pairOf n) ==> line) "line" - , numScheme (\n -> pairOf n ==> pairOf n ==> line) "segment" - , "customLine" -: listOf int ==> color ==> line ==> form - ] ++ hasType (color ==> line ==> form) ["solid","dashed","dotted"] - -shapes = [ twoNums (\n m -> listOf (pairOf n) ==> pairOf m ==> shape) "polygon" - , "filled" -: color ==> shape ==> form - , "outlined" -: color ==> shape ==> form - , "textured" -: string ==> shape ==> form - , "customOutline" -: listOf int ==> color ==> shape ==> form - ] ++ map (twoNums (\n m -> n ==> n ==> pairOf m ==> shape)) [ "ngon" - , "rect" - , "oval" ] - -collages = [ numScheme (\n -> pairOf n ==> element ==> form) "toForm" - , numScheme (\n -> string ==> n ==> n ==> pairOf n ==> form) "sprite" - , numScheme (\n -> n ==> n ==> form ==> form) "move" - , numScheme (\n -> n ==> form ==> form) "rotate" - , numScheme (\n -> n ==> form ==> form) "scale" - , numScheme (\n -> pairOf n ==> form ==> bool) "isWithin" - ] - -graphicsElement = prefix "Graphics" - (concat [elements,directions,positions,lineTypes,shapes,collages]) -graphicsColor = prefix "Color" clrs - where clrs = [ numScheme (\n -> n ==> n ==> n ==> color) "rgb" - , numScheme (\n -> n ==> n ==> n ==> n ==> color) "rgba" - , "complement" -: color ==> color - ] ++ hasType color ["red","green","blue","black","white" - ,"yellow","cyan","magenta","grey","gray"] - - --------- Foreign -------- - -casts = - [ "castJSBoolToBool" -: jsBool ==> bool - , "castBoolToJSBool" -: bool ==> jsBool - , "castJSNumberToInt" -: jsNumber ==> int - , "castIntToJSNumber" -: int ==> jsNumber - , "castJSElementToElement" -: int ==> int ==> jsElement ==> element - , "castElementToJSElement" -: element ==> jsElement - , "castJSStringToString" -: jsString ==> string - , "castStringToJSString" -: string ==> jsString - , "castJSNumberToFloat" -: jsNumber ==> float - , "castFloatToJSNumber" -: float ==> jsNumber - ] - -castToTuple n = (,) name $ Forall [1..n] [] (jsTuple vs ==> tupleOf vs) - where vs = map VarT [1..n] - name = "castJSTupleToTuple" ++ show n -castToJSTuple n = (,) name $ Forall [1..n] [] (tupleOf vs ==> jsTuple vs) - where vs = map VarT [1..n] - name = "castTupleToJSTuple" ++ show n - -polyCasts = - map castToTuple [2..5] ++ map castToJSTuple [2..5] ++ - [ "castJSArrayToList" -:: jsArray a ==> listOf a - , "castListToJSArray" -:: listOf a ==> jsArray a - ] - -javascript = prefix "JavaScript" (concat [casts,polyCasts]) - -json = prefix "JSON" - [ "JsonString" -: string ==> jsonValue - , "JsonBool" -: bool ==> jsonValue - , "JsonNull" -: jsonValue - , "JsonArray" -: listOf jsonValue ==> jsonValue - , "JsonObject" -: jsonObject ==> jsonValue - , numScheme (\n -> n ==> jsonValue) "JsonNumber" - , "toString" -: jsonObject ==> string - , "fromString" -: string ==> maybeOf jsonObject - , "lookup" -: string ==> jsonObject ==> maybeOf jsonValue - , "findObject" -: string ==> jsonObject ==> jsonObject - , "findArray" -: string ==> jsonObject ==> listOf jsonValue - , "findString" -: string ==> jsonObject ==> string - , "findNumber" -: float ==> jsonObject ==> float - , "findWithDefault" -:: jsonValue ==> string ==> jsonObject ==> jsonValue - , "toPrettyString" -: string ==> jsonObject ==> string - , "toPrettyJSString" -: string ==> jsonObject ==> jsString - , "toList" -: jsonObject ==> listOf (tupleOf [string,jsonValue]) - , "fromList" -: listOf (tupleOf [string,jsonValue]) ==> jsonObject - , "toJSString" -: jsonObject ==> jsString - , "fromJSString" -: jsString ==> jsonObject - ] - - --------- Signals -------- - -lyft n = sig (n+1) ("lift" ++ show n) -sig n name = (,) name $ Forall [1..n] [] (fn ts ==> fn (map signalOf ts)) - where fn = foldr1 (==>) - ts = map VarT [1..n] - -signals = prefix "Signal" - [ sig 1 "constant" - , sig 2 "lift" - ] ++ map lyft [2..8] ++ [ - "<~" -:: (a ==> b) ==> signalOf a ==> signalOf b - , "~" -:: signalOf (a ==> b) ==> signalOf a ==> signalOf b - , "foldp" -:: (a ==> b ==> b) ==> b ==> signalOf a ==> signalOf b - , "foldp1" -:: (a ==> a ==> a) ==> signalOf a ==> signalOf a - , "foldp'" -:: (a ==> b ==> b) ==> (a ==> b) ==> signalOf a ==> signalOf b - , "count" -:: signalOf a ==> signalOf int - , "countIf" -:: (a ==> bool) ==> signalOf a ==> signalOf int - , "keepIf" -:: (a ==> bool) ==> a ==> signalOf a ==> signalOf a - , "dropIf" -:: (a ==> bool) ==> a ==> signalOf a ==> signalOf a - , "keepWhen" -:: signalOf bool ==> a ==> signalOf a ==> signalOf a - , "dropWhen" -:: signalOf bool ==> a ==> signalOf a ==> signalOf a - , "dropRepeats" -:: signalOf a ==> signalOf a - , "sampleOn" -:: signalOf a ==> signalOf b ==> signalOf b - , "timestamp" -:: signalOf a ==> signalOf (tupleOf [time,a]) - , "timeOf" -:: signalOf a ==> signalOf time - , "merge" -:: signalOf a ==> signalOf a ==> signalOf a - , "merges" -:: listOf (signalOf a) ==> signalOf a - , "mergeEither" -:: signalOf a ==> signalOf b ==> signalOf (eitherOf a b) - , numScheme (\n -> int ==> signalOf n ==> signalOf float) "average" - ] - -http = prefix "HTTP" - [ "send" -:: signalOf (request a) ==> signalOf (response string) - , "sendGet" -:: signalOf string ==> signalOf (response string) - , "get" -: string ==> request string - , "post" -: string ==> string ==> request string - , "request" -: string ==> string ==> string ==> listOf (pairOf string) ==> request string - , "Waiting" -:: response a - , "Failure" -:: int ==> string ==> response a - , "Success" -:: a ==> response a ] - where request t = ADT "Request" [t] - response t = ADT "Response" [t] - -concreteSignals = - [ "Random.inRange" -: int ==> int ==> signalOf int - , "Random.randomize" -:: int ==> int ==> signalOf a ==> signalOf int - , "Window.dimensions" -: signalOf point - , "Window.width" -: signalOf int - , "Window.height" -: signalOf int - , "Mouse.position" -: signalOf point - , "Mouse.x" -: signalOf int - , "Mouse.y" -: signalOf int - , "Mouse.isDown" -: signalOf bool - , "Mouse.isClicked" -: signalOf bool - , "Mouse.clicks" -: signalOf (tupleOf []) - , "Input.textField" -: string ==> tupleOf [element, signalOf string] - , "Input.password" -: string ==> tupleOf [element, signalOf string] - , "Input.textArea" -: int ==> int ==> tupleOf [element, signalOf string] - , "Input.checkBox" -: bool ==> tupleOf [element, signalOf bool] - , "Input.button" -: string ==> tupleOf [element, signalOf bool] - , "Input.stringDropDown" -: listOf string ==> tupleOf [element, signalOf string] - , "Input.dropDown" -:: listOf (tupleOf [string,a]) ==> tupleOf [element, signalOf a] - ] - -keyboards = prefix "Keyboard" - [ "Raw.keysDown" -: signalOf (listOf int) - , "Raw.charPressed" -: signalOf (maybeOf int) - , "arrows" -: signalOf (recordOf [("x",int),("y",int)]) - , "wasd" -: signalOf (recordOf [("x",int),("y",int)]) - , "ctrl" -: signalOf bool - , "space" -: signalOf bool - , "shift" -: signalOf bool - ] - -touches = prefix "Touch" - [ "touches" -: signalOf (listOf (recordOf [("x" ,int) ,("y" ,int) - ,("x0",int) ,("y0",int) - ,("t0",time),("id",int)])) - , "taps" -: signalOf (recordOf [("x",int),("y",int)]) - ] - -times = prefix "Time" - [ numScheme (\n -> n ==> signalOf time) "fps" - , numScheme (\n -> n ==> signalOf bool ==> signalOf time) "fpsWhen" - , "every" -: time ==> signalOf time - , "delay" -:: time ==> signalOf a ==> signalOf a - , "since" -:: time ==> signalOf a ==> signalOf bool - , "hour" -: time - , "minute" -: time - , "second" -: time - , "ms" -: time - , "inHours" -: time ==> float - , "inMinutes" -: time ==> float - , "inSeconds" -: time ==> float - , "inMss" -: time ==> float - , "toDate" -: time ==> date - , "read" -: string ==> maybeOf time - ] - -dates = - let days = map (-: day) ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] - months = map (-: month) [ "Jan", "Feb", "Mar", "Apr", "May", "Jun" - , "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] - in prefix "Date" - ([ "read" -: string ==> maybeOf date - , "year" -: date ==> int - , "month" -: date ==> month - , "day" -: date ==> int - , "hour" -: date ==> int - , "minute" -: date ==> int - , "second" -: date ==> int - , "dayOfWeek" -: date ==> day - , "toTime" -: date ==> time - ] ++ days ++ months) - --------- Math and Binops -------- - -binop t = t ==> t ==> t -scheme1 super t name = - (name, Forall [0] [ ctx name $ VarT 0 :<: super - ] (t (VarT 0))) -scheme2 s1 s2 t name = - (name, Forall [0,1] [ ctx name $ VarT 0 :<: s1 - , ctx name $ VarT 1 :<: s2 - ] (t (VarT 0) (VarT 1))) -numScheme t name = scheme1 number t name -twoNums f name = scheme2 number number f name - -math = - map (numScheme (\t -> t ==> binop t)) ["clamp"] ++ - map (numScheme (\t -> binop t)) ["+","-","*","max","min"] ++ - [ numScheme (\t -> t ==> t) "abs" ] ++ - hasType (binop float) [ "/", "logBase" ] ++ - hasType (binop int) ["rem","div","mod"] ++ - hasType (float ==> float) ["sin","cos","tan","asin","acos","atan","sqrt"] ++ - hasType float ["pi","e"] ++ - hasType (int ==> float) ["toFloat","castIntToFloat"] ++ - hasType (float ==> int) ["round","floor","ceiling","truncate"] ++ - [ "show" -:: a ==> string - , "readInt" -: string ==> maybeOf int - , "readFloat" -: string ==> maybeOf float ] - -bools = - [ "not" -: bool ==> bool ] ++ - hasType (binop bool) ["&&","||","xor"] ++ - map (scheme1 comparable (\t -> t ==> t ==> bool)) ["<",">","<=",">="] ++ - [ ( "compare" - , Forall [0,1] [ ctx "compare" $ VarT 0 :<: comparable ] (VarT 0 ==> VarT 0 ==> VarT 1) ) - ] - -chars = prefix "Char" (classify ++ convert1 ++ convert2) - where classify = hasType (char ==> bool) - ["isDigit","isOctDigit","isHexDigit","isUpper","isLower"] - convert1 = hasType (char ==> char) - ["toUpper","toLower","toLocaleUpper","toLocaleLower"] - convert2 = [ "toCode" -: char ==> int, "fromCode" -: int ==> char ] - - --------- Polymorphic Functions -------- - -[a,b,c] = map VarT [1,2,3] - -infix 8 -:: -name -:: tipe = (name, Forall [1,2,3] [] tipe) - -funcs = - [ "id" -:: a ==> a - , "==" -:: a ==> a ==> bool - , "/=" -:: a ==> a ==> bool - , "flip" -:: (a ==> b ==> c) ==> (b ==> a ==> c) - , "." -:: (b ==> c) ==> (a ==> b) ==> (a ==> c) - , "$" -:: (a ==> b) ==> a ==> b - , ":" -:: a ==> listOf a ==> listOf a - , (,) "++" . Forall [0,1] [ ctx "++" $ VarT 0 :<: appendable (VarT 1) ] $ VarT 0 ==> VarT 0 ==> VarT 0 - , "Cons" -:: a ==> listOf a ==> listOf a - , "Nil" -:: listOf a - , "Just" -:: a ==> maybeOf a - , "Nothing" -:: maybeOf a - , "Left" -:: a ==> eitherOf a b - , "Right" -:: b ==> eitherOf a b - , "curry" -:: (tupleOf [a,b] ==> c) ==> a ==> b ==> c - , "uncurry" -:: (a ==> b ==> c) ==> tupleOf [a,b] ==> c - ] ++ map tuple [0..8] - -tuple n = ("Tuple" ++ show n, Forall [1..n] [] $ foldr (==>) (tupleOf vs) vs) - where vs = map VarT [1..n] - -lists = prefix "List" - [ "and" -:: listOf bool ==> bool - , "or" -:: listOf bool ==> bool - , numScheme (\n -> listOf n ==> listOf n) "sort" - , "head" -:: listOf a ==> a - , "tail" -:: listOf a ==> listOf a - , "length" -:: listOf a ==> int - , "filter" -:: (a ==> bool) ==> listOf a ==> listOf a - , "foldr1" -:: (a ==> a ==> a) ==> listOf a ==> a - , "foldl1" -:: (a ==> a ==> a) ==> listOf a ==> a - , "scanl1" -:: (a ==> a ==> a) ==> listOf a ==> a - , "all" -:: (a ==> bool) ==> listOf a ==> bool - , "any" -:: (a ==> bool) ==> listOf a ==> bool - , "reverse" -:: listOf a ==> listOf a - , "take" -:: int ==> listOf a ==> listOf a - , "drop" -:: int ==> listOf a ==> listOf a - , "partition" -:: (a ==> bool) ==> listOf a ==> tupleOf [listOf a,listOf a] - , "intersperse" -:: a ==> listOf a ==> listOf a - , "zip" -:: listOf a ==>listOf b ==>listOf(tupleOf [a,b]) - , "map" -:: (a ==> b) ==> listOf a ==> listOf b - , "foldr" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b - , "foldl" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b - , "scanl" -:: (a ==> b ==> b) ==> b ==> listOf a ==> listOf b - , (,) "concat" . Forall [0,1] [ ctx "concat" $ VarT 0 :<: appendable (VarT 1) ] $ - listOf (VarT 0) ==> VarT 0 - , (,) "concatMap" . Forall [0,1,2] [ ctx "concatMap" $ VarT 0 :<: appendable (VarT 1) ] $ - (VarT 2 ==> VarT 0) ==> listOf (VarT 2) ==> VarT 0 - , (,) "intercalate" . Forall [0,1] [ ctx "intercalate" $ VarT 0 :<: appendable (VarT 1) ] $ - VarT 0 ==> listOf (VarT 0) ==> VarT 0 - , "zipWith" -:: (a ==> b ==> c) ==> listOf a ==> listOf b ==> listOf c - ] ++ map (numScheme (\n -> listOf n ==> n)) [ "sum", "product" - , "maximum", "minimum" ] - -maybeFuncs = prefix "Maybe" - [ "maybe" -:: b ==> (a ==> b) ==> maybeOf a ==> b - , "isJust" -:: maybeOf a ==> bool - , "isNothing" -:: maybeOf a ==> bool - , "cons" -:: maybeOf a ==> listOf a ==> listOf a - , "justs" -:: listOf (maybeOf a) ==> listOf a - ] - -eithers = prefix "Either" - [ "isLeft" -:: eitherOf a b ==> bool - , "isRight" -:: eitherOf a b ==> bool - , "either" -:: (a ==> c) ==> (b ==> c) ==> eitherOf a b ==> c - , "lefts" -:: listOf (eitherOf a b) ==> listOf a - , "rights" -:: listOf (eitherOf a b) ==> listOf b - , "partition" -:: listOf (eitherOf a b) ==> tupleOf [listOf a,listOf b] - ] - -dictionary = - let dict k v = ADT "Dict" [k,v] in - prefix "Dict" - [ "empty" -:: dict a b - , "singleton" -:: a ==> b ==> dict a b - , "insert" -:: a ==> b ==> dict a b ==> dict a b - , "remove" -:: a ==> dict a b ==> dict a b - , "member" -:: a ==> dict a b ==> bool - , "lookup" -:: a ==> dict a b ==> maybeOf b - , "findWithDefault" -:: b ==> a ==> dict a b ==> b - , "intersect" -:: dict a b ==> dict a c ==> dict a b - , "union" -:: dict a b ==> dict a b ==> dict a b - , "diff" -:: dict a b ==> dict a c ==> dict a b - , "map" -:: (b ==> c) ==> dict a b ==> dict a c - , "foldl" -:: (a ==> b ==> c ==> c) ==> c ==> dict a b ==> c - , "foldr" -:: (a ==> b ==> c ==> c) ==> c ==> dict a b ==> c - , "keys" -:: dict a b ==> listOf a - , "values" -:: dict a b ==> listOf b - , "toList" -:: dict a b ==> listOf (tupleOf [a,b]) - , "fromList" -:: listOf (tupleOf [a,b]) ==> dict a b - ] - -sets = - let set v = ADT "Set" [v] in - prefix "Set" - [ "empty" -:: set a - , "singleton" -:: a ==> set a - , "insert" -:: a ==> set a ==> set a - , "remove" -:: a ==> set a ==> set a - , "member" -:: a ==> set a ==> bool - , "intersect" -:: set a ==> set a ==> set a - , "union" -:: set a ==> set a ==> set a - , "diff" -:: set a ==> set a ==> set a - , "map" -:: (a ==> b) ==> set a ==> set b - , "foldl" -:: (a ==> b ==> b) ==> b ==> set a ==> b - , "foldr" -:: (a ==> b ==> b) ==> b ==> set a ==> b - , "toList" -:: set a ==> listOf a - , "fromList" -:: listOf a ==> set a - ] - -automaton = - let auto a b = ADT "Automaton" [a,b] in - prefix "Automaton" - [ "pure" -:: (a ==> b) ==> auto a b - , "init" -:: b ==> (a ==> b ==> b) ==> auto a b - , "init'" -:: c ==> (a ==> c ==> tupleOf [b,c]) ==> auto a b - , ">>>" -:: auto a b ==> auto b c ==> auto a c - , "<<<" -:: auto b c ==> auto a b ==> auto a c - , "combine" -:: listOf (auto a b) ==> auto a (listOf b) - , "run" -:: auto a b ==> signalOf a ==> signalOf b - , "step" -:: auto a b ==> a ==> tupleOf [b,auto a b] - , "count" -:: auto a int - , "draggable" -:: form ==> auto (tupleOf [bool,point]) form - ] - --------- Everything -------- - -hints = mapM (\(n,s) -> (,) n `liftM` rescheme s) (concat hs) - where hs = [ funcs, lists, signals, math, bools, textAttrs - , graphicsElement, graphicsColor, eithers, keyboards, touches - , concreteSignals, javascript, json, maybeFuncs - , http, dictionary, sets, automaton, times, dates - ] diff --git a/elm/src/Types/Types.hs b/elm/src/Types/Types.hs deleted file mode 100644 index 2de3239..0000000 --- a/elm/src/Types/Types.hs +++ /dev/null @@ -1,119 +0,0 @@ - -module Types.Types where - -import Context -import Data.Char (isDigit) -import Data.List (intercalate,isPrefixOf) -import qualified Data.Set as Set -import qualified Data.Map as Map - -type X = Int - -data Type = LambdaT Type Type - | VarT X - | ADT String [Type] - | EmptyRecord - | RecordT (Map.Map String [Type]) Type - | Super (Set.Set Type) - deriving (Eq, Ord) - -data Scheme = Forall [X] [Context Constraint] Type deriving (Eq, Ord) - -data Constraint = Type :=: Type - | Type :<: Type - | X :<<: Scheme - deriving (Eq, Ord, Show) - -recordT :: [(String,Type)] -> Map.Map String [Type] -recordT fields = - foldl (\r (x,t) -> Map.insertWith (++) x [t] r) Map.empty fields - -recordOf :: [(String,Type)] -> Type -recordOf fields = RecordT (recordT fields) EmptyRecord - -tipe t = ADT t [] - -int = tipe "Int" -float = tipe "Float" -number = Super (Set.fromList [ int, float ]) - -char = tipe "Char" -bool = tipe "Bool" - -string = listOf char -- tipe "String" -text = tipe "Text" - -time = float --tipe "Time" -date = tipe "Date" -month = tipe "Month" -day = tipe "Day" - -element = tipe "Element" -direction = tipe "Direction" -form = tipe "Form" -line = tipe "Line" -shape = tipe "Shape" -color = tipe "Color" -position = tipe "Position" -location = tipe "Location" - -listOf t = ADT "List" [t] -signalOf t = ADT "Signal" [t] -tupleOf ts = ADT ("Tuple" ++ show (length ts)) ts -maybeOf t = ADT "Maybe" [t] -eitherOf a b = ADT "Either" [a,b] -pairOf t = tupleOf [t,t] -point = pairOf int -appendable t = Super (Set.fromList [ string, text, listOf t ]) -comparable = Super (Set.fromList [ int, float, char, string, time, date ]) - -jsBool = tipe "JSBool" -jsNumber = tipe "JSNumber" -jsString = tipe "JSString" -jsElement = tipe "JSElement" -jsArray t = ADT "JSArray" [t] -jsTuple ts = ADT ("JSTuple" ++ show (length ts)) ts -jsonValue = tipe "JsonValue" -jsonObject = tipe "JsonObject" - -infixr ==> -t1 ==> t2 = LambdaT t1 t2 - -infix 8 -: -name -: tipe = (,) name $ Forall [] [] tipe - -parens = ("("++) . (++")") - -instance Show Type where - show t = - case t of - { LambdaT t1@(LambdaT _ _) t2 -> parens (show t1) ++ " -> " ++ show t2 - ; LambdaT t1 t2 -> show t1 ++ " -> " ++ show t2 - ; VarT x -> 't' : show x - ; ADT "List" [ADT "Char" []] -> "String" - ; ADT "List" [tipe] -> "[" ++ show tipe ++ "]" - ; ADT name cs -> - if isTupleString name - then parens . intercalate "," $ map show cs - else case cs of - [] -> name - _ -> parens $ name ++ " " ++ unwords (map show cs) - ; Super ts -> "{" ++ (intercalate "," . map show $ Set.toList ts) ++ "}" - ; EmptyRecord -> "{}" - ; RecordT fs t -> - start ++ intercalate ", " (concatMap fields $ Map.toList fs) ++ " }" - where field n s = n ++ " :: " ++ show s - fields (n,ss) = map (field n) ss - start = case t of - EmptyRecord -> "{ " - _ -> "{ " ++ show t ++ " | " - } - -instance Show Scheme where - show (Forall [] [] t) = show t - show (Forall xs cs t) = - concat [ "Forall ", show xs - , concatMap (("\n "++) . show) cs - , "\n ", parens (show t) ] - -isTupleString str = "Tuple" `isPrefixOf` str && all isDigit (drop 5 str) \ No newline at end of file diff --git a/elm/src/Types/Unify.hs b/elm/src/Types/Unify.hs deleted file mode 100644 index 4180558..0000000 --- a/elm/src/Types/Unify.hs +++ /dev/null @@ -1,19 +0,0 @@ - -module Types.Unify (unify) where - -import Control.Monad (liftM) -import qualified Data.Map as Map - -import Guid -import Types.Constrain -import Types.Solver - -unify hints modul = run $ do - constraints <- constrain hints modul - case constraints of - Left msg -> return (Left msg) - Right (escapees, cs) -> - do subs <- solver cs Map.empty - return $ do ss <- subs - return (escapees, ss) - diff --git a/libraries/Automaton.elm b/libraries/Automaton.elm new file mode 100644 index 0000000..ad95bc9 --- /dev/null +++ b/libraries/Automaton.elm @@ -0,0 +1,96 @@ +-- This library is a way to package up dynamic behavior. It makes it easier to +-- dynamically create dynamic components. See the [original release +-- notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how +-- it can be used. +module Automaton where + +data Automaton a b = Step (a -> (Automaton a b, b)) + +-- Run an automaton on a given signal. The automaton steps forward +-- whenever the input signal updates. +run : Automaton a b -> b -> Signal a -> Signal b +run (Step f) base inputs = + let step a (Step f, _) = f a + in lift snd $ foldp step base inputs + +-- Step an automaton forward once with a given input. +step : a -> Automaton a b -> (Automaton a b, b) +step a (Step f) = f a + +-- Compose two automatons, chaining them together. +(>>>) : Automaton a b -> Automaton b c -> Automaton a c +f >>> g = + Step (\a -> let (f', b) = step a f + (g', c) = step b g + in (f' >>> g', c)) + +-- Compose two automatons, chaining them together. +(<<<) : Automaton b c -> Automaton a b -> Automaton a c +g <<< f = f >>> g + +-- Combine a list of automatons into a single automaton that produces a list. +combine : [Automaton a b] -> Automaton a [b] +combine autos = + Step (\a -> let (autos', bs) = unzip $ map (step a) autos + in (combine autos', bs)) + +-- Create an automaton with no memory. It just applies the given function to +-- every input. +pure : (a -> b) -> Automaton a b +pure f = Step (\x -> (pure f, f x)) + +-- Create an automaton with state. Requires an initial state and a step +-- function to step the state forward. For example, an automaton that counted +-- how many steps it has taken would look like this: +-- +-- count = Automaton a Int +-- count = state 0 (\\_ c -> c+1) +-- +-- It is a stateful automaton. The initial state is zero, and the step function +-- increments the state on every step. +state : b -> (a -> b -> b) -> Automaton a b +state s f = Step (\x -> let s' = f x s + in (state s' f, s')) + +-- Create an automaton with hidden state. Requires an initial state and a +-- step function to step the state forward and produce an output. +hiddenState : s -> (a -> s -> (s,b)) -> Automaton a b +hiddenState s f = Step (\x -> let (s',out) = f x s + in (hiddenState s' f, out)) + +-- Count the number of steps taken. +count : Automaton a Int +count = state 0 (\_ c -> c + 1) + +type Queue t = ([t],[t]) +empty = ([],[]) +enqueue x (en,de) = (x::en, de) +dequeue q = case q of + ([],[]) -> Nothing + (en,[]) -> enqueue ([], reverse en) + (en,hd::tl) -> Just (hd, (en,tl)) + +-- Computes the running average of the last `n` inputs. +average : Int -> Automaton Float Float +average k = + let step n (ns,len,sum) = + if len == k then stepFull n (ns,len,sum) + else ((enqueue n ns, len+1, sum+n), (sum+n) / (len+1)) + stepFull n (ns,len,sum) = + case dequeue ns of + Nothing -> ((ns,len,sum), 0) + Just (m,ns') -> let sum' = sum + n - m + in ((enqueue n ns', len, sum'), sum' / len) + in hiddenState (empty,0,0) step + + +{-- TODO(evancz): See the following papers for ideas on how to make this +library faster and better: + +- Functional Reactive Programming, Continued +- Causal commutative arrows and their optimization + +Speeding things up is a really low priority. Language features and +libraries with nice APIs and are way more important! +--} + diff --git a/libraries/Char.elm b/libraries/Char.elm new file mode 100644 index 0000000..70c81b6 --- /dev/null +++ b/libraries/Char.elm @@ -0,0 +1,38 @@ + +module Char where + +import Native.Char as N + +-- True for upper case letters. +isUpper : Char -> Bool + +-- True for lower case letters. +isLower : Char -> Bool + +-- True for ASCII digits (`0..9`). +isDigit : Char -> Bool + +-- True for ASCII octal digits (`0..7`). +isOctDigit : Char -> Bool + +-- True for ASCII hexadecimal digits (`0..9a..fA..F`). +isHexDigit : Char -> Bool + +-- Convert to upper case. +toUpper : Char -> Char + +-- Convert to lower case. +toLower : Char -> Char + +-- Convert to upper case, according to any locale-specific case mappings. +toLocaleUpper : Char -> Char + +-- Convert to lower case, according to any locale-specific case mappings. +toLocaleLower : Char -> Char + +-- Convert to unicode. +toCode : Char -> KeyCode + +-- Convert from unicode. +fromCode : KeyCode -> Char + diff --git a/libraries/Color.elm b/libraries/Color.elm new file mode 100644 index 0000000..2761da3 --- /dev/null +++ b/libraries/Color.elm @@ -0,0 +1,87 @@ + +module Color where + +data Color = Color Int Int Int 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 = Color + +-- Create RGB colors from numbers between 0 and 255 inclusive. +rgb : Int -> Int -> Int -> Color +rgb r g b = Color r g b 1 + +red : Color +red = Color 255 0 0 1 +lime : Color +lime = Color 0 255 0 1 +blue : Color +blue = Color 0 0 255 1 + +yellow : Color +yellow = Color 255 255 0 1 +cyan : Color +cyan = Color 0 255 255 1 +magenta : Color +magenta = Color 255 0 255 1 + +black : Color +black = Color 0 0 0 1 +white : Color +white = Color 255 255 255 1 + +gray : Color +gray = Color 128 128 128 1 +grey : Color +grey = Color 128 128 128 1 + +maroon : Color +maroon = Color 128 0 0 1 +navy : Color +navy = Color 0 0 128 1 +green : Color +green = Color 0 128 0 1 + +teal : Color +teal = Color 0 128 128 1 +purple : Color +purple = Color 128 0 128 1 + +violet : Color +violet = Color 238 130 238 1 +forestGreen : Color +forestGreen = Color 34 139 34 1 + +-- Produce a “complementary color”. +-- The two colors will accent each other. +complement : Color -> Color + +-- Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV) +-- with an alpha component for transparency. +hsva : Float -> Float -> Float -> Float -> Color + +-- Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV). +-- This is very convenient for creating colors that cycle and shift. +-- +-- hsv (degrees 240) 1 1 == blue +hsv : Float -> Float -> Float -> Color + +data Gradient + = Linear (Float,Float) (Float,Float) [(Float,Color)] + | Radial (Float,Float) Float (Float,Float) Float [(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](/edit/examples/Elements/LinearGradient.elm) for +-- a more visual explanation. +linear : (Number a, Number a) -> (Number a, Number a) -> [(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](/edit/examples/Elements/RadialGradient.elm) for +-- a more visual explanation. +radial : (Number a,Number a) -> Number a -> (Number a,Number a) -> Number a -> [(Float,Color)] -> Gradient +radial = Radial diff --git a/libraries/Date.elm b/libraries/Date.elm new file mode 100644 index 0000000..a7c43ef --- /dev/null +++ b/libraries/Date.elm @@ -0,0 +1,50 @@ + +-- Library for working with dates. It is still a work in progress, so email +-- the mailing list if you are having issues with internationalization or +-- locale formatting or something. +module Date where + +-- Represents the days of the week. +data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun + +-- Represents the month of the year. +data Month = Jan | Feb | Mar | Apr + | May | Jun | Jul | Aug + | Sep | Oct | Nov | Dec + +-- Attempt to read a date from a string. +read : String -> Maybe Date + +-- Convert a date into a time since midnight (UTC) of 1 January 1990 (i.e. +-- [UNIX time](http://en.wikipedia.org/wiki/Unix_time)). Given the date 23 June +-- 1990 at 11:45AM this returns the corresponding time. +toTime : Date -> Time + +-- Extract the year of a given date. Given the date 23 June 1990 at 11:45AM +-- this returns the integer `1990`. +year : Date -> Int + +-- 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 + + +-- Extract the day of a given date. Given the date 23 June 1990 at 11:45AM +-- this returns the integer `23`. +day : Date -> Int + +-- Extract the day of the week for a given date. Given the date 23 June +-- 1990 at 11:45AM this returns the Day `Thu` as defined below. +dayOfWeek : Date -> Day + +-- Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM +-- this returns the integer `11`. +hour : Date -> Int + +-- Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM +-- this returns the integer `45`. +minute : Date -> Int + +-- Extract the second of a given date. Given the date 23 June 1990 at 11:45AM +-- this returns the integer `0`. +second : Date -> Int diff --git a/core/Dict.elm b/libraries/Dict.elm similarity index 59% rename from core/Dict.elm rename to libraries/Dict.elm index c45de71..33a9ea4 100644 --- a/core/Dict.elm +++ b/libraries/Dict.elm @@ -8,40 +8,41 @@ module Dict (empty,singleton,insert ,toList,fromList ) where -import Maybe (isJust) +import Maybe as Maybe +import Native.Error as Error +import List as List +import Native.Utils (compare) data NColor = Red | Black -data RBTree k v = RBNode NColor k v (RBTree k v) (RBTree k v) | RBEmpty +data Dict k v = RBNode NColor k v (Dict k v) (Dict k v) | RBEmpty -empty : RBTree k v +-- Create an empty dictionary. +empty : Dict (Comparable k) v empty = RBEmpty -raise err = throw (JavaScript.castStringToJSString err) - {-- Helpers for checking invariants -- Check that the tree has an equal number of black nodes on each path -equal_pathLen t = +equal_pathLen t = let path_numBlacks t = case t of - { RBEmpty -> 1 - ; RBNode col _ _ l r -> + RBEmpty -> 1 + RBNode col _ _ l r -> let { bl = path_numBlacks l ; br = path_numBlacks r } in if bl /= br || bl == 0-1 || br == 0-1 then 0-1 else bl + (if col == Red then 0 else 1) - } in 0-1 /= path_numBlacks t -rootBlack t = +rootBlack t = case t of - { RBEmpty -> True - ; RBNode Black _ _ _ _ -> True - ; _ -> False } + RBEmpty -> True + RBNode Black _ _ _ _ -> True + _ -> False -redBlack_children t = - case t of +redBlack_children t = + case t of { RBNode Red _ _ (RBNode Red _ _ _ _) _ -> False ; RBNode Red _ _ _ (RBNode Red _ _ _ _) -> False ; RBEmpty -> True @@ -56,7 +57,7 @@ findExtreme f t = { Nothing -> Just k ; Just k' -> Just k' } } - + findminRbt t = findExtreme fst t findmaxRbt t = findExtreme snd t @@ -82,7 +83,7 @@ ordered t = } -- Check that there aren't any right red nodes in the tree *) -leftLeaning t = +leftLeaning t = case t of { RBEmpty -> True ; RBNode _ _ _ (RBNode Black _ _ _ _) (RBNode Red _ _ _ _) -> False @@ -91,40 +92,43 @@ leftLeaning t = } invariants_hold t = - ordered t && rootBlack t && redBlack_children t && + ordered t && rootBlack t && redBlack_children t && equal_pathLen t && leftLeaning t --** End invariant helpers ***** --} -min : RBTree k v -> (k,v) +min : Dict k v -> (k,v) min t = - case t of + case t of RBNode _ k v RBEmpty _ -> (k,v) RBNode _ _ _ l _ -> min l - RBEmpty -> raise "(min RBEmpty) is not defined" + RBEmpty -> Error.raise "(min Empty) is not defined" {-- max t = - case t of + case t of { RBNode _ k v _ RBEmpty -> (k,v) ; RBNode _ _ _ _ r -> max r - ; RBEmpty -> raise "(max RBEmpty) is not defined" + ; RBEmpty -> Error.raise "(max Empty) is not defined" } --} -lookup : k -> RBTree k v -> Maybe v +-- Lookup the value associated with a key. +lookup : Comparable k -> Dict (Comparable k) v -> Maybe v lookup k t = case t of - RBEmpty -> Nothing + RBEmpty -> Maybe.Nothing RBNode _ k' v l r -> case compare k k' of LT -> lookup k l - EQ -> Just v + EQ -> Maybe.Just v GT -> lookup k r -findWithDefault : v -> k -> RBTree k v -> v +-- Find the value associated with a key. If the key is not found, +-- return the default value. +findWithDefault : v -> Comparable k -> Dict (Comparable k) v -> v findWithDefault base k t = case t of RBEmpty -> base @@ -135,9 +139,10 @@ findWithDefault base k t = GT -> findWithDefault base k r {-- +-- Find the value associated with a key. If the key is not found, there will be a runtime error. find k t = case t of - { RBEmpty -> raise "Key was not found in dictionary!" + { RBEmpty -> Error.raise "Key was not found in dictionary!" ; RBNode _ k' v l r -> case compare k k' of { LT -> find k l @@ -146,64 +151,66 @@ find k t = } --} +-- Determine if a key is in a dictionary. +member : Comparable k -> Dict (Comparable k) v -> Bool -- Does t contain k? -member : k -> RBTree k v -> Bool -member k t = isJust $ lookup k t +member k t = Maybe.isJust $ lookup k t -rotateLeft : RBTree k v -> RBTree k v +rotateLeft : Dict k v -> Dict k v rotateLeft t = case t of RBNode cy ky vy a (RBNode cz kz vz b c) -> RBNode cy kz vz (RBNode Red ky vy a b) c - _ -> raise "rotateLeft of a node without enough children" + _ -> Error.raise "rotateLeft of a node without enough children" --- rotateRight -- the reverse, and +-- rotateRight -- the reverse, and -- makes Y have Z's color, and makes Z Red. -rotateRight : RBTree k v -> RBTree k v +rotateRight : Dict k v -> Dict k v rotateRight t = case t of RBNode cz kz vz (RBNode cy ky vy a b) c -> RBNode cz ky vy a (RBNode Red kz vz b c) - _ -> raise "rotateRight of a node without enough children" + _ -> Error.raise "rotateRight of a node without enough children" -rotateLeftIfNeeded : RBTree k v -> RBTree k v +rotateLeftIfNeeded : Dict k v -> Dict k v rotateLeftIfNeeded t = - case t of + case t of RBNode _ _ _ _ (RBNode Red _ _ _ _) -> rotateLeft t _ -> t -rotateRightIfNeeded : RBTree k v -> RBTree k v +rotateRightIfNeeded : Dict k v -> Dict k v rotateRightIfNeeded t = - case t of + case t of RBNode _ _ _ (RBNode Red _ _ (RBNode Red _ _ _ _) _) _ -> rotateRight t _ -> t otherColor c = case c of { Red -> Black ; Black -> Red } -color_flip : RBTree k v -> RBTree k v +color_flip : Dict k v -> Dict k v color_flip t = case t of - RBNode c1 bk bv (RBNode c2 ak av la ra) (RBNode c3 ck cv lc rc) -> + RBNode c1 bk bv (RBNode c2 ak av la ra) (RBNode c3 ck cv lc rc) -> RBNode (otherColor c1) bk bv (RBNode (otherColor c2) ak av la ra) (RBNode (otherColor c3) ck cv lc rc) - _ -> raise "color_flip called on a RBEmpty or RBNode with a RBEmpty child" + _ -> Error.raise "color_flip called on a Empty or Node with a Empty child" -color_flipIfNeeded : RBTree k v -> RBTree k v -color_flipIfNeeded t = +color_flipIfNeeded : Dict k v -> Dict k v +color_flipIfNeeded t = case t of RBNode _ _ _ (RBNode Red _ _ _ _) (RBNode Red _ _ _ _) -> color_flip t _ -> t fixUp t = color_flipIfNeeded (rotateRightIfNeeded (rotateLeftIfNeeded t)) -ensureBlackRoot : RBTree k v -> RBTree k v -ensureBlackRoot t = +ensureBlackRoot : Dict k v -> Dict k v +ensureBlackRoot t = case t of RBNode Red k v l r -> RBNode Black k v l r _ -> t - --- Invariant: t is a valid left-leaning rb tree *) -insert : k -> v -> RBTree k v -> RBTree k v -insert k v t = + +-- Insert a key-value pair into a dictionary. Replaces value when there is +-- a collision. +insert : Comparable k -> v -> Dict (Comparable k) v -> Dict (Comparable k) v +insert k v t = -- Invariant: t is a valid left-leaning rb tree let ins t = case t of RBEmpty -> RBNode Red k v RBEmpty RBEmpty @@ -216,48 +223,49 @@ insert k v t = in ensureBlackRoot (ins t) {-- if not (invariants_hold t) then - raise "invariants broken before insert" + Error.raise "invariants broken before insert" else (let new_t = ensureBlackRoot (ins t) in if not (invariants_hold new_t) then - raise "invariants broken after insert" + Error.raise "invariants broken after insert" else new_t) --} -singleton : k -> v -> RBTree k v +-- Create a dictionary with one key-value pair. +singleton : Comparable k -> v -> Dict (Comparable k) v singleton k v = insert k v RBEmpty -isRed : RBTree k v -> Bool +isRed : Dict k v -> Bool isRed t = case t of RBNode Red _ _ _ _ -> True _ -> False -isRedLeft : RBTree k v -> Bool +isRedLeft : Dict k v -> Bool isRedLeft t = case t of RBNode _ _ _ (RBNode Red _ _ _ _) _ -> True _ -> False -isRedLeftLeft : RBTree k v -> Bool +isRedLeftLeft : Dict k v -> Bool isRedLeftLeft t = case t of RBNode _ _ _ (RBNode _ _ _ (RBNode Red _ _ _ _) _) _ -> True _ -> False -isRedRight : RBTree k v -> Bool +isRedRight : Dict k v -> Bool isRedRight t = case t of RBNode _ _ _ _ (RBNode Red _ _ _ _) -> True _ -> False -isRedRightLeft : RBTree k v -> Bool +isRedRightLeft : Dict k v -> Bool isRedRightLeft t = case t of RBNode _ _ _ _ (RBNode _ _ _ (RBNode Red _ _ _ _) _) -> True _ -> False -moveRedLeft : RBTree k v -> RBTree k v -moveRedLeft t = +moveRedLeft : Dict k v -> Dict k v +moveRedLeft t = let t' = color_flip t in case t' of RBNode c k v l r -> @@ -267,23 +275,23 @@ moveRedLeft t = _ -> t' _ -> t' -moveRedRight : RBTree k v -> RBTree k v +moveRedRight : Dict k v -> Dict k v moveRedRight t = let t' = color_flip t in if isRedLeftLeft t' then color_flip (rotateRight t') else t' -moveRedLeftIfNeeded : RBTree k v -> RBTree k v +moveRedLeftIfNeeded : Dict k v -> Dict k v moveRedLeftIfNeeded t = - if not (isRedLeft t) && not (isRedLeftLeft t) then moveRedLeft t else t + if isRedLeft t || isRedLeftLeft t then t else moveRedLeft t -moveRedRightIfNeeded : RBTree k v -> RBTree k v +moveRedRightIfNeeded : Dict k v -> Dict k v moveRedRightIfNeeded t = - if not (isRedRight t) && not (isRedRightLeft t) then moveRedRight t else t + if isRedRight t || isRedRightLeft t then t else moveRedRight t -deleteMin : RBTree k v -> RBTree k v -deleteMin t = +deleteMin : Dict k v -> Dict k v +deleteMin t = let del t = - case t of + case t of RBNode _ _ _ RBEmpty _ -> RBEmpty _ -> case moveRedLeftIfNeeded t of RBNode c k v l r -> fixUp (RBNode c k v (del l) r) @@ -303,22 +311,24 @@ deleteMax t = in ensureBlackRoot (del t) --} -remove : k -> RBTree k v -> RBTree k v -remove k t = +-- Remove a key-value pair from a dictionary. If the key is not found, +-- no changes are made. +remove : Comparable k -> Dict (Comparable k) v -> Dict (Comparable k) v +remove k t = let eq_and_noRightNode t = case t of { RBNode _ k' _ _ RBEmpty -> k == k' ; _ -> False } eq t = case t of { RBNode _ k' _ _ _ -> k == k' ; _ -> False } - delLT t = case moveRedLeftIfNeeded t of + delLT t = case moveRedLeftIfNeeded t of RBNode c k' v l r -> fixUp (RBNode c k' v (del l) r) - RBEmpty -> raise "delLT on RBEmpty" + RBEmpty -> Error.raise "delLT on Empty" delEQ t = case t of -- Replace with successor RBNode c _ _ l r -> let (k',v') = min r in fixUp (RBNode c k' v' l (deleteMin r)) - RBEmpty -> raise "delEQ called on a RBEmpty" + RBEmpty -> Error.raise "delEQ called on a Empty" delGT t = case t of RBNode c k' v l r -> fixUp (RBNode c k' v l (del r)) - RBEmpty -> raise "delGT called on a RBEmpty" - del t = case t of + RBEmpty -> Error.raise "delGT called on a Empty" + del t = case t of RBEmpty -> RBEmpty RBNode _ k' _ _ _ -> if k < k' then delLT t else @@ -329,47 +339,64 @@ remove k t = in if member k t then ensureBlackRoot (del t) else t {-- if not (invariants_hold t) then - raise "invariants broken before remove" + Error.raise "invariants broken before remove" else (let t' = ensureBlackRoot (del t) in if invariants_hold t' then t' else - raise "invariants broken after remove") + Error.raise "invariants broken after remove") --} -map : (a -> b) -> RBTree k a -> RBTree k b +-- Apply a function to all values in a dictionary. +map : (a -> b) -> Dict (Comparable k) a -> Dict (Comparable k) b map f t = case t of RBEmpty -> RBEmpty RBNode c k v l r -> RBNode c k (f v) (map f l) (map f r) -foldl : (k -> v -> b -> b) -> b -> RBTree k v -> b +-- Fold over the key-value pairs in a dictionary, in order from lowest +-- key to highest key. +foldl : (Comparable k -> v -> b -> b) -> b -> Dict (Comparable k) v -> b foldl f acc t = case t of RBEmpty -> acc RBNode _ k v l r -> foldl f (f k v (foldl f acc l)) r -foldr : (k -> v -> b -> b) -> b -> RBTree k v -> b +-- Fold over the key-value pairs in a dictionary, in order from highest +-- key to lowest key. +foldr : (Comparable k -> v -> b -> b) -> b -> Dict (Comparable k) v -> b foldr f acc t = case t of RBEmpty -> acc RBNode _ k v l r -> foldr f (f k v (foldr f acc r)) l -union : RBTree k v -> RBTree k v -> RBTree k v +-- Combine two dictionaries. If there is a collision, preference is given +-- to the first dictionary. +union : Dict (Comparable k) v -> Dict (Comparable k) v -> Dict (Comparable k) v union t1 t2 = foldl insert t2 t1 -intersect : RBTree k v -> RBTree k v -> RBTree k v -intersect t1 t2 = foldl (\k v t -> if k `member` t2 then insert k v t else t) empty 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 k) v -> Dict (Comparable k) v -> Dict (Comparable k) v +intersect t1 t2 = + let combine k v t = if k `member` t2 then insert k v t else t + in foldl combine empty t1 -diff : RBTree k v -> RBTree k v -> RBTree k v +-- Keep a key-value pair when its key does not appear in the second dictionary. +-- Preference is given to the first dictionary. +diff : Dict (Comparable k) v -> Dict (Comparable k) v -> Dict (Comparable k) v diff t1 t2 = foldl (\k v t -> remove k t) t1 t2 -keys : RBTree k v -> [k] +-- Get all of the keys in a dictionary. +keys : Dict (Comparable k) v -> [Comparable k] keys t = foldr (\k v acc -> k :: acc) [] t -values : RBTree k v -> [v] +-- Get all of the values in a dictionary. +values : Dict (Comparable k) v -> [v] values t = foldr (\k v acc -> v :: acc) [] t -toList : RBTree k v -> [(k,v)] +-- Convert a dictionary into an association list of key-value pairs. +toList : Dict (Comparable k) v -> [(Comparable k,v)] toList t = foldr (\k v acc -> (k,v) :: acc) [] t -fromList : [(k,v)] -> RBTree k v -fromList assocs = Elm.List.foldl (uncurry insert) empty assocs +-- Convert an association list into a dictionary. +fromList : [(Comparable k,v)] -> Dict (Comparable k) v +fromList assocs = List.foldl (\(k,v) d -> insert k v d) empty assocs diff --git a/libraries/Either.elm b/libraries/Either.elm new file mode 100644 index 0000000..eb9b98d --- /dev/null +++ b/libraries/Either.elm @@ -0,0 +1,51 @@ + +module Either where + +import List + +-- Represents any data that can take two different types. +-- +-- This can also be used for error handling `(Either String a)` where error +-- messages are stored on the left, and the correct values (“right” values) are stored on the right. +data Either a b = Left a | Right b + +-- Apply the first function to a `Left` and the second function to a `Right`. +-- This allows the extraction of a value from an `Either`. +either : (a -> c) -> (b -> c) -> Either a b -> c +either f g e = case e of { Left x -> f x ; Right y -> g y } + +-- True if the value is a `Left`. +isLeft : Either a b -> Bool +isLeft e = case e of { Left _ -> True ; _ -> False } + +-- True if the value is a `Right`. +isRight : Either a b -> Bool +isRight e = case e of { Right _ -> True ; _ -> False } + +-- Keep only the values held in `Left` values. +lefts : [Either a b] -> [a] +lefts es = List.foldr consLeft [] es + +-- Keep only the values held in `Right` values. +rights : [Either a b] -> [b] +rights es = List.foldr consRight [] es + +-- Split into two lists, lefts on the left and rights on the right. So we +-- have the equivalence: `(partition es == (lefts es, rights es))` +partition : [Either a b] -> ([a],[b]) +partition es = List.foldr consEither ([],[]) es + +consLeft e vs = + case e of + Left v -> v::vs + Right _ -> vs + +consRight e vs = + case e of + Left _ -> vs + Right v -> v::vs + +consEither e (ls,rs) = + case e of + Left l -> (l::ls,rs) + Right r -> (ls,r::rs) diff --git a/libraries/Graphics/Collage.elm b/libraries/Graphics/Collage.elm new file mode 100644 index 0000000..ae7b6ca --- /dev/null +++ b/libraries/Graphics/Collage.elm @@ -0,0 +1,205 @@ + +module Graphics.Collage where + +import List +import Native.Utils (toFloat) +import Either +import Native.Matrix2D as Matrix +import Native.Graphics.Collage as N +import Graphics.Element +import Color + +type Form = { + theta : Float, + scale : Float, + x : Float, + y : Float, + form : BasicForm + } + +data FillStyle + = Solid Color + | Texture String + | Gradient Gradient + +-- The shape of the ends of a line. +data LineCap = Flat | Round | Padded + +-- The shape of the “joints” of a line, where each line segment +-- meets. `Sharp` takes an argument to limit the length of the joint. This +-- defaults to 10. +data LineJoin = Smooth | Sharp Float | Clipped + +-- All of the attributes of a line style. This lets you build up a line style +-- however you want. You can also update existing line styles with record updates. +type LineStyle = { + color : Color, + width : Float, + cap : LineCap, + join : LineJoin, + dashing : [Int], + dashOffset : Int + } + +-- The default line style, which is solid black with flat caps and sharp joints. +-- You can use record updates to build the line style you +-- want. For example, to make a thicker line, you could say: +-- +-- { defaultLine | width <- 10 } +defaultLine : LineStyle +defaultLine = { + color = Color.black, + width = 1, + cap = Flat, + join = Sharp 10, + dashing = [], + dashOffset = 0 + } + +-- Create a solid line style with a given color. +solid : Color -> LineStyle +solid clr = { defaultLine | color <- clr } + +-- Create a dashed line style with a given color. Dashing equals `[8,4]`. +dashed : Color -> LineStyle +dashed clr = { defaultLine | color <- clr, dashing <- [8,4] } + +-- Create a dotted line style with a given color. Dashing equals `[3,3]`. +dotted : Color -> LineStyle +dotted clr = { defaultLine | color <- clr, dashing <- [3,3] } + +data BasicForm + = FPath LineStyle Path + | FShape (Either LineStyle FillStyle) Shape + | FImage Int Int (Int,Int) String + | FElement Element + | FGroup Matrix2D [Form] + +form f = { theta = 0, scale = 1, x = 0, y = 0, form = f } + +fill style shape = form (FShape (Either.Right style) shape) + +-- Create a filled in shape. +filled : Color -> Shape -> Form +filled color shape = fill (Solid color) shape + +-- Create a textured shape. The texture is described by some url and is +-- tiled to fill the entire shape. +textured : String -> Shape -> Form +textured src shape = fill (Texture src) shape + +-- Fill a shape with a [gradient](/docs/Color.elm#linear). +gradient : Gradient -> Shape -> Form +gradient grad shape = fill (Gradient grad) shape + +-- Outline a shape with a given line style. +outlined : LineStyle -> Shape -> Form +outlined style shape = form (FShape (Either.Left style) shape) + +-- Trace a path with a given line style. +traced : LineStyle -> Path -> Form +traced style path = form (FPath style path) + +-- Create a sprite from a sprite sheet. It cuts out a rectangle +-- at a given position. +sprite : Int -> Int -> (Int,Int) -> String -> Form +sprite w h pos src = form (FImage w h pos src) + +-- Turn any `Element` into a `Form`. This lets you use text, gifs, and video +-- in your collage. This means you can move, rotate, and scale +-- an `Element` however you want. +toForm : Element -> Form +toForm e = form (FElement e) + +-- Flatten many forms into a single `Form`. This lets you move and rotate them +-- as a single unit, making it possible to build small, modular components. +group : [Form] -> Form +group fs = form (FGroup Matrix.identity fs) + +-- Flatten many forms into a single `Form` and then apply a matrix +-- transformation. +groupTransform : Matrix2D -> [Form] -> Form +groupTransform matrix fs = form (FGroup matrix fs) + +-- Rotate a form by a given angle. Rotate takes standard Elm angles (radians) +-- and turns things counterclockwise. So to turn `form` 30° to the left +-- you would say, `(rotate (degrees 30) form)`. +rotate : Float -> Form -> Form +rotate t f = { f | theta <- f.theta + t } + +-- Scale a form by a given factor. Scaling by 2 doubles the size. +scale : Float -> Form -> Form +scale s f = { f | scale <- f.scale * s } + +-- Move a form by the given amount. This is a relative translation so +-- `(move (10,10) form)` would move `form` ten pixels up and ten pixels to the +-- right. +move : (Float,Float) -> Form -> Form +move (x,y) f = { f | x <- f.x + x, y <- f.y + y } + +-- Move a shape in the x direction. This is relative so `(moveX 10 form)` moves +-- `form` 10 pixels to the right. +moveX : Float -> Form -> Form +moveX x f = { f | x <- f.x + x } + +-- Move a shape in the y direction. This is relative so `(moveY 10 form)` moves +-- `form` upwards by 10 pixels. +moveY : Float -> Form -> Form +moveY y f = { f | y <- f.y + y } + +-- A collage is a collection of 2D forms. There are no strict positioning +-- relationships between forms, so you are free to do all kinds of 2D graphics. +collage : Int -> Int -> [Form] -> Element + + +type Path = [(Float,Float)] + +-- Create a path that follows a sequence of points. +path : [(Number a,Number a)] -> Path +path ps = ps + +-- Create a path along a given line segment. +segment : (Number a,Number a) -> (Number a,Number a) -> Path +segment p1 p2 = [p1,p2] + +type Shape = [(Float,Float)] + +-- Create an arbitrary polygon by specifying its corners in order. +-- `polygon` will automatically close all shapes, so the given list +-- of points does not need to start and end with the same position. +polygon : [(Number a,Number a)] -> Shape +polygon points = points + +-- A rectangle with a given width and height. +rect : Number a -> Number a -> Shape +rect w h = [ (0-w/2,0-h/2), (0-w/2,h/2), (w/2,h/2), (w/2,0-h/2) ] + +-- A square with a given edge length. +square : Number a -> Shape +square n = rect w h + +-- An oval with a given width and height. +oval : Number a -> Number a -> Shape +oval w h = + let n = 50 + t = 2 * Math.PI / n + hw = w/2 + hh = h/2 + f i = (hw * Math.cos (t*i), hh * Math.sin (t*i)) + in List.map f [0..n-1] + +-- A circle with a given radius. +circle : Number a -> Shape +circle r = oval (2*r) (2*r) + +-- A regular polygon with N sides. The first argument specifies the number +-- of sides and the second is the radius. So to create a pentagon with radius +-- 30 you would say: +-- +-- ngon 5 30 +ngon : Int -> Number a -> Shape +ngon n r = + let m = toFloat n + t = 2 * Math.PI / m + f i = ( r * Math.cos (t*i), r * Math.sin (t*i) ) + in List.map f [0..n-1] diff --git a/libraries/Graphics/Element.elm b/libraries/Graphics/Element.elm new file mode 100644 index 0000000..facd121 --- /dev/null +++ b/libraries/Graphics/Element.elm @@ -0,0 +1,255 @@ + +module Graphics.Element (widthOf, heightOf, sizeOf, + width, height, opacity, color, tag, link, + image, fittedImage, croppedImage, + flow, up, down, left, right, inward, outward, + above, below, beside, layers, + container, absolute, relative, + middle, topLeft, topRight, bottomLeft, bottomRight, + midLeft, midRight, midTop, midBottom, middleAt, + topLeftAt, topRightAt, bottomLeftAt, bottomRightAt, + midLeftAt, midRightAt, midTopAt, midBottomAt, + spacer, newElement + ) where + +import Native.Utils (guid, max, htmlHeight) +import JavaScript as JS +import List as List +import Color +import Maybe (Just, Nothing) + +type Properties = { + id : Int, + width : Int, + height : Int, + opacity : Float, + color : Maybe Color, + href : JSString, + tag : JSString + } + +type Element = { props : Properties, element : ElementPrim } + +-- Get the width of an Element +widthOf : Element -> Int +widthOf e = e.props.width + +-- Get the height of an Element +heightOf : Element -> Int +heightOf e = e.props.height + +-- Get the width and height of an Element +sizeOf : Element -> (Int,Int) +sizeOf e = (e.props.width, e.props.height) + +-- Create an `Element` with a given width. +width : Int -> Element -> Element +width nw e = let p = e.props + props = case e.element of + Image _ w h _ -> {p| height <- h/w*nw } + RawHtml html -> {p| height <- let (w,h) = htmlHeight nw html in h} + _ -> p + in { element=e.element, props={props| width <- nw} } + +-- Create an `Element` with a given height. +height : Int -> Element -> Element +height nh e = let p = e.props + props = case e.element of + Image _ w h _ -> {p| width <- w/h*nh } + _ -> p + in { element=e.element, props={p| height <- nh} } + +-- Create an `Element` with a given opacity. Opacity is a number between 0 and 1 +-- where 0 means totally clear. +opacity : Float -> Element -> Element +opacity o e = let p = e.props in { element=e.element, props={p| opacity <- o} } + +-- Create an `Element` with a given background color. +color : Color -> Element -> Element +color c e = let p = e.props in + { element=e.element, props={p| color <- Just c} } + +-- Create an `Element` with a tag. This lets you link directly to it. +-- The element `(tag "all-about-badgers" thirdParagraph)` can be reached +-- with a link lik this: `/facts-about-animals.elm#all-about-badgers` +tag : String -> Element -> Element +tag name e = let p = e.props in + { element=e.element, props={p| tag <- JS.fromString name} } + +-- Create an `Element` that is a hyper-link. +link : String -> Element -> Element +link href e = let p = e.props in + { element=e.element, props={p| href <- JS.fromString href} } + +emptyStr = JS.fromString "" +newElement w h e = + { props = Properties (guid ()) w h 1 Nothing emptyStr emptyStr, element = e } + +data ElementPrim + = Image ImageStyle Int Int JSString + | Container Position Element + | Flow Direction [Element] + | Spacer + | RawHtml JSString + | Custom -- for custom Elements implemented in JS, see collage for example + +data ImageStyle = Plain | Fitted | Cropped (Int,Int) + +-- Create an image given a width, height, and image source. +image : Int -> Int -> String -> Element +image w h src = newElement w h (Image Plain w h (JS.fromString src)) + +-- Create a fitted image given a width, height, and image source. +-- This will crop the picture to best fill the given dimensions. +fittedImage : Int -> Int -> String -> Element +fittedImage w h src = newElement w h (Image Fitted w h (JS.fromString src)) + +-- Create a cropped image. Take a rectangle out of the picture starting +-- at the given top left coordinate. If you have a 140-by-140 image, +-- the following will cut a 100-by-100 square out of the middle of it. +-- +-- croppedImage 100 100 (20,20) "yogi.jpg" +croppedImage : Int -> Int -> (Int,Int) -> String -> Element +croppedImage w h pos src = + newElement w h (Image (Cropped pos) w h (JS.fromString src)) + +data Three = P | Z | N +data Pos = Absolute Int | Relative Float +type Position = { horizontal : Three, vertical : Three, x : Pos, y : Pos } + +-- Put an element in a container. This lets you position the element really +-- easily, and there are tons of ways to set the `Position`. +-- To center `element` exactly in a 300-by-300 square you would say: +-- +-- container 300 300 middle element +-- +-- By setting the color of the container, you can create borders. +container : Int -> Int -> Position -> Element -> Element +container w h pos e = newElement w h (Container pos e) + +-- Create an empty box. This is useful for getting your spacing right and +-- for making borders. +spacer : Int -> Int -> Element +spacer w h = newElement w h Spacer + +data Direction = DUp | DDown | DLeft | DRight | DIn | DOut + +-- Have a list of elements flow in a particular direction. +-- The `Direction` starts from the first element in the list. +-- +-- flow right [a,b,c] +-- +-- +---+---+---+ +-- | a | b | c | +-- +---+---+---+ +flow : Direction -> [Element] -> Element +flow dir es = + let ws = List.map widthOf es + hs = List.map heightOf es + newFlow w h = newElement w h (Flow dir es) + in + if es == [] then spacer 0 0 else + case dir of + DUp -> newFlow (List.maximum ws) (List.sum hs) + DDown -> newFlow (List.maximum ws) (List.sum hs) + DLeft -> newFlow (List.sum ws) (List.maximum hs) + DRight -> newFlow (List.sum ws) (List.maximum hs) + DIn -> newFlow (List.maximum ws) (List.maximum hs) + DOut -> newFlow (List.maximum ws) (List.maximum hs) + +-- Stack elements vertically. To put `a` above `b` you would say: +-- +-- a `above` b +above : Element -> Element -> Element +above hi lo = + newElement (max (widthOf hi) (widthOf lo)) + (heightOf hi + heightOf lo) + (Flow DDown [hi,lo]) + +-- Stack elements vertically. To put `a` below `b` you would say: +-- +-- a `below` b +below : Element -> Element -> Element +below lo hi = + newElement (max (widthOf hi) (widthOf lo)) + (heightOf hi + heightOf lo) + (Flow DDown [hi,lo]) + +-- Put elements beside each other horizontally. +beside : Element -> Element -> Element +beside lft rht = + newElement (widthOf lft + widthOf rht) + (max (heightOf lft) (heightOf rht)) + (Flow right [lft,rht]) + +-- Layer elements on top of each other, starting from the bottom. +-- `(layers == flow outward)` +layers : [Element] -> Element +layers es = + let ws = List.map widthOf es + hs = List.map heightOf es + in newElement (List.maximum ws) (List.maximum hs) (Flow DOut es) + + +-- Repetitive things -- + +absolute : Int -> Pos +absolute = Absolute +relative : Float -> Pos +relative = Relative + +middle : Position +middle = { horizontal=Z, vertical=Z, x=Relative 0.5, y=Relative 0.5 } +topLeft : Position +topLeft = { horizontal=N, vertical=P, x=Absolute 0, y=Absolute 0 } +topRight : Position +topRight = { topLeft | horizontal <- P } +bottomLeft : Position +bottomLeft = { topLeft | vertical <- N } +bottomRight : Position +bottomRight = { bottomLeft | horizontal <- P } +midLeft : Position +midLeft = { middle | horizontal <- N, x <- Absolute 0 } +midRight : Position +midRight = { midLeft | horizontal <- P } +midTop : Position +midTop = { middle | vertical <- P, y <- Absolute 0 } +midBottom : Position +midBottom = { midTop | vertical <- N } + +middleAt : Pos -> Pos -> Position +middleAt x y = { horizontal = Z, vertical = Z, x = x, y = y } +topLeftAt : Pos -> Pos -> Position +topLeftAt x y = { horizontal = N, vertical = P, x = x, y = y } +topRightAt : Pos -> Pos -> Position +topRightAt x y = { horizontal = P, vertical = P, x = x, y = y } +bottomLeftAt : Pos -> Pos -> Position +bottomLeftAt x y = { horizontal = N, vertical = N, x = x, y = y } +bottomRightAt : Pos -> Pos -> Position +bottomRightAt x y = { horizontal = P, vertical = N, x = x, y = y } +midLeftAt : Pos -> Pos -> Position +midLeftAt x y = { horizontal = N, vertical = Z, x = x, y = y } +midRightAt : Pos -> Pos -> Position +midRightAt x y = { horizontal = P, vertical = Z, x = x, y = y } +midTopAt : Pos -> Pos -> Position +midTopAt x y = { horizontal = Z, vertical = P, x = x, y = y } +midBottomAt : Pos -> Pos -> Position +midBottomAt x y = { horizontal = Z, vertical = N, x = x, y = y } + +up : Direction +up = DUp + +down : Direction +down = DDown + +left : Direction +left = DLeft + +right : Direction +right = DRight + +inward : Direction +inward = DIn + +outward : Direction +outward = DOut \ No newline at end of file diff --git a/libraries/Graphics/Input.elm b/libraries/Graphics/Input.elm new file mode 100644 index 0000000..2f53b02 --- /dev/null +++ b/libraries/Graphics/Input.elm @@ -0,0 +1,119 @@ + +module Graphics.Input where + +import Signal (lift) +import Native.Graphics.Input as N + +id x = x + +-- Create a group of buttons. +-- +-- * The first argument is the default value of the `events` signal. +-- * The `events` signal represents all of the activity in this group +-- of buttons. +-- * The `button` function creates a button +-- with the given name, like “Submit” or “Cancel”. +-- The `a` value is sent to `events` whenever the button is pressed. +buttons : a -> { events : Signal a, + button : a -> String -> Element } + +-- Create a button with a given label. The result is an `Element` and +-- a signal of units. This signal triggers whenever the button is pressed. +button : String -> (Element, Signal ()) +button txt = + let pool = N.buttons () + in (pool.button () txt, pool.events) + +-- Create a group of custom buttons. +-- +-- * The first argument is the default value of the `events` signal. +-- * The `events` signal represents all of the activity in this group +-- of custom buttons. +-- * The `customButton` function creates a button with three different visual +-- states, one for up, hovering, and down. The resulting button has dimensions +-- large enough to fit all three possible `Elements`. +-- The `a` value is sent to `events` whenever the button is pressed. +customButtons : a -> { events : Signal a, + customButton : a -> Element -> Element -> Element -> Element } + +-- Create a button with custom states for up, hovering, and down +-- (given in that order). The result is an `Element` and +-- a signal of units. This signal triggers whenever the button is pressed. +customButton : Element -> Element -> Element -> (Element, Signal ()) +customButton up hover down = + let pool = N.customButtons () + in (pool.button () up hover down, pool.events) + +-- Create a group of checkboxes. +-- +-- * The first argument is the default value of the `events` signal. +-- * The `events` signal represents all of the activity in this group +-- of checkboxes. +-- * The `checkbox` function creates a +-- checkbox with a given state. The `(Bool -> a)` function is used +-- when the checkbox is modified. It takes the new state and turns +-- it into a value that can be sent to `events`. For example, this +-- lets you add an ID to distinguish between checkboxes. +checkboxes : a -> { events : Signal a, + checkbox : (Bool -> a) -> Bool -> Element } + +-- Create a checkbox with a given start state. Unlike `button`, this result +-- is a *signal* of elements. That is because a checkbox has state that +-- updates based on user input. +-- The boolean signal represents the current state of the checkbox. +checkbox : Bool -> (Signal Element, Signal Bool) +checkbox b = + let cbs = N.checkboxes b + in (lift (cbs.box id) cbs.events, cbs.events) + +-- Represents the current state of a text field. The `string` represents the +-- characters filling the text field. The `selectionStart` and `selectionEnd` +-- values represent what the user has selected with their mouse or keyboard. +-- For example: +-- +-- { string="She sells sea shells", selectionStart=3, selectionEnd=0 } +-- +-- This means the user highlighted the substring `"She"` backwards. +type FieldState = { string:String, selectionStart:Int, selectionEnd:Int } + +-- Create a group of text input fields. +-- +-- * The first argument is the default value of the `events` signal. +-- * The `events` signal represents all of the activity in this group +-- of text fields. +-- * The `field` function creates a +-- field with the given ghost text and initial field state. +-- When the field is modified, the `(FieldState -> a)` function +-- takes the new state and turns +-- it into a value that can be sent to `events`. For example, this +-- lets you add an ID to distinguish between input fields. +fields : a -> { events : Signal a, + field : (FieldState -> a) -> String -> FieldState -> Element } + +-- The empty field state: +-- +-- { string="", selectionStart=0, selectionEnd=0 } +emptyFieldState : FieldState +emptyFieldState = { string="", selectionStart=0, selectionEnd=0 } + +-- Create a field with the given default text. The output is an element that +-- updates to match the user input and a signal of strings representing the +-- content of the field. +field : String -> (Signal Element, Signal String) +field placeHolder = + let tfs = N.fields emptyFieldState + in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events) + +-- Same as `field` but the UI element blocks out each characters. +password : String -> (Signal Element, Signal String) +password placeHolder = + let tfs = N.passwords emptyFieldState + in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events) + +-- Same as `field` but it adds an annotation that this field is for email +-- addresses. This is helpful for auto-complete and for mobile users who may +-- get a custom keyboard with an `@` and `.com` button. +email : String -> (Signal Element, Signal String) +email placeHolder = + let tfs = N.emails emptyFieldState + in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events) diff --git a/libraries/Http.elm b/libraries/Http.elm new file mode 100644 index 0000000..57094af --- /dev/null +++ b/libraries/Http.elm @@ -0,0 +1,43 @@ +-- A library for asynchronous HTTP requests (AJAX). See the +-- [WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if +-- you have very strict latency requirements. + +module Http where + +import Native.Http (send) +import Signal (lift) + +-- The datatype for responses. Success contains only the returned message. +-- Failures contain both an error code and an error message. +data Response a = Success a | Waiting | Failure Int String + +type Request a = { + verb : String, + url : String, + body : a, + headers : [(String,String)] + } + +-- Create a customized request. Arguments are request type (get, post, put, +-- delete, etc.), target url, data, and a list of additional headers. +request : String -> String -> String -> [(String,String)] -> Request String +request = Request + +-- Create a GET request to the given url. +get : String -> Request String +get url = Request "GET" url "" [] + +-- Create a POST request to the given url, carrying the given data. +post : String -> String -> Request String +post url body = Request "POST" url body [] + + +-- Performs an HTTP request with the given requests. Produces a signal +-- that carries the responses. +send : Signal (Request a) -> Signal (Response String) + +-- Performs an HTTP GET request with the given urls. Produces a signal +-- that carries the responses. +sendGet : Signal String -> Signal (Response String) +sendGet reqs = send (lift get reqs) + diff --git a/libraries/JavaScript.elm b/libraries/JavaScript.elm new file mode 100644 index 0000000..5e712a9 --- /dev/null +++ b/libraries/JavaScript.elm @@ -0,0 +1,26 @@ + +module JavaScript where + + +-- Requires that the input array be uniform (all members have the same type) +toList : JSArray a -> [a] +toInt : JSNumber -> Int +toFloat : JSNumber -> Float +toBool : JSBool -> Bool +toString : JSString -> String + + +-- Produces a uniform JavaScript array with all members of the same type. +fromList : [a] -> JSArray a +fromInt : Int -> JSNumber +fromFloat : Float -> JSNumber +fromBool : Bool -> JSBool +fromString : String -> JSString + + +-- Turn an `Element` into a plain old DOM node. +fromElement : Element -> JSDomNode + +-- Turn a DOM node into an `Element`. You can resize the node +-- using the normal `width` and `height` functions. +toElement : Int -> Int -> JSDomNode -> Element diff --git a/libraries/JavaScript/Experimental.elm b/libraries/JavaScript/Experimental.elm new file mode 100644 index 0000000..250988c --- /dev/null +++ b/libraries/JavaScript/Experimental.elm @@ -0,0 +1,31 @@ + +module JavaScript.Experimental where + +import JavaScript as JS + +-- Turn arbitrary JavaScript objects into Elm records. +-- Arrays are converted into lists, nested objects are allowed. +-- No `null` values or non-homogeneous arrays. +-- +-- -- OK objects +-- { student:"Steve", scores:[83,94,99,72] } +-- { errorLevel:10, critical:true } +-- +-- -- BAD objects +-- { answer:null } +-- { info:[true,42,'what'] } +toRecord : JSObject -> a +toRecord = JS.toRecord + +-- Turn arbitrary Elm records into JavaScript objects. +-- Lists become arrays, nested records are allowed. No ADTs. +-- +-- -- OK records +-- { student="Steve", scores=[83,94,99,72] } +-- { errorLevel=10, critical=True } +-- +-- -- BAD records +-- { answer = Nothing } +-- { result = Left "An error occurred" } +fromRecord : a -> JSObject +fromRecord = JS.fromRecord \ No newline at end of file diff --git a/libraries/Json.elm b/libraries/Json.elm new file mode 100644 index 0000000..5ed3259 --- /dev/null +++ b/libraries/Json.elm @@ -0,0 +1,112 @@ + +-- TOOD: Evan please review texts + +module Json where + +import Dict as Dict +import JavaScript as JS +import Native.Json as Native + +-- This datatype can represent all valid values that can be held in a JSON +-- object. In Elm, a proper JSON object is represented as a (Dict String JsonValue) +-- which is a mapping from strings to Json Values. +data JsonValue + = String String + | Number Float + | Boolean Bool + | Null + | Array [JsonValue] + | Object (Dict String JsonValue) + + +-- String Converters + +-- Convert a `JsonValue` into a prettified string. +-- The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will +-- be used for indentation in the prettified string version of the JSON. +toString : String -> JsonValue -> String +toString sep v = JS.toString (Native.toJSString sep v) + +-- Convert a proper JSON object into a JavaScript string. +-- Note that the type JSString seen here is not the same as the type constructor +-- JsonString used elsewhere in this module. +toJSString : String -> JsonValue -> JSString + +-- Parse a string representation of a proper JSON object into +-- its Elm representation. +fromString : String -> Maybe JsonValue +fromString s = Native.fromJSString (JS.fromString s) + +-- Parse a JavaScript string representation of a proper JSON object into +-- its Elm representation. +fromJSString : JSString -> Maybe JsonValue + +-- Convert a JS object into a `JsonValue`. +fromJSObject : JSObject -> JsonValue + +-- Convert a `JsonValue` into a `JSObject`. Paired with the +-- [`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm), +-- This lets you convert strings into Elm records: +-- +-- import JavaScript.Experimental as JS +-- +-- stringToRecord str = +-- case fromString str of +-- Just jsonValue -> Just (JS.toRecord (toJSObject jsonValue)) +-- Nothing -> Nothing +toJSObject : JsonValue -> JSObject + + {-- Extract Elm values from Json values + + string : JsonValue -> String + string v = case v of { String s -> s ; _ -> "" } + + number : JsonValue -> Float + number v = case v of { Number n -> n ; _ -> 0 } + + boolean : JsonValue -> Bool + boolean v = case v of { Boolean b -> b ; _ -> False } + + array : JsonValue -> [JsonValue] + array v = case v of { Array a -> a ; _ -> [] } + + object : JsonValue -> Dict String JsonValue + object v = case v of { Object o -> o ; _ -> Dict.empty } + + + -- Extract Elm values from dictionaries of Json values + + -- Find a value in a Json Object using the passed get function. If the key is + -- not found, this returns the given default/base value. + find get base = + let f key dict = + case Dict.lookup key dict of + Nothing -> base + Just v -> get v + in f + + -- Find a string value in an Elm Json object. If the key is not found or the + -- value found is not a string, this returns the empty string. + findString : String -> Object -> String + findString = find string "" + + -- Find a number value in an Elm Json object. If the key is not found or the + -- value found is not a number, this returns 0 + findNumber : String -> Object -> Float + findNumber = find number 0 + + -- Find a boolean value in an Elm Json object. If the key is not found or the + -- value found is not a boolean, this returns the False. + findBoolean : String -> Object -> Bool + findBoolean = find boolean False + + -- Find an array value in an Elm Json object. If the key is not found or the + -- value found is not an array, this returns an empty list. + findArray : String -> Object -> [JsonValue] + findArray = find array [] + + -- Find an object value in an Elm Json object. If the key is not found or the + -- value found is not an object, this returns an empty object. + findObject : String -> Object -> Object + findObject = find object Dict.empty + --} \ No newline at end of file diff --git a/libraries/Keyboard.elm b/libraries/Keyboard.elm new file mode 100644 index 0000000..07ac22b --- /dev/null +++ b/libraries/Keyboard.elm @@ -0,0 +1,52 @@ +module Keyboard where + +import Native.Keyboard as N + +-- Type alias to make it clearer what integers are supposed to represent +-- in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and +-- [`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters. +type KeyCode = Int + +-- A signal of records indicating which arrow keys are pressed. +-- +-- `{ x = 0, y = 0 }` when pressing no arrows.<br> +-- `{ x =-1, y = 0 }` when pressing the left arrow.<br> +-- `{ x = 1, y = 1 }` when pressing the up and right arrows.<br> +-- `{ x = 0, y =-1 }` when pressing the down, left, and right arrows. +arrows : Signal { x:Int, y:Int } +arrows = N.directions 38 40 37 39 + +-- Just like the arrows signal, but this uses keys w, a, s, and d, +-- which are common controls for many computer games. +wasd : Signal { x:Int, y:Int } +wasd = N.directions 87 83 65 68 + +-- Custom key directions so that you can support different locales. +-- The plan is to have a locale independent version of this function +-- that uses the physical location of keys, but I don't know how to do it. +directions : KeyCode -> KeyCode -> KeyCode -> KeyCode -> Signal { x:Int, y:Int } + +-- Whether an arbitrary key is pressed. +isDown : KeyCode -> Signal Bool + +-- Whether the shift key is pressed. +shift : Signal Bool +shift = N.isDown 16 + +-- Whether the control key is pressed. +ctrl : Signal Bool +ctrl = N.isDown 17 + +-- Whether the space key is pressed. +space : Signal Bool +space = N.isDown 32 + +-- Whether the enter key is pressed. +enter : Signal Bool +enter = N.isDown 13 + +-- List of keys that are currently down. +keysDown : Signal [KeyCode] + +-- The latest key that has been pressed. +lastPressed : Signal KeyCode diff --git a/libraries/List.elm b/libraries/List.elm new file mode 100644 index 0000000..341910f --- /dev/null +++ b/libraries/List.elm @@ -0,0 +1,155 @@ + +module List where + +import Native.Utils (min, max) +import Native.List as L + +-- Add an element to the front of a list `(1 :: [2,3] == [1,2,3])` +(::) : a -> [a] -> [a] + +-- Puts two appendable things together: +-- +-- [1,1] ++ [2,3] == [1,1,2,3] +-- "abc" ++ "123" == "abc123" +(++) : Appendable a -> Appendable a -> Appendable a + +-- Extract the first element of a list. List must be non-empty. +-- `(head [1,2,3] == 1)` +head : [a] -> a + +-- Extract the elements after the head of the list. List must be non-empty. +-- `(tail [1,2,3] == [2,3])` +tail : [a] -> [a] + +-- Extract the last element of a list. List must be non-empty. +-- `(last [1,2,3] == 3)` +last : [a] -> a + +-- Apply a function to every element of a list: `(map sqrt [1,4,9] == [1,2,3])` +map : (a -> b) -> [a] -> [b] + +-- Reduce a list from the left: `(foldl (::) [] "gateman" == "nametag")` +foldl : (a -> b -> b) -> b -> [a] -> b + +-- Reduce a list from the right: `(foldr (+) 0 [1,2,3] == 6)` +foldr : (a -> b -> b) -> b -> [a] -> b + +-- Reduce a list from the left without a base case. List must be non-empty. +foldl1 : (a -> a -> a) -> [a] -> a + +-- Reduce a list from the right without a base case. List must be non-empty. +foldr1 : (a -> a -> a) -> [a] -> a + +-- 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 -> [a] -> [b] + +-- Same as scanl but it doesn't require a base case. List must be non-empty. +-- +-- scanl1 (+) [1,2,3,4] == [1,3,6,10] +scanl1 : (a -> a -> a) -> [a] -> [a] + +-- Filter out elements which do not satisfy the predicate: `(filter isLower "AaBbCc" == "abc")` +filter : (a -> Bool) -> [a] -> [a] + +-- Determine the length of a list: `(length "innumerable" == 11)` +length : [a] -> Int + +-- Reverse a list. `(reverse [1..4] == [4,3,2,1])` +reverse : [a] -> [a] + +-- Check to see if all elements satisfy the predicate. +all : (a -> Bool) -> [a] -> Bool + +-- Check to see if any elements satisfy the predicate. +any : (a -> Bool) -> [a] -> Bool + +-- Check to see if all elements are True. +and : [Bool] -> Bool + +-- Check to see if any elements are True. +or : [Bool] -> Bool + +-- Concatenate a list of appendable things: +-- +-- concat ["tree","house"] == "treehouse" +concat : [Appendable a] -> Appendable a + +-- Map a given function onto a list and flatten the resulting lists. +-- +-- concatMap f xs == concat (map f xs) +concatMap : (a -> Appendable b) -> [a] -> Appendable b +concatMap f = L.concat . L.map f + +-- Get the sum of the list elements. `(sum [1..4] == 10)` +sum : [Number a] -> Number a +sum = L.foldl (+) 0 + +-- Get the product of the list elements. `(product [1..4] == 24)` +product : [Number a] -> Number a +product = L.foldl (*) 1 + +-- Find the highest number in a non-empty list. +maximum : [Number a] -> Number a +maximum = L.foldl1 max + +-- Find the lowest number in a non-empty list. +minimum : [Number a] -> Number a +minimum = L.foldl1 min + +-- Split a list based on the predicate. +partition : (a -> Bool) -> [a] -> ([a],[a]) +partition pred lst = + case lst of + [] -> ([],[]) + x::xs -> let (bs,cs) = partition pred xs in + if pred x then (x::bs,cs) else (bs,x::cs) + +-- Combine two lists, combining them into tuples pairwise. +-- If one list is longer, the extra elements are dropped. +-- +-- zip [1,2,3] [6,7] == [(1,6),(2,7)] +-- zip == zipWith (,) +zip : [a] -> [b] -> [(a,b)] + +-- Combine two lists, combining them with the given function. +-- If one list is longer, the extra elements are dropped. +-- +-- zipWith (+) [1,2,3] [1,2,3,4] == [2,4,6] +zipWith : (a -> b -> c) -> [a] -> [b] -> [c] + +-- Decompose a list of tuples. +unzip : [(a,b)] -> ([a],[b]) +unzip pairs = + case pairs of + [] -> ([],[]) + (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys) + +-- Split a list with a given seperator. +-- +-- split "," "hello,there,friend" == ["hello", "there", "friend"] +split : [a] -> [a] -> [[a]] + +-- Places the given value between all of the lists in the second argument +-- and concatenates the result. +-- +-- join "a" ["H","w","ii","n"] == "Hawaiian" +join : Appendable a -> [Appendable a] -> Appendable a + +-- Places the given value between all members of the given list. +-- +-- intersperse ' ' "INCEPTION" == "I N C E P T I O N" +intersperse : a -> [a] -> [a] +intersperse sep xs = + case xs of + a::b::cs -> a :: sep :: intersperse sep (b::cs) + [a] -> [a] + [] -> [] + +-- Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])` +take : Int -> [a] -> [a] + +-- Drop the first n members of a list: `(drop 2 [1,2,3,4] == [3,4])` +drop : Int -> [a] -> [a] + diff --git a/libraries/Matrix2D.elm b/libraries/Matrix2D.elm new file mode 100644 index 0000000..849e8d0 --- /dev/null +++ b/libraries/Matrix2D.elm @@ -0,0 +1,36 @@ + +module Matrix2D where + +import Native.Matrix2D as M + +-- Create an identity matrix. +-- +-- / 1 0 \\ +-- \\ 0 1 / +identity : Matrix2D + +-- Creates an arbitrary matrix. This lets you create scales, shears, reflections, +-- translations, or any other 2D transform. +-- +-- matrix a b c d dx dy +-- +-- / a b \\ +-- \\ c d / +-- +-- And `dx` and `dy` are the translation values. +matrix : Float -> Float -> Float -> Float -> Float -> Float -> Matrix2D + +-- Creates a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix). +-- Given an angle t, it creates a counterclockwise rotation matrix: +-- +-- / cos t -sin t \\ +-- \\ sin t cos t / +rotation : Float -> Matrix2D + +-- Multiplies two matrices together: +-- +-- multiply a b +-- +-- / a11 a12 \\ . / b11 b12 \\ +-- \\ a21 a22 / \\ b21 b22 / +multiply : Matrix2D -> Matrix2D -> Matrix2D diff --git a/libraries/Maybe.elm b/libraries/Maybe.elm new file mode 100644 index 0000000..918f419 --- /dev/null +++ b/libraries/Maybe.elm @@ -0,0 +1,33 @@ + +module Maybe where + +import List as List + +-- The Maybe datatype. Useful when a computation may or may not +-- result in a value (e.g. logarithm is defined only for positive numbers). +data Maybe a = Just a | Nothing + +-- Apply a function to the contents of a `Maybe`. +-- Return default when given `Nothing`. +maybe : b -> (a -> b) -> Maybe a -> b +maybe b f m = case m of + Just v -> f v + Nothing -> b + +-- Check if constructed with `Just`. +isJust : Maybe a -> Bool +isJust = maybe False (\_ -> True) + +-- Check if constructed with `Nothing`. +isNothing : Maybe a -> Bool +isNothing = not . isJust + + +-- If `Just`, adds the value to the front of the list. +-- If `Nothing`, list is unchanged. +cons : Maybe a -> [a] -> [a] +cons mx xs = maybe xs (\x -> x :: xs) mx + +-- Filters out Nothings and extracts the remaining values. +justs : [Maybe a] -> [a] +justs = List.foldr cons [] diff --git a/libraries/Mouse.elm b/libraries/Mouse.elm new file mode 100644 index 0000000..ccfd7cc --- /dev/null +++ b/libraries/Mouse.elm @@ -0,0 +1,24 @@ + +module Mouse where + +import Native.Mouse as M + +-- The current mouse position. +position : Signal (Int,Int) + +-- The current x-coordinate of the mouse. +x : Signal Int + +-- The current y-coordinate of the mouse. +y : Signal Int + +-- The current state of the left mouse-button. +-- True when the button is down, and false otherwise. +isDown : Signal Bool + +-- True immediately after the left mouse-button has been clicked, +-- and false otherwise. +isClicked : Signal Bool + +-- Always equal to unit. Event triggers on every mouse click. +clicks : Signal () diff --git a/libraries/Native/Char.js b/libraries/Native/Char.js new file mode 100644 index 0000000..191a834 --- /dev/null +++ b/libraries/Native/Char.js @@ -0,0 +1,31 @@ + +Elm.Native.Char = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Char) return elm.Native.Char; + + function isBetween(lo,hi) { return function(chr) { + var c = chr.charCodeAt(0); + return lo <= c && c <= hi; + }; + } + var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0)); + var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0)); + var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0)); + + return elm.Native.Char = { + fromCode : function(c) { return String.fromCharCode(c); }, + toCode : function(c) { return c.charCodeAt(0); }, + toUpper : function(c) { return c.toUpperCase(); }, + toLower : function(c) { return c.toLowerCase(); }, + toLocaleUpper : function(c) { return c.toLocaleUpperCase(); }, + toLocaleLower : function(c) { return c.toLocaleLowerCase(); }, + isLower : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)), + isUpper : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)), + isDigit : isDigit, + isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)), + isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); } + }; + +}; diff --git a/libraries/Native/Color.js b/libraries/Native/Color.js new file mode 100644 index 0000000..ff79f6c --- /dev/null +++ b/libraries/Native/Color.js @@ -0,0 +1,71 @@ + + +Elm.Native.Color = function(elm) { + "use strict"; + + elm.Native = elm.Native || {}; + if (elm.Native.Color) return elm.Native.Color; + + var Utils = Elm.Native.Utils(elm); + + function complement(rgb) { + var hsv = toHSV(rgb); + hsv.hue = (hsv.hue + 180) % 360; + return toRGB(hsv); + } + + function hsva(h,s,v,a) { + var degree = A2(Utils.mod, h * 180 / Math.PI, 360); + var clr = toRGB({hue:degree, saturation:s, value:v}); + clr._3 = a; + return clr; + } + + function hsv(h,s,v) { + var degree = A2(Utils.mod, h * 180 / Math.PI, 360); + return toRGB({hue:degree, saturation:s, value:v}); + } + + function toHSV(rgb) { + var hsv = {}; + var r = rgb._0 / 255.0, g = rgb._1 / 255.0, b = rgb._2 / 255.0; + var M = Math.max(r,g,b); + var m = Math.min(r,g,b); + var c = M - m; + + var h = 0; + if (c === 0) { h = 0; } + else if (M === r) { h = ((g - b) / c) % 6; } + else if (M === g) { h = ((b - r) / c) + 2; } + else if (M === b) { h = ((r - g) / c) + 4; } + h *= 60; + + return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) }; + } + + function between(lo,hi,x) { return lo <= x && x < hi; } + function norm(n) { return Math.round(n*255); } + + function toRGB(hsv) { + var c = hsv.value * hsv.saturation; + var hue = hsv.hue / 60; + var x = c * (1 - Math.abs((hue % 2) - 1)); + var r = 0, g = 0, b = 0; + if (between(0,1,hue)) { r = c; g = x; b = 0; } + else if (between(1,2,hue)) { r = x; g = c; b = 0; } + else if (between(2,3,hue)) { r = 0; g = c; b = x; } + else if (between(3,4,hue)) { r = 0; g = x; b = c; } + else if (between(4,5,hue)) { r = x; g = 0; b = c; } + else if (between(5,6,hue)) { r = c; g = 0; b = x; } + + var m = hsv.value - c; + return { ctor:"Color", _0:norm(r+m), _1:norm(g+m), _2:norm(b+m), _3:1 }; + } + + return elm.Native.Color = { + hsva:F4(hsva), + hsv:F3(hsv), + complement:complement + }; + +}; \ No newline at end of file diff --git a/libraries/Native/Date.js b/libraries/Native/Date.js new file mode 100644 index 0000000..f2dbe55 --- /dev/null +++ b/libraries/Native/Date.js @@ -0,0 +1,34 @@ + +Elm.Native.Date = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Date) return elm.Native.Date; + + var JS = Elm.JavaScript(elm); + var Maybe = Elm.Maybe(elm); + + function dateNow() { return new window.Date; } + function readDate(str) { + var d = new window.Date(JS.fromString(str)); + if (isNaN(d.getTime())) return Maybe.Nothing; + return Maybe.Just(d); + } + + var dayTable = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + var monthTable = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + + return elm.Native.Date = { + read : readDate, + 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(); }, + toTime : function(d) { return d.getTime(); }, + dayOfWeek : function(d) { return { ctor:dayTable[d.getDay()] }; } + }; + +}; diff --git a/libraries/Native/Error.js b/libraries/Native/Error.js new file mode 100644 index 0000000..a3aa28a --- /dev/null +++ b/libraries/Native/Error.js @@ -0,0 +1,22 @@ + +Elm.Native.Error = function(elm) { + 'use strict'; + elm.Native = elm.Native || {}; + if (elm.Native.Error) return elm.Native.Error; + + var fromString = Elm.Native.JavaScript(elm).fromString; + + function Case(span) { + var msg = 'Non-exhaustive pattern match in case expression' + throw new Error(msg + " (" + span + ")") + } + + function If(span) { + var msg = 'Non-exhaustive pattern match in multi-way-if expression' + throw new Error(msg + " (" + span + ")") + } + + function raise(str) { throw new Error(fromString(str)); } + + return elm.Native.Error = { Case: Case, If: If, raise: raise }; +}; \ No newline at end of file diff --git a/libraries/Native/Function.js b/libraries/Native/Function.js new file mode 100644 index 0000000..47fe5e5 --- /dev/null +++ b/libraries/Native/Function.js @@ -0,0 +1,101 @@ + +function F2(fun) { + function wrapper(a) { return function(b) { return fun(a,b) } } + wrapper.arity = 2; + wrapper.func = fun; + return wrapper; +} + +function F3(fun) { + function wrapper(a) { + return function(b) { return function(c) { return fun(a,b,c) }} + } + wrapper.arity = 3; + wrapper.func = fun; + return wrapper; +} + +function F4(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return fun(a,b,c,d) }}} + } + wrapper.arity = 4; + wrapper.func = fun; + return wrapper; +} + +function F5(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return fun(a,b,c,d,e) }}}} + } + wrapper.arity = 5; + wrapper.func = fun; + return wrapper; +} + +function F6(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return fun(a,b,c,d,e,f) }}}}} + } + wrapper.arity = 6; + wrapper.func = fun; + return wrapper; +} + +function F7(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return fun(a,b,c,d,e,f,g) }}}}}} + } + wrapper.arity = 7; + wrapper.func = fun; + return wrapper; +} + +function F8(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return function(h) {return fun(a,b,c,d,e,f,g,h)}}}}}}} + } + wrapper.arity = 8; + wrapper.func = fun; + return wrapper; +} + +function F9(fun) { + function wrapper(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return function(h) { return function(i) { + return fun(a,b,c,d,e,f,g,h,i) }}}}}}}} + } + wrapper.arity = 9; + wrapper.func = fun; + return wrapper; +} + +function A2(fun,a,b) { + return fun.arity === 2 ? fun.func(a,b) : fun(a)(b); +} +function A3(fun,a,b,c) { + return fun.arity === 3 ? fun.func(a,b,c) : fun(a)(b)(c); +} +function A4(fun,a,b,c,d) { + return fun.arity === 4 ? fun.func(a,b,c,d) : fun(a)(b)(c)(d); +} +function A5(fun,a,b,c,d,e) { + return fun.arity === 5 ? fun.func(a,b,c,d,e) : fun(a)(b)(c)(d)(e); +} +function A6(fun,a,b,c,d,e,f) { + return fun.arity === 6 ? fun.func(a,b,c,d,e,f) : fun(a)(b)(c)(d)(e)(f); +} +function A7(fun,a,b,c,d,e,f,g) { + return fun.arity === 7 ? fun.func(a,b,c,d,e,f,g) : fun(a)(b)(c)(d)(e)(f)(g); +} +function A8(fun,a,b,c,d,e,f,g,h) { + return fun.arity === 8 ? fun.func(a,b,c,d,e,f,g,h) : fun(a)(b)(c)(d)(e)(f)(g)(h); +} +function A9(fun,a,b,c,d,e,f,g,h,i) { + return fun.arity === 9 ? fun.func(a,b,c,d,e,f,g,h,i) + : fun(a)(b)(c)(d)(e)(f)(g)(h)(i); +} diff --git a/libraries/Native/Graphics/Collage.js b/libraries/Native/Graphics/Collage.js new file mode 100644 index 0000000..097fe97 --- /dev/null +++ b/libraries/Native/Graphics/Collage.js @@ -0,0 +1,23 @@ + +Elm.Native.Graphics.Collage = function(elm) { + "use strict"; + + elm.Native = elm.Native || {}; + elm.Native.Graphics = elm.Native.Graphics || {}; + if (elm.Native.Graphics.Collage) return elm.Native.Graphics.Collage; + + var newElement = Elm.Graphics.Element(elm).newElement; + var C = ElmRuntime.use(ElmRuntime.Render.Collage); + + function collage(w,h,forms) { + return A3(newElement, w, h, { + ctor: 'Custom', + type: 'Collage', + render: C.render, + update: C.update, + model: {w:w, h:h, forms:forms} + }); + } + return elm.Native.Graphics.Collage = { collage:F3(collage) }; + +}; \ No newline at end of file diff --git a/libraries/Native/Graphics/Input.js b/libraries/Native/Graphics/Input.js new file mode 100644 index 0000000..4323024 --- /dev/null +++ b/libraries/Native/Graphics/Input.js @@ -0,0 +1,234 @@ + +Elm.Native.Graphics.Input = function(elm) { + "use strict"; + + elm.Native = elm.Native || {}; + elm.Native.Graphics = elm.Native.Graphics || {}; + if (elm.Native.Graphics.Input) return elm.Native.Graphics.Input; + + var Render = ElmRuntime.use(ElmRuntime.Render.Element); + var Utils = ElmRuntime.use(ElmRuntime.Render.Utils); + var newNode = Utils.newElement, fromString = Utils.fromString, + toString = Utils.toString; + + var Signal = Elm.Signal(elm); + var newElement = Elm.Graphics.Element(elm).newElement; + + function buttons(defaultValue) { + var events = Signal.constant(defaultValue); + + function render(model) { + var b = newNode('button'); + b.style.display = 'block'; + b.elmEvent = model.event; + function click() { elm.notify(events.id, b.elmEvent); } + b.addEventListener('click', click); + b.innerHTML = model.text; + return b; + } + + function update(node, oldModel, newModel) { + node.elmEvent = newModel.event; + var txt = newModel.text; + if (oldModel.text !== txt) node.innerHTML = txt; + } + + function button(evnt, txt) { + return A3(newElement, 100, 40, { + ctor: 'Custom', + type: 'Button', + render: render, + update: update, + model: { event:evnt, text:fromString(txt) } + }); + } + + return { _:{}, button:F2(button), events:events }; + } + + function customButtons(defaultValue) { + var events = Signal.constant(defaultValue); + + function render(model) { + var btn = newNode('div'); + btn.elmEvent = model.event; + + btn.elmUp = Render.render(model.up); + btn.elmHover = Render.render(model.hover); + btn.elmDown = Render.render(model.down); + + function replace(node) { + if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild); + } + var overCount = 0; + function over(e) { + if (overCount++ > 0) return; + replace(btn.elmHover); + } + function out(e) { + if (btn.contains(e.toElement || e.relatedTarget)) return; + overCount = 0; + replace(btn.elmUp); + } + function up() { + replace(btn.elmHover); + elm.notify(events.id, btn.elmEvent); + } + function down() { replace(btn.elmDown); } + btn.addEventListener('mouseover', over); + btn.addEventListener('mouseout' , out); + btn.addEventListener('mousedown', down); + btn.addEventListener('mouseup' , up); + + btn.appendChild(btn.elmUp); + return btn; + } + + function update(node, oldModel, newModel) { + node.elmEvent = newModel.event; + Render.update(node.elmUp, oldModel.up, newModel.up) + Render.update(node.elmHover, oldModel.hover, newModel.hover) + Render.update(node.elmDown, oldModel.down, newModel.down) + } + + function button(evnt, up, hover, down) { + return A3(newElement, + Math.max(up.props.width, hover.props.width, down.props.width), + Math.max(up.props.height, hover.props.height, down.props.height), + { ctor: 'Custom', + type: 'CustomButton', + render: render, + update: update, + model: { event:evnt, up:up, hover:hover, down:down } + }); + } + + return { _:{}, button:F4(button), events:events }; + } + + + function checkboxes(defaultValue) { + var events = Signal.constant(defaultValue); + + function render(model) { + var b = newNode('input'); + b.type = 'checkbox'; + b.checked = model.checked; + b.style.display = 'block'; + b.elmHandler = model.handler; + function change() { elm.notify(events.id, b.elmHandler(b.checked)); } + b.addEventListener('change', change); + return b; + } + + function update(node, oldModel, newModel) { + node.elmHandler = newModel.handler; + node.checked = newModel.checked; + return true; + } + + function box(handler, checked) { + return A3(newElement, 13, 13, { + ctor: 'Custom', + type: 'CheckBox', + render: render, + update: update, + model: { checked:checked, handler:handler } + }); + } + + return { _:{}, box:F2(box), events:events }; + } + + function mkTextPool(type) { return function fields(defaultValue) { + var events = Signal.constant(defaultValue); + + var state = null; + + function render(model) { + var field = newNode('input'); + field.elmHandler = model.handler; + + field.id = 'test'; + field.type = type; + field.placeholder = fromString(model.placeHolder); + field.value = fromString(model.state.string); + field.setSelectionRange(model.state.selectionStart, model.state.selectionEnd); + field.style.border = 'none'; + state = model.state; + + function update() { + var start = field.selectionStart, + end = field.selectionEnd; + if (field.selectionDirection === 'backward') { + start = end; + end = field.selectionStart; + } + state = { _:{}, + string:toString(field.value), + selectionStart:start, + selectionEnd:end }; + elm.notify(events.id, field.elmHandler(state)); + } + function mousedown() { + update(); + elm.node.addEventListener('mouseup', mouseup); + } + function mouseup() { + update(); + elm.node.removeEventListener('mouseup', mouseup) + } + field.addEventListener('keyup', update); + field.addEventListener('mousedown', mousedown); + + return field; + } + + function update(node, oldModel, newModel) { + node.elmHandler = newModel.handler; + if (state === newModel.state) return; + var newStr = fromString(newModel.state.string); + if (node.value !== newStr) node.value = newStr; + + var start = newModel.state.selectionStart; + var end = newModel.state.selectionEnd; + var direction = 'forward'; + if (end < start) { + start = end; + end = newModel.state.selectionStart; + direction = 'backward'; + } + + if (node.selectionStart !== start + || node.selectionEnd !== end + || node.selectionDirection !== direction) { + node.setSelectionRange(start, end, direction); + } + } + + function field(handler, placeHolder, state) { + return A3(newElement, 200, 30, + { ctor: 'Custom', + type: type + 'Input', + render: render, + update: update, + model: { handler:handler, + placeHolder:placeHolder, + state:state } + }); + } + + return { _:{}, field:F3(field), events:events }; + } + } + + return elm.Native.Graphics.Input = { + buttons:buttons, + customButtons:customButtons, + checkboxes:checkboxes, + fields:mkTextPool('text'), + emails:mkTextPool('email'), + passwords:mkTextPool('password') + }; + +}; diff --git a/libraries/Native/JavaScript.js b/libraries/Native/JavaScript.js new file mode 100644 index 0000000..22993a0 --- /dev/null +++ b/libraries/Native/JavaScript.js @@ -0,0 +1,102 @@ + +Elm.Native.JavaScript = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.JavaScript) return elm.Native.JavaScript; + + var List = Elm.Native.List(elm); + var Render = ElmRuntime.use(ElmRuntime.Render.Element); + + function fromJS(v) { + var type = typeof v; + if (type === 'number' ) return v; + if (type === 'boolean') return v; + if (type === 'string' ) return List.fromArray(v); + if (v instanceof Array) { + var arr = []; + var len = v.length; + for (var i = 0; i < len; ++i) { + var x = fromJS(v[i]); + if (x !== null) arr.push(x); + } + return List.fromArray(arr); + } + if (type === 'object') { + var rec = { _:{} }; + for (var f in v) { + var x = fromJS(v[f]); + if (x !== null) rec[f] = x; + } + return rec; + } + return null; + } + + function toJS(v) { + var type = typeof v; + if (type === 'number' || type === 'boolean') return v; + if (type === 'object' && '_' in v) { + var obj = {}; + for (var k in v) { + var x = v[k]; + if (x !== null) obj[k] = x; + } + return obj; + } + if (type === 'object' && (v.ctor === 'Cons' || v.ctor === 'Nil')) { + var array = List.toArray(v); + for (var i = array.length; i--; ) { + array[i] = toJS(array[i]); + } + if (typeof array[0] === 'string') array.join(''); + return array; + } + return null; + } + + function fromRecord(r) { + if (typeof r === 'object' && '_' in r) { + return toJS(r); + } + throw new Error("'fromRecord' must be called on a record."); + } + + function id(n) { return n; } + + function toElement(w,h,domNode) { + return A3( newElement, w, h, { + ctor: 'Custom', + type: 'DomNode', + render: function(node) { return node; }, + update: function(node,oldNode,newNode) { + if (node === newNode) return; + node.parentNode.replaceChild(newNode, node); + }, + model: domNode + }); + } + + function fromElement(element) { + return Render.render(element); + } + + return elm.Native.JavaScript = { + toFloat : id, + toBool : id, + toInt : function(n) { return n|0; }, + toString : List.fromArray, + toList : List.fromArray, + fromString : function(s) { return List.toArray(s).join(''); }, + fromList : List.toArray, + fromInt : id, + fromFloat : id, + fromBool : id, + + toElement : toElement, + fromElement : fromElement, + toRecord : fromJS, + fromRecord : fromRecord + }; + +}; \ No newline at end of file diff --git a/libraries/Native/Json.js b/libraries/Native/Json.js new file mode 100644 index 0000000..93305d2 --- /dev/null +++ b/libraries/Native/Json.js @@ -0,0 +1,69 @@ + +Elm.Native.Json = function(elm) { + 'use strict'; + + var Maybe = Elm.Maybe(elm); + var Dict = Elm.Dict(elm); + var List = Elm.List(elm); + var JS = Elm.JavaScript(elm); + var Utils = Elm.Native.Utils(elm); + + function fromValue(v) { + switch (v.ctor) { + case 'Null' : return null; + case 'String' : return JS.fromString(v._0); + case 'Object' : + var obj = {}; + var array = JS.fromList(Dict.toList(v._0)); + for (var i = arr.length; i--; ) { + obj[JS.fromString(array[i]._0)] = fromValue(array[i]._1); + } + return obj; + case 'Array' : + var array = JS.fromList(v._0); + for (var i = array.length; i--; ) { + array[i] = fromValue(array[i]); + } + return array; + default : + return v._0; + } + } + + function toPrettyJSString(sep, obj) { + return JSON.stringify(fromValue(obj), null, JS.fromString(sep)); + } + + function toValue(v) { + switch (typeof v) { + case 'string' : return { ctor:"String", _0: JS.toString(v) }; + case 'number' : return { ctor:"Number", _0: JS.toFloat(v) }; + case 'boolean': return { ctor:"Bool" , _0: JS.toBool(v) }; + case 'object' : + if (v === null) return { ctor:"Null" }; + if (v instanceof Array) { + for (var i = v.length; i--; ) { v[i] = toValue(v[i]); } + return { ctor:"Array", _0: JS.toList(v) }; + } + var array = []; + for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k]))); + return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) }; + } + } + + function fromJSString(str) { + try { + return Maybe.Just(toValue(JSON.parse(str))); + } catch (e) { + return Maybe.Nothing; + } + } + + return elm.Native.Json = { + toJSString : F2(toPrettyJSString), + fromJSString : fromJSString, + toJSObject : fromValue, + fromJSObject : toValue + }; + +}; diff --git a/libraries/Native/List.js b/libraries/Native/List.js new file mode 100644 index 0000000..7950aab --- /dev/null +++ b/libraries/Native/List.js @@ -0,0 +1,347 @@ +Elm.Native.List = function(elm) { + "use strict"; + + elm.Native = elm.Native || {}; + if (elm.Native.List) return elm.Native.List; + if ('values' in Elm.Native.List) + return elm.Native.List = Elm.Native.List.values; + + var Utils = Elm.Native.Utils(elm); + + // TODO: Improve Nil handling + // We can change places like: if (xs.ctor === 'Nil') ... to if (xs === Nil) ... + // but only if we're confident Nil can only be defined once. + // Currently (27Mar2013) each module can have different instantiations, so multiple Nil objects can exist + // (and if they're used interchangeably then direct object comparison fails where ctor doesn't). + // So, this can only be fixed when modules initialisation is also fixed. + // The performance overhead of the .ctor calls is 5-10% according to jsperf (depending on fn + list size) + // (on firefox 19) + + var Nil = { ctor:'Nil' }; + + // using freeze for every cons would be nice but is a huge (9x on firefox 19) + // performance penalty + function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; } + + function throwError(f) { + throw new Error("Function '" + f + "' expects a non-empty list!"); + } + + function toArray(xs) { + var out = []; + while (xs.ctor !== 'Nil') { + out.push(xs._0); + xs = xs._1; + } + return out; + } + + function fromArray(arr) { + var out = Nil; + for (var i = arr.length; i--; ) { + out = Cons(arr[i], out); + } + return out; + } + + function range(lo,hi) { + var lst = Nil; + if (lo <= hi) { + do { lst = Cons(hi,lst) } while (hi-->lo); + } + return lst + } + + function append(xs,ys) { + if (typeof xs === "string") { return xs.concat(ys); } + if (xs.ctor === 'Nil') { return ys; } + var root = Cons(xs._0, Nil); + var curr = root; + xs = xs._1; + while (xs.ctor !== 'Nil') { + curr._1 = Cons(xs._0, Nil); + xs = xs._1; + curr = curr._1; + } + curr._1 = ys; + return root; + } + + function head(v) { return v.ctor === 'Nil' ? throwError('head') : v._0; } + function tail(v) { return v.ctor === 'Nil' ? throwError('tail') : v._1; } + + function last(xs) { + if (xs.ctor === 'Nil') { throwError('last'); } + var out = xs._0; + while (xs.ctor !== 'Nil') { + out = xs._0; + xs = xs._1; + } + return out; + } + + function map(f, xs) { + var arr = []; + while (xs.ctor !== 'Nil') { + arr.push(f(xs._0)); + xs = xs._1; + } + return fromArray(arr); + } + + // f defined similarly for both foldl and foldr (NB: different from Haskell) + // ie, foldl :: (a -> b -> b) -> b -> [a] -> b + function foldl(f, b, xs) { + var acc = b; + while (xs.ctor !== 'Nil') { + acc = A2(f, xs._0, acc); + xs = xs._1; + } + return acc; + } + + 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 foldl1(f, xs) { + return xs.ctor === 'Nil' ? throwError('foldl1') : foldl(f, xs._0, xs._1); + } + + function foldr1(f, xs) { + if (xs.ctor === 'Nil') { throwError('foldr1'); } + var arr = toArray(xs); + var acc = arr.pop(); + for (var i = arr.length; i--; ) { + acc = A2(f, arr[i], acc); + } + return acc; + } + + function scanl(f, b, xs) { + var arr = toArray(xs); + arr.unshift(b); + var len = arr.length; + for (var i = 1; i < len; ++i) { + arr[i] = A2(f, arr[i], arr[i-1]); + } + return fromArray(arr); + } + + function scanl1(f, xs) { + return xs.ctor === 'Nil' ? throwError('scanl1') : scanl(f, xs._0, xs._1); + } + + function filter(pred, xs) { + var arr = []; + while (xs.ctor !== 'Nil') { + if (pred(xs._0)) { arr.push(xs._0); } + xs = xs._1; + } + return fromArray(arr); + } + + function length(xs) { + var out = 0; + while (xs.ctor !== 'Nil') { + out += 1; + xs = xs._1; + } + return out; + } + + function member(x, xs) { + while (xs.ctor !== 'Nil') { + if (Utils.eq(x,xs._0)) return true; + xs = xs._1; + } + return false; + } + + function reverse(xs) { return fromArray(toArray(xs).reverse()); } + + function concat(xss) { + if (xss.ctor === 'Nil') return xss; + var arr = toArray(xss); + var xs = arr[arr.length-1]; + for (var i = arr.length-1; i--; ) { + xs = append(arr[i], xs); + } + return xs; + } + + function all(pred, xs) { + while (xs.ctor !== 'Nil') { + if (!pred(xs._0)) return false; + xs = xs._1; + } + return true; + } + + function any(pred, xs) { + while (xs.ctor !== 'Nil') { + if (pred(xs._0)) return true; + xs = xs._1; + } + return false; + } + + function zipWith(f, xs, ys) { + var arr = []; + while (xs.ctor !== 'Nil' && ys.ctor !== 'Nil') { + arr.push(A2(f, xs._0, ys._0)); + xs = xs._1; + ys = ys._1; + } + return fromArray(arr); + } + + function zip(xs, ys) { + var arr = []; + while (xs.ctor !== 'Nil' && ys.ctor !== 'Nil') { + arr.push(Utils.Tuple2(xs._0, ys._0)); + xs = xs._1; + ys = ys._1; + } + return fromArray(arr); + } + + function sort(xs) { + function cmp(a,b) { + var ord = Utils.compare(a,b).ctor; + return ord=== 'EQ' ? 0 : ord === 'LT' ? -1 : 1; + } + return fromArray(toArray(xs).sort(cmp)); + } + + function take(n, xs) { + var arr = []; + while (xs.ctor !== 'Nil' && n > 0) { + arr.push(xs._0); + xs = xs._1; + --n; + } + return fromArray(arr); + } + + function drop(n, xs) { + while (xs.ctor !== 'Nil' && n > 0) { + xs = xs._1; + --n; + } + return xs; + } + + function join(sep, xss) { + if (typeof sep === 'string') return toArray(xss).join(sep); + if (xss.ctor === 'Nil') return Nil; + var s = toArray(sep); + var out = toArray(xss._0); + xss = xss._1; + while (xss.ctor !== 'Nil') { + out = out.concat(s, toArray(xss._0)); + xss = xss._1; + } + return fromArray(out); + } + + function split(seperator, list) { + var array = toArray(list); + var alen = array.length; + if (alen === 0) { + // splitting an empty list is a list of lists: [[]] + return Cons(Nil,Nil); + } + + var sep = toArray(seperator); + var seplen = sep.length; + if (seplen === 0) { + // splitting with an empty sep is a list of all elements + // Same as (map (\x -> [x]) list) + var out = Nil; + for (var i = alen; i--; ) { + out = Cons(Cons(array[i],Nil), out); + } + return out; + } + + var matches = [-seplen]; + var sepStart = sep[0]; + var len = alen - seplen + 1; + for (var i = 0; i < len; ++i) { + if (Utils.eq(array[i], sepStart)) { + var match = true; + for (var j = seplen; --j; ) { + if (!Utils.eq(array[i+j], sep[j])) { match = false; break; } + } + if (match) { + matches.push(i); + i += seplen - 1; + } + } + } + + // shortcut in case of no matches + if (matches.length === 0) { + return Cons(list,Nil); + } + + var out = Nil; + var index = alen - 1; + for (var i = matches.length; i--; ) { + var temp = Nil; + var stop = matches[i] + seplen - 1; + for ( ; index > stop; --index ) { + temp = Cons(array[index], temp); + } + out = Cons(temp,out); + index -= seplen; + } + return out; + } + + Elm.Native.List.values = { + Nil:Nil, + Cons:Cons, + toArray:toArray, + fromArray:fromArray, + range:range, + append:append, + + head:head, + tail:tail, + last:last, + + map:F2(map), + foldl:F3(foldl), + foldr:F3(foldr), + + foldl1:F2(foldl1), + foldr1:F2(foldr1), + scanl:F3(scanl), + scanl1:F2(scanl1), + filter:F2(filter), + length:length, + member:F2(member), + reverse:reverse, + concat:concat, + + all:F2(all), + any:F2(any), + zipWith:F3(zipWith), + zip:F2(zip), + sort:sort, + take:F2(take), + drop:F2(drop), + + join:F2(join), + split:F2(split) + }; + return elm.Native.List = Elm.Native.List.values; + +}; \ No newline at end of file diff --git a/libraries/Native/Matrix2D.js b/libraries/Native/Matrix2D.js new file mode 100644 index 0000000..b7e8439 --- /dev/null +++ b/libraries/Native/Matrix2D.js @@ -0,0 +1,88 @@ + +Elm.Native.Matrix2D = function(elm) { + "use strict"; + + elm.Native = elm.Native || {}; + if (elm.Native.Matrix2D) return elm.Native.Matrix2D; + + if (typeof Float32Array === 'undefined'){ Float32Array = Array; } + var A = Float32Array; + + // layout of matrix in an array is + // + // | m11 m12 dx | + // | m21 m22 dy | + // | 0 0 1 | + // + // new A([ m11, m12, dx, m21, m22, dy ]) + + var identity = new A([1,0,0,0,1,0]); + function matrix(m11, m12, m21, m22, dx, dy) { + return new A([m11, m12, dx, m21, m22, dy]); + } + function rotation(t) { + var c = Math.cos(t); + var s = Math.sin(t); + return new A([c, -s, 0, s, c, 0]); + } + + function rotate(t,m) { + var c = Math.cos(t); + var s = Math.sin(t); + var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4]; + return new A([m11*c + m12*s, -m11*s + m12*c, m[2], + m21*c + m22*s, -m21*s + m22*c, m[5]]); + } + /* + function move(xy,m) { + var x = xy._0; + var y = xy._1; + var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4]; + return new A([m11, m12, m11*x + m12*y + m[2], + m21, m22, m21*x + m22*y + m[5]]); + } + function scale(s,m) { return new A([m[0]*s, m[1]*s, m[2], m[3]*s, m[4]*s, m[5]]); } + function scaleX(x,m) { return new A([m[0]*x, m[1], m[2], m[3]*x, m[4], m[5]]); } + function scaleY(y,m) { return new A([m[0], m[1]*y, m[2], m[3], m[4]*y, m[5]]); } + function reflectX(m) { return new A([-m[0], m[1], m[2], -m[3], m[4], m[5]]); } + function reflectY(m) { return new A([m[0], -m[1], m[2], m[3], -m[4], m[5]]); } + + function transform(m11, m21, m12, m22, mdx, mdy, n) { + var n11 = n[0], n12 = n[1], n21 = n[3], n22 = n[4], ndx = n[2], ndy = n[5]; + return new A([m11*n11 + m12*n21, + m11*n12 + m12*n22, + m11*ndx + m12*ndy + mdx, + m21*n11 + m22*n21, + m21*n12 + m22*n22, + m21*ndx + m22*ndy + mdy]); + } + */ + function multiply(m, n) { + var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4], mdx = m[2], mdy = m[5]; + var n11 = n[0], n12 = n[1], n21 = n[3], n22 = n[4], ndx = n[2], ndy = n[5]; + return new A([m11*n11 + m12*n21, + m11*n12 + m12*n22, + m11*ndx + m12*ndy + mdx, + m21*n11 + m22*n21, + m21*n12 + m22*n22, + m21*ndx + m22*ndy + mdy]); + } + + return elm.Native.Matrix2D = { + identity:identity, + matrix:F6(matrix), + rotation:rotation, + multiply:F2(multiply) + /* + transform:F7(transform), + rotate:F2(rotate), + move:F2(move), + scale:F2(scale), + scaleX:F2(scaleX), + scaleY:F2(scaleY), + reflectX:reflectX, + reflectY:reflectY + */ + }; + +}; diff --git a/libraries/Native/Prelude.js b/libraries/Native/Prelude.js new file mode 100644 index 0000000..2c4b700 --- /dev/null +++ b/libraries/Native/Prelude.js @@ -0,0 +1,123 @@ + +Elm.Native.Prelude = function(elm) { + 'use strict'; + if (elm.Native.Prelude) return elm.Native.Prelude; + + var JS = Elm.JavaScript(elm); + var Maybe = Elm.Maybe(elm); + var Utils = Elm.Native.Utils(elm); + var Char = Elm.Char(elm); + + function div(a,b) { return (a/b)|0; } + function rem(a,b) { return a % b; } + var mod = Utils.mod; + function abs(x) { return x < 0 ? -x : x; } + function logBase(base,n) { return Math.log(n) / Math.log(base); } + function min(a,b) { return a < b ? a : b; } + function max(a,b) { return a > b ? a : b; } + function clamp(lo,hi,n) { return n < lo ? lo : n > hi ? hi : n; } + function xor(a,b) { return a !== b; } + function not(b) { return !b; } + + function truncate(n) { return n|0; } + + function id(n) { return n; } + function flip(f,a,b) { return A2(f,b,a); } + function curry(f,a,b) { return f(Utils.Tuple2(a,b)); } + function uncurry(f,v) { return A2(f,v._0,v._1); } + function fst(t) { return t._0; } + function snd(t) { return t._1; } + + function readInt(str) { + var s = JS.fromString(str); + var len = s.length; + if (len === 0) { return Maybe.Nothing; } + var start = 0; + if (s[0] == '-') { + if (len === 1) { return Maybe.Nothing; } + start = 1; + } + for (var i = start; i < len; ++i) { + if (!Char.isDigit(s[i])) { return Maybe.Nothing; } + } + return Maybe.Just(parseInt(s, 10)); + } + + function readFloat(str) { + var s = JS.fromString(str); + var len = s.length; + if (len === 0) { return Maybe.Nothing; } + var start = 0; + if (s[0] == '-') { + if (len === 1) { return Maybe.Nothing; } + start = 1; + } + var dotCount = 0; + for (var i = start; i < len; ++i) { + if (Char.isDigit(s[i])) { continue; } + if (s[i] === '.') { + dotCount += 1; + if (dotCount <= 1) { continue; } + } + return Maybe.Nothing; + } + return Maybe.Just(parseFloat(s)); + } + + var prelude = { + div:F2(div), + rem:F2(rem), + mod: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), + + sqrt:Math.sqrt, + abs:abs, + logBase:F2(logBase), + min:F2(min), + max:F2(max), + clamp:F3(clamp), + compare:Utils.compare, + + xor:F2(xor), + not:not, + otherwise:true, + + truncate:truncate, + ceiling:Math.ceil, + floor:Math.floor, + round:Math.round, + toFloat:id, + + readInt:readInt, + readFloat:readFloat, + + id:id, + flip:F3(flip), + curry:F3(curry), + uncurry:F2(uncurry), + fst:fst, + snd:snd + }; + + function add(Module) { + var M = Module(elm); + for (var k in M) { prelude[k] = M[k]; } + } + add(Elm.Native.Show); + add(Elm.Signal); + add(Elm.List); + add(Elm.Maybe); + add(Elm.Time); + add(Elm.Graphics.Element); + + return elm.Native.Prelude = prelude; +}; diff --git a/libraries/Native/Show.js b/libraries/Native/Show.js new file mode 100644 index 0000000..6917742 --- /dev/null +++ b/libraries/Native/Show.js @@ -0,0 +1,99 @@ + +Elm.Native.Show = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Show) return elm.Native.Show; + + var NList = Elm.Native.List(elm); + var List = Elm.List(elm); + var Maybe = Elm.Maybe(elm); + var JS = Elm.JavaScript(elm); + var Dict = Elm.Dict(elm); + var Json = Elm.Json(elm); + var Tuple2 = Elm.Native.Utils(elm).Tuple2; + + var toString = function(v) { + if (typeof v === "function") { + var name = v.func ? v.func.name : v.name; + return '<function' + (name === '' ? '' : ': ') + name + '>'; + } else if (typeof v === "boolean") { + return v ? "True" : "False"; + } else if (typeof v === "number") { + return v+""; + } else if (typeof v === "string" && v.length < 2) { + return "'" + showChar(v) + "'"; + } else if (typeof v === "object" && '_' in v) { + var output = []; + for (var k in v._) { + for (var i = v._[k].length; i--; ) { + output.push(k + " = " + toString(v._[k][i])); + } + } + for (var k in v) { + if (k === '_') continue; + output.push(k + " = " + toString(v[k])); + } + if (output.length === 0) return "{}"; + return "{ " + output.join(", ") + " }"; + } else if (typeof v === "object" && 'ctor' in v) { + if (v.ctor.substring(0,5) === "Tuple") { + var output = []; + for (var k in v) { + if (k === 'ctor') continue; + output.push(toString(v[k])); + } + return "(" + output.join(",") + ")"; + } else if (v.ctor === "Cons") { + var isStr = typeof v._0 === "string", + start = isStr ? '"' : "[", + end = isStr ? '"' : "]", + sep = isStr ? "" : ",", + f = !isStr ? toString : showChar; + var output = start + f(v._0); + v = v._1; + while (v.ctor === "Cons") { + output += sep + f(v._0); + v = v._1; + } + return output + end; + } else if (v.ctor === "Nil") { + return "[]"; + } else if (v.ctor === "RBNode" || v.ctor === "RBEmpty") { + var cons = F3(function(k,v,acc){return NList.Cons(Tuple2(k,v),acc)}); + var list = A3(Dict.foldr, cons, NList.Nil, v); + var name = "Dict"; + if (list.ctor === "Cons" && list._0._1.ctor === "Tuple0") { + name = "Set"; + list = A2(List.map, function(x){return x._0}, list); + } + return name + ".fromList " + toString(list); + } else { + var output = ""; + for (var i in v) { + if (i === 'ctor') continue; + var str = toString(v[i]); + var parenless = str[0] === '{' || str.indexOf(' ') < 0; + output += ' ' + (parenless ? str : '(' + str + ')'); + } + return v.ctor + output; + } + } + return v+""; + }; + function show(v) { return NList.fromArray(toString(v)); } + + function showChar (c) { + return c === '\n' ? '\\n' : + c === '\t' ? '\\t' : + c === '\b' ? '\\b' : + c === '\r' ? '\\r' : + c === '\v' ? '\\v' : + c === '\0' ? '\\0' : + c === '\'' ? "\\'" : + c === '\"' ? '\\"' : + c === '\\' ? '\\\\' : c; + } + + return elm.Native.Show = { show:show }; +}; diff --git a/libraries/Native/Signal/Http.js b/libraries/Native/Signal/Http.js new file mode 100644 index 0000000..b0dea8b --- /dev/null +++ b/libraries/Native/Signal/Http.js @@ -0,0 +1,61 @@ + +Elm.Native.Http = function(elm) { + 'use strict'; + elm.Native = elm.Native || {}; + if (elm.Native.Http) return elm.Native.Http; + + + var JS = Elm.JavaScript(elm); + var List = Elm.List(elm); + var Signal = Elm.Signal(elm); + + + function registerReq(queue,responses) { return function(req) { + if (req.url !== "") { sendReq(queue,responses,req); } + }; + } + + function updateQueue(queue,responses) { + if (queue.length > 0) { + elm.notify(responses.id, queue[0].value); + if (queue[0].value.ctor !== 'Waiting') { + queue.shift(); + setTimeout(function() { updateQueue(queue,responses); }, 0); + } + } + } + + function setHeader(pair) { + request.setRequestHeader( JS.fomString(pair._0), JS.fromString(pair._1) ); + } + + function sendReq(queue,responses,req) { + var response = { value: { ctor:'Waiting' } }; + queue.push(response); + + var request = null; + if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } + if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } + request.onreadystatechange = function(e) { + if (request.readyState === 4) { + response.value = (request.status === 200 ? + { ctor:'Success', _0:JS.toString(request.responseText) } : + { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) }); + setTimeout(function() { updateQueue(queue,responses); }, 0); + } + }; + request.open(JS.fromString(req.verb), JS.fromString(req.url), true); + List.map(setHeader)(req.headers); + request.send(JS.fromString(req.body)); + } + + function send(requests) { + var responses = Signal.constant(elm.Http.Waiting); + var sender = A2( Signal.lift, registerReq([],responses), requests ); + function f(x) { return function(y) { return x; } } + return A3( Signal.lift2, f, responses, sender ); + } + + return elm.Native.Http = {send:send}; + +}; diff --git a/libraries/Native/Signal/Keyboard.js b/libraries/Native/Signal/Keyboard.js new file mode 100644 index 0000000..6ddd934 --- /dev/null +++ b/libraries/Native/Signal/Keyboard.js @@ -0,0 +1,72 @@ + +Elm.Native.Keyboard = function(elm) { + 'use strict'; + elm.Native = elm.Native || {}; + if (elm.Native.Keyboard) return elm.Native.Keyboard; + + var Signal = Elm.Signal(elm); + var NList = Elm.Native.List(elm); + + var keysDown = Signal.constant(NList.Nil); + var lastKey = Signal.constant('\0'); + + function down(e) { + if (NList.member(e.keyCode)(keysDown.value)) return; + var list = NList.Cons(e.keyCode, keysDown.value); + var hasListener = elm.notify(keysDown.id, list); + if (!hasListener) document.removeEventListener('keydown', down); + } + function up(e) { + function notEq(kc) { return kc !== e.keyCode; } + var codes = NList.filter(notEq)(keysDown.value); + var hasListener = elm.notify(keysDown.id, codes); + if (!hasListener) document.removeEventListener('keyup', up); + } + function blur(e) { + var hasListener = elm.notify(keysDown.id, NList.Nil); + if (!hasListener) document.removeEventListener('blur', blur); + } + function press(e) { + var hasListener = elm.notify(lastKey.id, e.charCode || e.keyCode); + if (!hasListener) document.removeEventListener('keypress', press); + } + + document.addEventListener('keydown' , down ); + document.addEventListener('keyup' , up ); + document.addEventListener('blur' , blur ); + document.addEventListener('keypress', press); + + function keySignal(f) { + var signal = A2( Signal.lift, f, keysDown ); + keysDown.defaultNumberOfKids += 1; + signal.defaultNumberOfKids = 0; + return signal; + } + + function dir(up, down, left, right) { + function f(ks) { + var x = 0, y = 0; + while (ks.ctor == "Cons") { + switch (ks._0) { + case left : --x; break; + case right: ++x; break; + case up : ++y; break; + case down : --y; break; + } + ks = ks._1; + } + return { _:{}, x:x, y:y }; + } + return keySignal(f); + } + + function is(key) { return keySignal(NList.member(key)); } + + return elm.Native.Keyboard = { + isDown:is, + directions:F4(dir), + keysDown:keysDown, + lastPressed:lastKey + }; + +}; diff --git a/libraries/Native/Signal/Mouse.js b/libraries/Native/Signal/Mouse.js new file mode 100644 index 0000000..a928b0f --- /dev/null +++ b/libraries/Native/Signal/Mouse.js @@ -0,0 +1,79 @@ + +Elm.Native.Mouse = function(elm) { + 'use strict'; + elm.Native = elm.Native || {}; + if (elm.Native.Mouse) return elm.Native.Mouse; + + var Signal = Elm.Signal(elm); + var Utils = Elm.Native.Utils(elm); + + var position = Signal.constant(Utils.Tuple2(0,0)); + position.defaultNumberOfKids = 2; + + // do not move x and y into Elm. By setting their default number + // of kids, it is possible to detatch the mouse listeners if + // they are not needed. + var x = A2( Signal.lift, function(p){return p._0}, position); + x.defaultNumberOfKids = 0; + var y = A2( Signal.lift, function(p){return p._1}, position); + y.defaultNumberOfKids = 0; + + var isDown = Signal.constant(false); + var isClicked = Signal.constant(false); + var clicks = Signal.constant(Utils.Tuple0); + + function getXY(e) { + var posx = 0; + var posy = 0; + if (!e) e = window.event; + if (e.pageX || e.pageY) { + posx = e.pageX; + posy = e.pageY; + } else if (e.clientX || e.clientY) { + posx = e.clientX + document.body.scrollLeft + + document.documentElement.scrollLeft; + posy = e.clientY + document.body.scrollTop + + document.documentElement.scrollTop; + } + return Utils.Tuple2(posx-elm.node.offsetX, posy-elm.node.offsetY); + } + + var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node; + + function click(e) { + var hasListener1 = elm.notify(isClicked.id, true); + var hasListener2 = elm.notify(clicks.id, Utils.Tuple0); + elm.notify(isClicked.id, false); + if (!hasListener1 && !hasListener2) + node.removeEventListener('click', click); + } + + function down(e) { + var hasListener = elm.notify(isDown.id, true); + if (!hasListener) node.removeEventListener('mousedown', down); + } + + function up(e) { + var hasListener = elm.notify(isDown.id, false); + if (!hasListener) node.removeEventListener('mouseup', up); + } + + function move(e) { + var hasListener = elm.notify(position.id, getXY(e)); + if (!hasListener) node.removeEventListener('mousemove', move); + } + + node.addEventListener('click' , click); + node.addEventListener('mousedown', down); + node.addEventListener('mouseup' , up); + node.addEventListener('mousemove', move); + + return elm.Native.Mouse = { + position: position, + x:x, + y:y, + isClicked: isClicked, + isDown: isDown, + clicks: clicks + }; +}; \ No newline at end of file diff --git a/libraries/Native/Signal/Random.js b/libraries/Native/Signal/Random.js new file mode 100644 index 0000000..119ba11 --- /dev/null +++ b/libraries/Native/Signal/Random.js @@ -0,0 +1,21 @@ + +Elm.Native.Random = function(elm) { + 'use strict'; + elm.Native = elm.Native || {}; + if (elm.Native.Random) return elm.Native.Random; + + var Signal = Elm.Signal(elm); + + function range(min, max, signal) { + function f(x) { return Math.floor(Math.random() * (max-min+1)) + min; } + return A2( Signal.lift, f, signal ); + } + + function flt(signal) { + function f(x) { return Math.random(); } + return A2( Signal.lift, f, signal ); + } + + return elm.Native.Random = { range: F3(range), float: flt }; + +}; diff --git a/libraries/Native/Signal/Signal.js b/libraries/Native/Signal/Signal.js new file mode 100644 index 0000000..f5c10c3 --- /dev/null +++ b/libraries/Native/Signal/Signal.js @@ -0,0 +1,225 @@ + +Elm.Native.Signal = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Signal) return elm.Native.Signal; + + var Utils = Elm.Native.Utils(elm); + var foldl1 = Elm.List(elm).foldl1; + + function send(node, timestep, changed) { + var kids = node.kids; + for (var i = kids.length; i--; ) { + kids[i].recv(timestep, changed, node.id); + } + } + + function Input(base) { + this.id = Utils.guid(); + this.value = base; + this.kids = []; + this.defaultNumberOfKids = 0; + this.recv = function(timestep, eid, v) { + var changed = eid === this.id; + if (changed) { this.value = v; } + send(this, timestep, changed); + return changed; + }; + elm.inputs.push(this); + } + + function LiftN(update, args) { + this.id = Utils.guid(); + this.value = update(); + this.kids = []; + + var n = args.length; + var count = 0; + var isChanged = false; + + this.recv = function(timestep, changed, parentID) { + ++count; + if (changed) { isChanged = true; } + if (count == n) { + if (isChanged) { this.value = update(); } + send(this, timestep, isChanged); + isChanged = false; + count = 0; + } + }; + for (var i = n; i--; ) { args[i].kids.push(this); } + } + + function lift(func, a) { + function update() { return func(a.value); } + return new LiftN(update, [a]); + } + function lift2(func, a, b) { + function update() { return A2( func, a.value, b.value ); } + return new LiftN(update, [a,b]); + } + function lift3(func, a, b, c) { + function update() { return A3( func, a.value, b.value, c.value ); } + return new LiftN(update, [a,b,c]); + } + function lift4(func, a, b, c, d) { + function update() { return A4( func, a.value, b.value, c.value, d.value ); } + return new LiftN(update, [a,b,c,d]); + } + function lift5(func, a, b, c, d, e) { + function update() { return A5( func, a.value, b.value, c.value, d.value, e.value ); } + return new LiftN(update, [a,b,c,d,e]); + } + function lift6(func, a, b, c, d, e, f) { + function update() { return A6( func, a.value, b.value, c.value, d.value, e.value, f.value ); } + return new LiftN(update, [a,b,c,d,e,f]); + } + function lift7(func, a, b, c, d, e, f, g) { + function update() { return A7( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value ); } + return new LiftN(update, [a,b,c,d,e,f,g]); + } + function lift8(func, a, b, c, d, e, f, g, h) { + function update() { return A8( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value, h.value ); } + return new LiftN(update, [a,b,c,d,e,f,g,h]); + } + + function foldp(func,state,input) { + var first = true; + function update() { + first ? first = false : state = A2(func, input.value, state); + return state; + } + return new LiftN(update, [input]); + } + + function DropIf(pred,base,input) { + this.id = Utils.guid(); + this.value = pred(input.value) ? base : input.value; + this.kids = []; + this.recv = function(timestep, changed, parentID) { + var chng = changed && !pred(input.value); + if (chng) { this.value = input.value; } + send(this, timestep, chng); + }; + input.kids.push(this); + } + + function DropRepeats(input) { + this.id = Utils.guid(); + this.value = input.value; + this.kids = []; + this.recv = function(timestep, changed, parentID) { + var chng = changed && !Utils.eq(this.value,input.value); + if (chng) { this.value = input.value; } + send(this, timestep, chng); + }; + input.kids.push(this); + } + + function dropWhen(s1,b,s2) { + var pairs = lift2( F2(function(x,y){return {x:x,y:y};}), s1, s2 ); + var dropped = new DropIf(function(p){return p.x;},{x:true,y:b},pairs); + return lift(function(p){return p.y;}, dropped); + } + + function timestamp(a) { + function update() { return Utils.Tuple2(Date.now(), a.value); } + return new LiftN(update, [a]); + } + + function SampleOn(s1,s2) { + this.id = Utils.guid(); + this.value = s2.value; + this.kids = []; + + var count = 0; + var isChanged = false; + + this.recv = function(timestep, changed, parentID) { + if (parentID === s1.id) isChanged = changed; + ++count; + if (count == 2) { + if (isChanged) { this.value = s2.value; } + send(this, timestep, isChanged); + count = 0; + isChanged = false; + } + }; + s1.kids.push(this); + s2.kids.push(this); + } + + function sampleOn(s1,s2) { return new SampleOn(s1,s2); } + + function delay(t,s) { + var delayed = new Input(s.value); + var firstEvent = true; + function update(v) { + if (firstEvent) { firstEvent = false; return; } + setTimeout(function() { elm.notify(delayed.id, v); }, t); + } + function first(a,b) { return a; } + return new SampleOn(delayed, lift2(F2(first), delayed, lift(update,s))); + } + + function Merge(s1,s2) { + this.id = Utils.guid(); + this.value = s1.value; + this.kids = []; + + var next = null; + var count = 0; + var isChanged = false; + + this.recv = function(timestep, changed, parentID) { + ++count; + if (changed) { + isChanged = true; + if (parentID == s2.id && next === null) { next = s2.value; } + if (parentID == s1.id) { next = s1.value; } + } + + if (count == 2) { + if (isChanged) { this.value = next; next = null; } + send(this, timestep, isChanged); + isChanged = false; + count = 0; + } + }; + s1.kids.push(this); + s2.kids.push(this); + } + + function merge(s1,s2) { return new Merge(s1,s2); } + function merges(ss) { return A2(foldl1, F2(merge), ss); } + + return elm.Native.Signal = { + constant : function(v) { return new Input(v); }, + lift : F2(lift ), + lift2 : F3(lift2), + lift3 : F4(lift3), + lift4 : F5(lift4), + lift5 : F6(lift5), + lift6 : F7(lift6), + lift7 : F8(lift7), + lift8 : F9(lift8), + foldp : F3(foldp), + delay : F2(delay), + merge : F2(merge), + merges : merges, + count : function(s) { return foldp(F2(function(_,c) { return c+1; }), 0, s); }, + countIf : F2(function(pred,s) { + return foldp(F2(function(x,c){ + return pred(x) ? c+1 : c; }), 0, s)}), + keepIf : F3(function(pred,base,sig) { + return new DropIf(function(x) {return !pred(x);},base,sig); }), + dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }), + keepWhen : F3(function(s1,b,s2) { + return dropWhen(lift(function(b){return !b;},s1), b, s2); }), + dropWhen : F3(dropWhen), + dropRepeats : function(s) { return new DropRepeats(s);}, + sampleOn : F2(sampleOn), + timestamp : timestamp + }; +}; diff --git a/libraries/Native/Signal/Time.js b/libraries/Native/Signal/Time.js new file mode 100644 index 0000000..e5ec52d --- /dev/null +++ b/libraries/Native/Signal/Time.js @@ -0,0 +1,60 @@ + +Elm.Native.Time = function(elm) { + 'use strict'; + + var Signal = Elm.Signal(elm); + var Maybe = Elm.Maybe(elm); + var Utils = Elm.Native.Utils(elm); + + function fpsWhen(desiredFPS, isOn) { + var msPerFrame = 1000 / desiredFPS; + var prev = Date.now(), curr = prev, diff = 0, wasOn = true; + var ticker = Signal.constant(diff); + function tick(zero) { return function() { + curr = Date.now(); + diff = zero ? 0 : curr - prev; + prev = curr; + elm.notify(ticker.id, diff); + }; + } + var timeoutID = 0; + function f(isOn, t) { + if (isOn) { + timeoutID = setTimeout(tick(!wasOn && isOn), msPerFrame); + } else if (wasOn) { + clearTimeout(timeoutID); + } + wasOn = isOn; + return t; + } + return A3( Signal.lift2, F2(f), isOn, ticker ); + } + + function everyWhen(t, isOn) { + var clock = Signal.constant(Date.now()); + function tellTime() { elm.notify(clock.id, Date.now()); } + setInterval(tellTime, t); + return clock; + } + + function since(t, s) { + function cmp(a,b) { return !Utils.eq(a,b); } + var dcount = Signal.count(A2(Signal.delay, t, s)); + return A3( Signal.lift2, F2(cmp), Signal.count(s), dcount ); + } + function read(s) { + var t = Date.parse(s); + return isNaN(t) ? Maybe.Nothing : Maybe.Just(t); + } + return elm.Native.Time = { + fpsWhen : F2(fpsWhen), + fps : function(t) { return fpsWhen(t, Signal.constant(true)); }, + every : function(t) { return everyWhen(t, Signal.constant(true)) }, + delay : Signal.delay, + timestamp : Signal.timestamp, + since : F2(since), + toDate : function(t) { return new window.Date(t); }, + read : read + }; + +}; diff --git a/libraries/Native/Signal/Touch.js b/libraries/Native/Signal/Touch.js new file mode 100644 index 0000000..89f761b --- /dev/null +++ b/libraries/Native/Signal/Touch.js @@ -0,0 +1,150 @@ + +Elm.Native.Touch = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Touch) return elm.Native.Touch; + + var Signal = Elm.Signal(elm); + var JS = Elm.JavaScript(elm); + var _ = Elm.Native.Utils(elm); + + function Dict() { + this.keys = []; + this.values = []; + + this.insert = function(key,value) { + this.keys.push(key); + this.values.push(value); + }; + this.lookup = function(key) { + var i = this.keys.indexOf(key) + return i >= 0 ? this.values[i] : {x:0,y:0,t:0}; + }; + this.remove = function(key) { + var i = this.keys.indexOf(key); + if (i < 0) return; + var t = this.values[i]; + this.keys.splice(i,1); + this.values.splice(i,1); + return t; + }; + this.clear = function() { + this.keys = []; + this.values = []; + }; + } + + var root = Signal.constant([]), + tapTime = 500, + hasTap = false, + tap = {_:{},x:0,y:0}, + dict = new Dict(); + + function touch(t) { + var r = dict.lookup(t.identifier); + return {_ : {}, + id: t.identifier, + x : t.pageX - elm.node.offsetX, + y : t.pageY - elm.node.offsetY, + x0: r.x, + y0: r.y, + t0: r.t + }; + } + + var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node; + + function start(e) { + dict.insert(e.identifier, + {x: e.pageX - elm.node.offsetX, + y: e.pageY - elm.node.offsetY, + t: Date.now()}); + } + function end(e) { + var t = dict.remove(e.identifier); + if (Date.now() - t.t < tapTime) { + hasTap = true; + tap = {_:{}, x:t.x, y:t.y}; + } + } + + function listen(name, f) { + function update(e) { + for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); } + var ts = new Array(e.touches.length); + for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); } + var hasListener = elm.notify(root.id, ts); + if (!hasListener) return node.removeEventListener(name, update); + e.preventDefault(); + } + node.addEventListener(name, update); + } + + listen("touchstart", start); + listen("touchmove", function(_){}); + listen("touchend", end); + listen("touchcancel", end); + listen("touchleave", end); + + var mouseID = -1; + function move(e) { + for (var i = root.value.length; i--; ) { + if (root.value[i].id === mouseID) { + root.value[i].x = e.pageX - elm.node.offsetX; + root.value[i].y = e.pageY - elm.node.offsetY; + elm.notify(root.id, root.value); + break; + } + } + } + node.addEventListener("mousedown", function(e) { + node.addEventListener("mousemove", move); + e.identifier = mouseID; + start(e); + root.value.push(touch(e)); + elm.notify(root.id, root.value); + }); + node.addEventListener("mouseup", function(e) { + node.removeEventListener("mousemove", move); + e.identifier = mouseID; + end(e); + for (var i = root.value.length; i--; ) { + if (root.value[i].id === mouseID) { + root.value.splice(i, 1); + --mouseID; + break; + } + } + elm.notify(root.id, root.value); + }); + node.addEventListener("blur", function() { + node.removeEventListener("mousemove", move); + if (root.values.length > 0) { + elm.notify(root.id, []); + --mouseID; + } + dict.clear(); + }); + + function dependency(f) { + var sig = A2( Signal.lift, f, root ); + root.defaultNumberOfKids += 1; + sig.defaultNumberOfKids = 0; + return sig; + } + + var touches = dependency(JS.toList); + + var taps = function() { + var sig = dependency(function(_) { return tap; }); + sig.defaultNumberOfKids = 1; + function pred(_) { var b = hasTap; hasTap = false; return b; } + var sig2 = A3( Signal.keepIf, pred, {_:{},x:0,y:0}, sig); + sig2.defaultNumberOfKids = 0; + return sig2; + }(); + + return elm.Native.Touch = { touches: touches, taps: taps }; + +}; \ No newline at end of file diff --git a/libraries/Native/Signal/WebSocket.js b/libraries/Native/Signal/WebSocket.js new file mode 100644 index 0000000..3709fc9 --- /dev/null +++ b/libraries/Native/Signal/WebSocket.js @@ -0,0 +1,38 @@ + +Elm.Native.WebSocket = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.WebSocket) return elm.Native.WebSocket; + + var Signal = Elm.Signal(elm); + var JS = Elm.JavaScript(elm); + var List = Elm.Native.List(elm); + + function open(url, outgoing) { + var incoming = Signal.constant(List.Nil); + var ws = new WebSocket(JS.fromString(url)); + + var pending = []; + var ready = false; + + ws.onopen = function(e) { + var len = pending.length; + for (var i = 0; i < len; ++i) { ws.send(pending[i]); } + ready = true; + }; + ws.onmessage = function(event) { + elm.notify(incoming.id, JS.toString(event.data)); + }; + + function send(msg) { + var s = JS.fromString(msg); + ready ? ws.send(s) : pending.push(s); + } + + function take1(x,y) { return x } + return A3(Signal.lift2, F2(take1), incoming, A2(Signal.lift, send, outgoing)); + } + + return elm.Native.WebSocket = { connect: F2(open) }; +}; diff --git a/libraries/Native/Signal/Window.js b/libraries/Native/Signal/Window.js new file mode 100644 index 0000000..560f266 --- /dev/null +++ b/libraries/Native/Signal/Window.js @@ -0,0 +1,46 @@ + +Elm.Native.Window = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Window) return elm.Native.Window; + + var Signal = Elm.Signal(elm); + var Tuple2 = Elm.Native.Utils(elm).Tuple2; + + function getWidth() { return elm.node.clientWidth; } + function getHeight() { + if (elm.display === ElmRuntime.Display.FULLSCREEN) { + return window.innerHeight; + } + return elm.node.clientHeight; + } + + var dimensions = Signal.constant(Tuple2(getWidth(), getHeight())); + dimensions.defaultNumberOfKids = 2; + + // Do not move width and height into Elm. By setting the default number of kids, + // the resize listener can be detached. + var width = A2(Signal.lift, function(p){return p._0;}, dimensions); + width.defaultNumberOfKids = 0; + + var height = A2(Signal.lift, function(p){return p._1;}, dimensions); + height.defaultNumberOfKids = 0; + + function resizeIfNeeded() { + var w = getWidth(); + var h = getHeight(); + if (dimensions.value._0 === w && dimensions.value._1 === h) return; + var hasListener = elm.notify(dimensions.id, Tuple2(w,h)); + if (!hasListener) window.removeEventListener('resize', resizeIfNeeded); + } + window.addEventListener('resize', resizeIfNeeded); + + return elm.Native.Window = { + dimensions:dimensions, + width:width, + height:height, + resizeIfNeeded:resizeIfNeeded + }; + +}; diff --git a/libraries/Native/Text.js b/libraries/Native/Text.js new file mode 100644 index 0000000..db7ad96 --- /dev/null +++ b/libraries/Native/Text.js @@ -0,0 +1,136 @@ + +Elm.Native.Text = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Text) return elm.Native.Text; + + var JS = Elm.JavaScript(elm); + var htmlHeight = Elm.Native.Utils(elm).htmlHeight; + var Color = Elm.Native.Color(elm); + var Element = Elm.Graphics.Element(elm); + var show = Elm.Native.Show(elm).show; + + function makeSpaces(s) { + if (s.length == 0) { return s; } + var arr = s.split(''); + if (arr[0] == ' ') { arr[0] = " " } + for (var i = arr.length; --i; ) { + if (arr[i][0] == ' ' && arr[i-1] == ' ') { + arr[i-1] = arr[i-1] + arr[i]; + arr[i] = ''; + } + } + for (var i = arr.length; i--; ) { + if (arr[i].length > 1 && arr[i][0] == ' ') { + var spaces = arr[i].split(''); + for (var j = spaces.length - 2; j >= 0; j -= 2) { + spaces[j] = ' '; + } + arr[i] = spaces.join(''); + } + } + arr = arr.join(''); + if (arr[arr.length-1] === " ") { + return arr.slice(0,-1) + ' '; + } + return arr; + } + + function properEscape(str) { + if (str.length == 0) return str; + str = str //.replace(/&/g, "&") + .replace(/"/g, /*"*/ '"') + .replace(/'/g, /*'*/ "'") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/\n/g, "<br/>"); + var arr = str.split('<br/>'); + for (var i = arr.length; i--; ) { + arr[i] = makeSpaces(arr[i]); + } + return arr.join('<br/>'); + } + + function toText(str) { return properEscape(JS.fromString(str)); } + + function addTag(tag) { return function(text) { + return '<' + tag + ' style="padding:0;margin:0">' + text + '</' + tag + '>'; + } + } + + function addStyle(style, value, text) { + return "<span style='" + style + ":" + value + "'>" + text + "</span>"; + } + + function typeface(name, text) { + return addStyle('font-family', JS.fromString(name), text); + } + function monospace(text) { + return addStyle('font-family', 'monospace', text); + } + function size(px, text) { return addStyle('font-size', px + 'px', text) } + var header = addTag('h1'); + function height(h, text) { return addStyle('font-size', h+'em', text) } + function italic(text) { return addStyle('font-style', 'italic', text) } + var bold = addTag('b'); + + function extract(c) { + if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; } + return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')'; + } + function color(c, text) { + return addStyle('color', extract(c), text); + } + function underline(text) { return addStyle('text-decoration', 'underline', text) } + function overline(text) { return addStyle('text-decoration', 'overline', text) } + function strikeThrough(text) { + return addStyle('text-decoration', 'line-through', text); + } + function link(href, text) { + return "<a href='" + toText(href) + "'>" + text + "</a>"; + } + + function position(pos) { return function(text) { + var e = {ctor:'RawHtml', + _0: '<div style="padding:0;margin:0;text-align:' + + pos + '">' + text + '</div>' + }; + var p = A2(htmlHeight, 0, text); + return A3(Element.newElement, p._0, p._1, e); + } + } + + function asText(v) { + return position('left')(monospace(toText(show(v)))); + } + + function plainText(v) { + return position('left')(toText(v)); + } + + return elm.Native.Text = { + toText: toText, + + header : header, + height : F2(height), + italic : italic, + bold : bold, + underline : underline, + overline : overline, + strikeThrough : strikeThrough, + monospace : monospace, + typeface : F2(typeface), + color : F2(color), + link : F2(link), + + justified : position('justify'), + centered : position('center'), + righted : position('right'), + text : position('left'), + plainText : plainText, + + asText : asText + }; + +}; \ No newline at end of file diff --git a/libraries/Native/Utils.js b/libraries/Native/Utils.js new file mode 100644 index 0000000..0056c52 --- /dev/null +++ b/libraries/Native/Utils.js @@ -0,0 +1,157 @@ + +Elm.Native.Utils = function(elm) { + 'use strict'; + + elm.Native = elm.Native || {}; + if (elm.Native.Utils) return elm.Native.Utils; + + function eq(x,y) { + if (x === y) return true; + if (typeof x === "object") { + var c = 0; + for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; } + return c === Object.keys(y).length; + } + if (typeof x === 'function') { + throw new Error('Equality error: general function equality is ' + + 'undecidable, and therefore, unsupported'); + } + return x === y; + } + + var EQ = 0, LT = 1, GT = 2, ord = ['EQ','LT','GT']; + function compare(x,y) { return { ctor: ord[cmp(x,y)] } } + function cmp(x,y) { + var ord; + if (typeof x !== 'object') return x === y ? EQ : x < y ? LT : GT; + + if (x.ctor === "Cons" || x.ctor === "Nil") { + while (true) { + if (x.ctor === "Nil" && y.ctor === "Nil") return EQ; + if (x.ctor !== y.ctor) return x.ctor === 'Nil' ? LT : GT; + ord = cmp(x._0, y._0); + if (ord !== EQ) return ord; + x = x._1; + y = y._1; + } + } + + if (x.ctor.slice(0,5) === 'Tuple') { + var n = x.ctor.slice(5) - 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.') + } + + + var Tuple0 = { ctor: "Tuple0" }; + function Tuple2(x,y) { return { ctor:"Tuple2", _0:x, _1:y } } + + var count = 0; + function guid(_) { return count++ } + + function copy(r) { + var o = {}; + for (var i in r) { o[i] = r[i]; } + return o; + } + + function remove(x,r) { + var o = copy(r); + if (x in o._) { + o[x] = o._[x][0]; + o._[x] = o._[x].slice(1); + if (o._[x].length === 0) { delete o._[x]; } + } else { + delete o[x]; + } + return o; + } + + function replace(kvs,r) { + var o = copy(r); + for (var i = kvs.length; i--; ) { + var kvsi = kvs[i]; + o[kvsi[0]] = kvsi[1]; + } + return o; + } + + function insert(x,v,r) { + var o = copy(r); + if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []); + o[x] = v; + return o; + } + + function max(a,b) { return a > b ? a : b } + function min(a,b) { return a < b ? a : b } + + function mod(a,b) { + 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 htmlHeight(width, html) { + var t = document.createElement('div'); + t.innerHTML = html; + if (width > 0) { t.style.width = width + "px"; } + t.style.visibility = "hidden"; + t.style.styleFloat = "left"; + t.style.cssFloat = "left"; + + elm.node.appendChild(t); + var w = t.clientWidth; + var h = t.clientHeight; + elm.node.removeChild(t); + return Tuple2(w,h); + } + + function adjustOffset() { + var node = elm.node; + var offsetX = 0, offsetY = 0; + if (node.offsetParent) { + do { + offsetX += node.offsetLeft; + offsetY += node.offsetTop; + } while (node = node.offsetParent); + } + elm.node.offsetX = offsetX; + elm.node.offsetY = offsetY; + } + + if (elm.display === ElmRuntime.Display.COMPONENT) { + elm.node.addEventListener('mouseover', adjustOffset); + } + + return elm.Native.Utils = { + eq:eq, + cmp:compare, + compare:F2(compare), + Tuple0:Tuple0, + Tuple2:Tuple2, + copy: copy, + remove: remove, + replace: replace, + insert: insert, + guid: guid, + max : F2(max), + min : F2(min), + mod : F2(mod), + htmlHeight: F2(htmlHeight), + toFloat: function(x){return x} + }; +}; diff --git a/libraries/Prelude.elm b/libraries/Prelude.elm new file mode 100644 index 0000000..5eee1c4 --- /dev/null +++ b/libraries/Prelude.elm @@ -0,0 +1,202 @@ + +module Prelude where + +import Native.Prelude as N + +-- Convert radians to standard Elm angles (radians). +radians : Float -> Float +radians t = t + +-- Convert degrees to standard Elm angles (radians). +degrees : Float -> Float +degrees d = d * Math.PI / 180 + +-- Convert turns to standard Elm angles (radians). +-- One turn is equal to 360°. +turns : Float -> Float +turns r = 2 * Math.PI * r + +-- Start with polar coordinates (r,θ) +-- and get out cartesian coordinates (x,y). +fromPolar : (Float,Float) -> (Float,Float) +fromPolar (r,t) = (r * N.cos t, r * N.sin t) + +-- Start with cartesian coordinates (x,y) +-- and get out polar coordinates (r,θ). +toPolar : (Float,Float) -> (Float,Float) +toPolar (x,y) = (N.sqrt (x^2 + y^2), N.atan2 y x) + +(+) : Number a -> Number a -> Number a +(-) : Number a -> Number a -> Number a +(*) : Number a -> Number a -> Number a + +-- Floating point division. +(/) : Float -> Float -> Float + +-- Integer division, remainder is discarded. +div : Int -> Int -> Int + +-- Finds the remainder after dividing one number by another: ``4 `rem` 3 == 1`` +rem : Int -> Int -> Int + +-- Perform modular arithmetic: ``7 `mod` 2 == 1`` +mod : Int -> Int -> Int + +-- Exponentiation: `3^2 == 9` +(^) : Number a -> Number a -> Number a + +cos : Float -> Float +sin : Float -> Float +tan : Float -> Float +acos : Float -> Float +asin : Float -> Float + +-- You probably do not want to use this. Because it takes `(y/x)` as the argument +-- there is no way to know where the negative signs come from so the resulting +-- angle is always between π/2 and -π/2 (in quadrants I and IV). +atan : Float -> Float + +-- 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 + +-- Take the square root of a number. +sqrt : Number a -> Number a + +-- Take the absolute value of a number. +abs : Number a -> Number a + +-- Calculate the logarithm of a number with a given base: `logBase 10 100 == 2` +logBase : Number a -> Number a -> Number a + +-- Given two numbers, returns the smaller one. +min : Number a -> Number a -> Number a + +-- Given two numbers, returns the larger one. +max : Number a -> Number a -> Number a + +-- 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 a -> Number a -> Number a -> Number a + +-- An approximation of pi. +pi : Float + +-- An approximation of e. +e : Float + +-- Compare any two values for structural equality. Functions cannot be compared. +(==) : a -> a -> Bool +(/=) : a -> a -> Bool + +(<) : Comparable a -> Comparable a -> Bool +(>) : Comparable a -> Comparable a -> Bool +(<=) : Comparable a -> Comparable a -> Bool +(>=) : Comparable a -> Comparable a -> Bool + +-- 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 a -> Comparable a -> Order + +-- Represents the relative ordering of two things. +-- The relations are less than, equal to, and greater than. +data Order = LT | EQ | GT + +-- The and operator. True if both inputs are True. +(&&) : Bool -> Bool -> Bool + +-- The or operator. True if one or both inputs are True. +(||) : Bool -> Bool -> Bool + +-- The exclusive-or operator. True if exactly one input is True. +xor : Bool -> Bool -> Bool + +-- Negate a boolean value: `(not True == False)` and `(not False == True)` +not : Bool -> Bool + +-- Equal to true. Useful as the last case of a multi-way-if. +otherwise : Bool +otherwise = True + + +-- Conversions + +-- Round a number to the nearest integer. +round : Float -> Int + +-- Truncate a decimal number, rounding towards zero. +truncate : Float -> Int + +-- Floor function, rounding down. +floor : Float -> Int + +-- Ceiling function, rounding up. +ceiling : Float -> Int + +-- Convert an integer into a float. +toFloat : Int -> Float + +-- Convert almost any value to its string representation. +show : a -> String + +-- Read an integer from a string +readInt : String -> Maybe Int + +-- Read a float from a string. +readFloat : String -> Maybe Float + +-- Function Helpers + +-- Function composition: `(f . g == (\\x -> f (g x)))` +(.) : (b -> c) -> (a -> b) -> (a -> c) + +-- Forward function application `x |> f == f x`. This function is useful +-- for avoiding parenthesis 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 + +-- Function application `f <| x == f x`. This function is useful for avoiding +-- parenthesis. Consider the following code to create a text element: +-- +-- text (monospace (toText "code")) +-- +-- This can also be written as: +-- +-- text . monospace <| toText "code" +(<|) : (a -> b) -> a -> b + +-- Given a value, returns exactly the same value. +id : a -> a + +-- Given a 2-tuple, returns the first value. +fst : (a,b) -> a + +-- Given a 2-tuple, returns the second value. +snd : (a,b) -> b + +-- Flips the order of the first two arguments to a function. +flip : (a -> b -> c) -> (b -> a -> c) + +-- Change how arguments are passed to a function. This splits paired arguments +-- into two separate arguments. +curry : ((a,b) -> c) -> a -> b -> c + +-- Change how arguments are passed to a function. This combines two arguments +-- into a sigle pair. +uncurry : (a -> b -> c) -> (a,b) -> c diff --git a/libraries/Random.elm b/libraries/Random.elm new file mode 100644 index 0000000..e32e115 --- /dev/null +++ b/libraries/Random.elm @@ -0,0 +1,13 @@ + +module Random where + +import Native.Random as R + +-- Given a range from low to high and a signal of values, this produces +-- a new signal that changes whenever the input signal changes. The new +-- values are random number between 'low' and 'high' inclusive. +range : Int -> Int -> Signal a -> Signal Int + +-- Produces a new signal that changes whenever the input signal changes. +-- The new values are random numbers in [0..1). +float : Signal a -> Signal Float diff --git a/libraries/Set.elm b/libraries/Set.elm new file mode 100644 index 0000000..356cbde --- /dev/null +++ b/libraries/Set.elm @@ -0,0 +1,65 @@ + +module Set (empty,singleton,insert,remove + ,member + ,foldl,foldr,map + ,union,intersect,diff + ,toList,fromList + ) where + +import Dict as Dict +import List as List + +type Set t = Dict t () + +-- Create an empty set. +empty : Set (Comparable k) +empty = Dict.empty + +-- Create a set with one value. +singleton : Comparable k -> Set (Comparable k) +singleton k = Dict.singleton k () + +-- Insert a value into a set. +insert : Comparable k -> Set (Comparable k) -> Set (Comparable k) +insert k = Dict.insert k () + +-- Remove a value from a set. If the value is not found, no changes are made. +remove : Comparable k -> Set (Comparable k) -> Set (Comparable k) +remove = Dict.remove + +-- Determine if a value is in a set. +member : Comparable k -> Set (Comparable k) -> Bool +member = Dict.member + +-- Get the union of two sets. Keep all values. +union : Set (Comparable k) -> Set (Comparable k) -> Set (Comparable k) +union = Dict.union + +-- Get the intersection of two sets. Keeps values that appear in both sets. +intersect : Set (Comparable k) -> Set (Comparable k) -> Set (Comparable k) +intersect = Dict.intersect + +-- Get the difference between the first set and the second. Keeps values +-- that do not appear in the second set. +diff : Set (Comparable k) -> Set (Comparable k) -> Set (Comparable k) +diff = Dict.diff + +-- Convert a set into a list. +toList : Set (Comparable k) -> [Comparable k] +toList = Dict.keys + +-- Convert a list into a set, removing any duplicates. +fromList : [Comparable k] -> Set (Comparable k) +fromList xs = List.foldl insert empty xs + +-- Fold over the values in a set, in order from lowest to highest. +foldl : (Comparable a -> b -> b) -> b -> Set (Comparable a) -> b +foldl f b s = Dict.foldl (\k _ b -> f k b) b s + +-- Fold over the values in a set, in order from highest to lowest. +foldr : (Comparable a -> b -> b) -> b -> Set (Comparable a) -> b +foldr f b s = Dict.foldr (\k _ b -> f k b) b s + +-- Map a function onto a set, creating a new set with no duplicates. +map : (Comparable a -> Comparable b) -> Set (Comparable a) -> Set (Comparable b) +map f s = fromList (List.map f (toList s)) diff --git a/libraries/Signal.elm b/libraries/Signal.elm new file mode 100644 index 0000000..3f8ef3f --- /dev/null +++ b/libraries/Signal.elm @@ -0,0 +1,109 @@ + +-- The library for general signal manipulation. Some useful functions for +-- working with time (e.g. setting FPS) and combining signals and time (e.g. +-- delaying updates, getting timestamps) can be found in the +-- [`Time`](/docs/Signal/Time.elm) library. +-- +-- Note: There are lift functions up to `lift8`. +module Signal where + +import Native.Signal as S +import List as L + +-- Create a constant signal that never changes. +constant : a -> Signal a + +-- Transform a signal with a given function. +lift : (a -> b) -> Signal a -> Signal b + +-- Combine two signals with a given function. +lift2 : (a -> b -> c) -> Signal a -> Signal b -> Signal c + +-- Combine three signals with a given function. +lift3 : (a -> b -> c -> d) -> Signal a -> Signal b -> Signal c -> Signal d +lift4 : (a -> b -> c -> d -> e) -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e +lift5 : (a -> b -> c -> d -> e -> f) -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e -> Signal f +lift6 : (a -> b -> c -> d -> e -> f -> g) + -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e -> Signal f -> Signal g +lift7 : (a -> b -> c -> d -> e -> f -> g -> h) + -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e -> Signal f -> Signal g -> Signal h +lift8 : (a -> b -> c -> d -> e -> f -> g -> h -> i) + -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e -> Signal f -> Signal g -> Signal h -> Signal i + +-- Create a past-dependent signal. Each value given on the input signal will +-- be accumulated, producing a new output value. +-- +-- For instance, `(foldp (\\t acc -> acc + 1) 0 (Time.every second))` increments every second. +foldp : (a -> b -> b) -> b -> Signal a -> Signal b + +-- Merge two signals into one, biased towards the first signal if both signals +-- update at the same time. +merge : Signal a -> Signal a -> Signal a + +-- Merge many signals into one, biased towards the left-most signal if multiple +-- signals update simultaneously. +merges : [Signal a] -> Signal a + +-- Combine a list of signals into a signal of lists. +combine : [Signal a] -> Signal [a] +combine = L.foldr (S.lift2 (::)) (S.constant []) + + -- Merge two signals into one, but distinguishing the values by marking the first + -- signal as `Left` and the second signal as `Right`. This allows you to easily + -- fold over non-homogeneous inputs. + -- mergeEither : Signal a -> Signal b -> Signal (Either a b) + +-- Count the number of events that have occured. +count : Signal a -> Signal Int + +-- Count the number of events that have occured that satisfy a given predicate. +countIf : (a -> Bool) -> Signal a -> Signal Int + +-- Keep only events that satisfy the given predicate. Elm does not allow +-- undefined signals, so a base case must be provided in case the predicate is +-- never satisfied. +keepIf : (a -> Bool) -> a -> Signal a -> Signal a + +-- Drop events that satisfy the given predicate. Elm does not allow undefined +-- signals, so a base case must be provided in case the predicate is never +-- satisfied. +dropIf : (a -> Bool) -> a -> Signal a -> Signal a + +-- Keep events only when the first signal is true. When the first signal becomes +-- true, the most recent value of the second signal will be propagated. Until +-- the first signal becomes false again, all events will be propagated. Elm does +-- not allow undefined signals, so a base case must be provided in case the first +-- signal is never true. +keepWhen : Signal Bool -> a -> Signal a -> Signal a + +-- Drop events when the first signal is true. When the first signal becomes false, +-- the most recent value of the second signal will be propagated. Until the first +-- signal becomes true again, all events will be propagated. Elm does not allow +-- undefined signals, so a base case must be provided in case the first signal is +-- always true. +dropWhen : Signal Bool -> a -> Signal a -> Signal a + +-- Drop sequential repeated values. For example, if a signal produces the +-- sequence `[1,1,2,2,1]`, it becomes `[1,2,1]` by dropping the values that +-- are the same as the previous value. +dropRepeats : Signal a -> Signal a + +-- Sample from the second input every time an event occurs on the first input. +-- For example, `(sampleOn clicks (every second))` will give the approximate +-- time of the latest click. +sampleOn : Signal a -> Signal b -> Signal b + +-- An alias for `lift`. A prettier way to apply a +-- function to the current value of a signal. +-- +-- lift f signal == f <~ signal +(<~) : (a -> b) -> Signal a -> Signal b + +-- Signal application. This takes two signals, holding a function and +-- a value. It applies the current function to the current value. +-- +-- So the following expressions are equivalent: +-- +-- scene <~ Window.dimensions ~ Mouse.position +-- lift2 scene Window.dimensions Mouse.position +(~) : Signal (a -> b) -> Signal a -> Signal b diff --git a/libraries/Text.elm b/libraries/Text.elm new file mode 100644 index 0000000..923a66d --- /dev/null +++ b/libraries/Text.elm @@ -0,0 +1,65 @@ + +module Text where + +import Native.Text as T + + +-- Convert a string into text which can be styled and displayed. +toText : String -> Text + +-- Set the typeface of some text. The first argument should be a comma separated listing of the desired typefaces +-- "helvetica, arial, sans-serif" +-- Works the same as the CSS font-family property. +typeface : String -> Text -> Text + +-- Switch to a monospace typeface. Good for code snippets. +monospace : Text -> Text + +-- Make text big and noticable. +header : Text -> Text + +-- Create a link. +link : String -> Text -> Text + +-- Set the height of text in \"ems\". 1em is the normal height of text. 2ems is twice that height. +height : Float -> Text -> Text + +-- Set the color of a string. +color : Color -> Text -> Text + +-- Make a string bold. +bold : Text -> Text + +-- Italicize a string. +italic : Text -> Text + +-- Draw a line above a string. +overline : Text -> Text + +-- Underline a string. +underline : Text -> Text + +-- Draw a line through a string. +strikeThrough : Text -> Text + +-- Display justified, styled text. +justified : Text -> Element + +-- Display centered, styled text. +centered : Text -> Element + +-- Display right justified, styled text. +righted : Text -> Element + +-- Display styled text. +text : Text -> Element + +-- Display a plain string. +plainText : String -> Element + +-- Convert anything to it's textual representation and make it displayable in browser +-- +-- asText == text . monospace . show +-- +-- Excellent for debugging. +asText : a -> Element diff --git a/libraries/Time.elm b/libraries/Time.elm new file mode 100644 index 0000000..234f82c --- /dev/null +++ b/libraries/Time.elm @@ -0,0 +1,69 @@ +-- Library for working with time. Type `Time` represents some number of milliseconds. +module Time where + +import Native.Time as T + +-- Type alias to make it clearer when you are working with time values. +-- Using the `Time` constants instead of raw numbers is very highly recommended. +type Time = Float + +-- Units of time, making it easier to specify things like a +-- half-second `(500 * milliseconds)` 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 + +-- Takes desired number of frames per second (fps). The resulting signal +-- gives a sequence of time deltas as quickly as possible until it reaches +-- the desired FPS. A time delta is the time between the last frame and the +-- current frame. +fps : Number a -> Signal Time + +-- Same as the fps function, but you can turn it on and off. Allows you +-- to do brief animations based on user input without major inefficiencies. +-- The first time delta after a pause is always zero, no matter how long +-- the pause was. This way summing the deltas will actually give the amount +-- of time that the output signal has been running. +fpsWhen : Number a -> Signal Bool -> Signal Time + +-- Takes a time interval t. The resulting signal is the current time, +-- updated every t. +every : Time -> Signal Time + +-- Takes a time `t` and any signal. The resulting boolean signal +-- is true for time `t` after every event on the input signal. +-- So ``(second `since` Mouse.clicks)`` would result in a signal +-- that is true for one second after each mouse click and false +-- otherwise. +since : Time -> Signal a -> Signal Bool + +-- Add a timestamp to any signal. Timestamps increase monotonically. Each +-- timestamp is related to a specfic event, so `Mouse.x` and `Mouse.y` will +-- always have the same timestamp because they both rely on the same +-- underlying event. +timestamp : Signal a -> Signal (Time, a) + +-- Delay a signal by a certain amount of time. So `(delay second Mouse.clicks)` +-- will update one second later than any mouse click. +delay : Time -> Signal a -> Signal a diff --git a/libraries/Touch.elm b/libraries/Touch.elm new file mode 100644 index 0000000..d2b0ee9 --- /dev/null +++ b/libraries/Touch.elm @@ -0,0 +1,20 @@ +-- This is an early version of the touch library. It will likely grow to +-- include gestures that would be useful for both games and web-pages. +module Touch where + +import Native.Touch as T + +-- Every `Touch` has `xy` coordinates. It also has an identifier `id` to +-- distinguish one touch from another. +-- +-- A touch also keeps info about the intial point and time of contact: +-- `x0`, `y0`, and `t0`. This helps compute more complicated gestures +-- like taps, drags, and swipes which need to know about timing or direction. +type Touch = { x:Int, y:Int, id:Int, x0:Int, y0:Int, t0:Time } + +-- A list of ongoing touches. +touches : Signal [Touch] + +-- The last position that was tapped. Default value is `{x=0,y=0}`. +-- Updates whenever the user taps the screen. +taps : Signal { x:Int, y:Int } diff --git a/libraries/WebSocket.elm b/libraries/WebSocket.elm new file mode 100644 index 0000000..9263c56 --- /dev/null +++ b/libraries/WebSocket.elm @@ -0,0 +1,13 @@ +-- A library for low latency HTTP communication. See the HTTP library for +-- standard requests like GET, POST, etc. +module WebSocket where + +import Native.WebSocket as WS + +-- Create a web-socket. The first argument is the URL of the desired +-- web-socket server. The input signal holds the outgoing messages, +-- and the resulting signal contains the incoming ones. +connect : String -> Signal String -> Signal String + +-- data Action = Open String | Close String | Send String String +-- connections : Signal Action -> Signal String \ No newline at end of file diff --git a/libraries/Window.elm b/libraries/Window.elm new file mode 100644 index 0000000..efdaeaa --- /dev/null +++ b/libraries/Window.elm @@ -0,0 +1,14 @@ + +module Window where + +import Native.Window as W + +-- The current dimensions of the window (i.e. the area viewable to the +-- user, not including scroll bars). +dimensions : Signal (Int,Int) + +-- The current width of the window. +width : Signal Int + +-- The current height of the window. +height : Signal Int diff --git a/runtime/Init.js b/runtime/Init.js new file mode 100644 index 0000000..a003f98 --- /dev/null +++ b/runtime/Init.js @@ -0,0 +1,117 @@ + +(function() { +'use strict'; + +Elm.fullscreen = function(module) { + var style = document.createElement('style'); + style.type = 'text/css'; + style.innerHTML = "html,head,body { padding:0; margin:0; }" + + "body { font-family: calibri, helvetica, arial, sans-serif; }"; + document.head.appendChild(style); + var container = document.createElement('div'); + document.body.appendChild(container); + return init(ElmRuntime.Display.FULLSCREEN, container, module); +}; + +Elm.byId = function(id, module) { + var container = document.getElementById(id); + var tag = container.tagName; + if (tag !== 'DIV') { + throw new Error('Elm.byId must be given a div, not a ' + tag + '.'); + } + while (container.hasChildNodes()) { + container.removeChild(container.lastChild); + } + return init(ElmRuntime.Display.COMPONENT, container, module); +}; + +Elm.worker = function(module) { + return init(ElmRuntime.Display.NONE, {}, module); +}; + +function init(display, container, module) { + // defining state needed for an instance of the Elm RTS + var signalGraph = null; + var inputs = []; + var visualModel = null; + + function notify(id, v) { + var timestep = Date.now(); + var hasListener = false; + for (var i = inputs.length; i--; ) { + // must maintain the order of this stmt to avoid having the || + // short-circuiting the necessary work of recv + hasListener = inputs[i].recv(timestep, id, v) || hasListener; + } + return hasListener; + } + + container.offsetX = 0; + container.offsetY = 0; + + // create the actual RTS. Any impure modules will attach themselves to this + // object. This permits many Elm programs to be embedded per document. + var elm = { notify:notify, + node:container, + display:display, + id:ElmRuntime.guid(), + inputs:inputs + }; + + // Set up methods to communicate with Elm program from JS. + function send(name, value) { + if (typeof value === 'undefined') return function(v) { return send(name,v); }; + var e = document.createEvent('Event'); + e.initEvent(name + '_' + elm.id, true, true); + e.value = value; + document.dispatchEvent(e); + } + function recv(name, handler) { + document.addEventListener(name + '_' + elm.id, handler); + } + + recv('log', function(e) {console.log(e.value)}); + recv('title', function(e) {document.title = e.value}); + recv('redirect', function(e) { + if (e.value.length > 0) { window.location = e.value; } + }); + + // If graphics are not enabled, escape early, skip over setting up DOM stuff. + if (display === ElmRuntime.Display.NONE) { + module(elm); + return { send : send, recv : recv }; + } + + var Render = ElmRuntime.use(ElmRuntime.Render.Element); + + // evaluate the given module and extract its 'main' value. + signalGraph = module(elm).main; + + // make sure the signal graph is actually a signal, extract the visual model, + // and filter out any unused inputs. + var Signal = Elm.Signal(elm); + if (!('recv' in signalGraph)) signalGraph = Signal.constant(signalGraph); + visualModel = signalGraph.value; + inputs = ElmRuntime.filterDeadInputs(inputs); + + // Add the visualModel to the DOM + container.appendChild(Render.render(visualModel)); + if (elm.Native.Window) elm.Native.Window.resizeIfNeeded(); + + // set up updates so that the DOM is adjusted as necessary. + var update = Render.update; + function domUpdate(value) { + ElmRuntime.draw(function(_) { + update(container.firstChild, visualModel, value); + visualModel = value; + if (elm.Native.Window) elm.Native.Window.resizeIfNeeded(); + }); + return value; + } + + signalGraph = A2(Signal.lift, domUpdate, signalGraph); + + return { send : send, recv : recv, node : container }; +}; + +}()); \ No newline at end of file diff --git a/runtime/Render/Collage.js b/runtime/Render/Collage.js new file mode 100644 index 0000000..fc4b22d --- /dev/null +++ b/runtime/Render/Collage.js @@ -0,0 +1,340 @@ + +ElmRuntime.Render.Collage = function() { +'use strict'; + +var Render = ElmRuntime.use(ElmRuntime.Render.Element); +var Matrix = Elm.Matrix2D({}); +var Utils = ElmRuntime.use(ElmRuntime.Render.Utils); +var newElement = Utils.newElement, + extract = Utils.extract, fromList = Utils.fromList, + fromString = Utils.fromString, addTransform = Utils.addTransform; + +function trace(ctx, path) { + var points = fromList(path); + var i = points.length - 1; + if (i <= 0) return; + ctx.moveTo(points[i]._0, points[i]._1); + while (i--) { ctx.lineTo(points[i]._0, points[i]._1); } + if (path.closed) { + i = points.length - 1; + ctx.lineTo(points[i]._0, points[i]._1); + } +} + +function line(ctx,style,path) { + style.dashing.ctor === 'Nil' ? trace(ctx, path) : customLineHelp(ctx, style, path); + ctx.stroke(); +} + +function customLineHelp(ctx, style, path) { + var points = fromList(path); + if (path.closed) points.push(points[0]); + var pattern = fromList(style.dashing); + var i = points.length - 1; + if (i <= 0) return; + var x0 = points[i]._0, y0 = points[i]._1; + var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0; + var pindex = 0, plen = pattern.length; + var draw = true, segmentLength = pattern[0]; + ctx.moveTo(x0,y0); + while (i--) { + x1 = points[i]._0; y1 = points[i]._1; + dx = x1 - x0; dy = y1 - y0; + remaining = Math.sqrt(dx * dx + dy * dy); + while (segmentLength <= remaining) { + x0 += dx * segmentLength / remaining; + y0 += dy * segmentLength / remaining; + ctx[draw ? 'lineTo' : 'moveTo'](x0, y0); + // update starting position + dx = x1 - x0; dy = y1 - y0; + remaining = Math.sqrt(dx * dx + dy * dy); + // update pattern + draw = !draw; + pindex = (pindex + 1) % plen; + segmentLength = pattern[pindex]; + } + if (remaining > 0) { + ctx[draw ? 'lineTo' : 'moveTo'](x1, y1); + segmentLength -= remaining; + } + x0 = x1; y0 = y1; + } +} + +function drawLine(ctx, style, path) { + ctx.lineWidth = style.width; + var cap = style.cap.ctor; + ctx.lineCap = cap === 'Flat' ? 'butt' : + cap === 'Round' ? 'round' : 'square'; + var join = style.join.ctor; + ctx.lineJoin = join === 'Smooth' ? 'round' : + join === 'Sharp' ? 'miter' : 'bevel'; + ctx.miterLimit = style.join._0 || 10; + ctx.strokeStyle = extract(style.color); + return line(ctx, style, path); +} + +function texture(redo, ctx, src) { + var img = new Image(); + img.src = fromString(src); + img.onload = redo; + return ctx.createPattern(img, 'repeat'); +} + +function gradient(ctx, grad) { + var g; + var stops = []; + if (grad.ctor === 'Linear') { + var p0 = grad._0, p1 = grad._1; + g = ctx.createLinearGradient(p0._0, -p0._1, p1._0, -p1._1); + stops = fromList(grad._2); + } else { + var p0 = grad._0, p2 = grad._2; + g = ctx.createRadialGradient(p0._0, -p0._1, grad._1, p2._0, -p2._1, grad._3); + stops = fromList(grad._4); + } + var len = stops.length; + for (var i = 0; i < len; ++i) { + var stop = stops[i]; + g.addColorStop(stop._0, extract(stop._1)); + } + return g; +} + +function drawShape(redo, ctx, style, path) { + trace(ctx, path); + var sty = style.ctor; + ctx.fillStyle = + sty === 'Solid' ? extract(style._0) : + sty === 'Texture' ? texture(redo, ctx, style._0) : gradient(ctx, style._0); + ctx.fill(); +} + +function drawImage(redo, ctx, form) { + var img = new Image(); + img.onload = redo; + img.src = fromString(form._3); + var w = form._0, + h = form._1, + pos = form._2, + srcX = pos._0, + srcY = pos._1, + srcW = w, + srcH = h, + destX = -w/2, + destY = -h/2, + destW = w, + destH = h; + + ctx.drawImage(img, srcX, srcY, srcW, srcH, destX, destY, destW, destH); +} + +function renderForm(redo, ctx, form) { + ctx.save(); + var x = form.x, y = form.y, theta = form.theta, scale = form.scale; + if (x !== 0 || y !== 0) ctx.translate(x, y); + if (theta !== 0) ctx.rotate(theta); + ctx.scale(scale,-scale); + ctx.beginPath(); + var f = form.form; + switch(f.ctor) { + case 'FPath' : drawLine(ctx, f._0, f._1); break; + case 'FImage': drawImage(redo, ctx, f); break; + case 'FShape': + if (f._0.ctor === 'Left') { + f._1.closed = true; + drawLine(ctx, f._0._0, f._1); + } else { + drawShape(redo, ctx, f._0._0, f._1); + } + break; + } + ctx.restore(); +} + +function formToMatrix(form) { + var scale = form.scale; + var matrix = A6( Matrix.matrix, scale, 0, 0, scale, scale * form.x, scale * form.y ); + + var theta = form.theta + if (theta !== 0) + matrix = A2( Matrix.multiply, matrix, Matrix.rotation(theta) ); + + return matrix; +} + +function makeTransform(w, h, form, matrices) { + var props = form.form._0.props; + var m = A6( Matrix.matrix, 1, 0, 0, 1, + (w - props.width)/2, + (h - props.height)/2 ); + var len = matrices.length; + for (var i = 0; i < len; ++i) { m = A2( Matrix.multiply, m, matrices[i] ); } + m = A2( Matrix.multiply, m, formToMatrix(form) ); + + return 'matrix(' + m[0] + ',' + m[3] + ',' + + (-m[1]) + ',' + (-m[4]) + ',' + + m[2] + ',' + m[5] + ')'; +} + +function stepperHelp(list) { + var arr = fromList(list); + var i = 0; + function peekNext() { + return i < arr.length ? arr[i].form.ctor : ''; + } + // assumes that there is a next element + function next() { + var out = arr[i]; + ++i; + return out; + } + return { peekNext:peekNext, next:next }; +} + +function stepper(forms) { + var ps = [stepperHelp(forms)]; + var matrices = []; + function peekNext() { + var len = ps.length; + var formType = ''; + for (var i = 0; i < len; ++i ) { + if (formType = ps[i].peekNext()) return formType; + } + return ''; + } + // assumes that there is a next element + function next(ctx) { + while (!ps[0].peekNext()) { ps.shift(); matrices.pop(); ctx.restore(); } + var out = ps[0].next(); + var f = out.form; + if (f.ctor === 'FGroup') { + ps.unshift(stepperHelp(f._1)); + var m = A2( Matrix.multiply, f._0, formToMatrix(out)); + ctx.save(); + ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]); + matrices.push(m); + } + return out; + } + function transforms() { return matrices; } + return { peekNext:peekNext, next:next, transforms:transforms }; +} + +function makeCanvas(w,h) { + var canvas = newElement('canvas'); + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + canvas.style.display = "block"; + canvas.style.position = "absolute"; + canvas.width = w; + canvas.height = h; + return canvas; +} + +function render(model) { + var div = newElement('div'); + update(div, model, model); + return div; +} + +function updateTracker(w,h,div) { + var kids = div.childNodes; + var i = 0; + function transform(transforms, ctx) { + ctx.translate(w/2, h/2); + var len = transforms.length; + for (var i = 0; i < len; ++i) { + var m = transforms[i]; + ctx.save(); + ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]); + } + return ctx; + } + function getContext(transforms) { + while (i < kids.length) { + var node = kids[i++]; + if (node.getContext) { + node.width = w; + node.height = h; + node.style.width = w + 'px'; + node.style.height = h + 'px'; + return transform(transforms, node.getContext('2d')); + } + div.removeChild(node); + } + var canvas = makeCanvas(w,h); + div.appendChild(canvas); + // we have added a new node, so we must step our position + ++i; + return transform(transforms, canvas.getContext('2d')); + } + function element(matrices, form) { + var container = kids[i]; + if (!container || container.getContext) { + container = newElement('div'); + container.style.overflow = 'hidden'; + container.style.position = 'absolute'; + addTransform(container.style, 'scaleY(-1)'); + if (!container) { + div.appendChild(container); + } else { + div.insertBefore(container, kids[i]); + } + } + // we have added a new node, so we must step our position + ++i; + + container.style.width = w + 'px'; + container.style.height = h + 'px'; + + var elem = form.form._0; + var node = container.firstChild; + if (node) { + Render.update(node, node.oldElement, elem); + node = container.firstChild; + } else { + node = Render.render(elem); + container.appendChild(node); + } + node.oldElement = elem; + addTransform(node.style, makeTransform(w, h, form, matrices)); + } + return { getContext:getContext, element:element }; +} + + +function update(div, _, model) { + var w = model.w; + var h = model.h; + div.style.width = w + 'px'; + div.style.height = h + 'px'; + if (model.forms.ctor === 'Nil') { + while (div.hasChildNodes()) { + div.removeChild(div.lastChild); + } + } + var stpr = stepper(model.forms); + var tracker = updateTracker(w,h,div); + var ctx = null; + var formType = ''; + + while (formType = stpr.peekNext()) { + if (ctx === null && formType !== 'FElement') { + ctx = tracker.getContext(stpr.transforms()); + ctx.scale(1,-1); + } + var form = stpr.next(ctx); + if (formType === 'FElement') { + tracker.element(stpr.transforms(), form); + ctx = null; + } else if (formType !== 'FGroup') { + renderForm(function() { update(div, model, model); }, ctx, form); + } + } + return div; +} + +return { render:render, update:update }; + +}; diff --git a/runtime/Render/Element.js b/runtime/Render/Element.js new file mode 100644 index 0000000..30d57d2 --- /dev/null +++ b/runtime/Render/Element.js @@ -0,0 +1,269 @@ + +ElmRuntime.Render.Element = function() { +'use strict'; + +var Utils = ElmRuntime.use(ElmRuntime.Render.Utils); +var newElement = Utils.newElement, extract = Utils.extract, + addTransform = Utils.addTransform, removeTransform = Utils.removeTransform, + fromList = Utils.fromList, eq = Utils.eq; + +function setProps(props, e) { + e.style.width = (props.width |0) + 'px'; + e.style.height = (props.height|0) + 'px'; + if (props.opacity !== 1) { e.style.opacity = props.opacity; } + if (props.color.ctor === 'Just') { + e.style.backgroundColor = extract(props.color._0); + } + if (props.tag !== '') { e.id = props.tag; } + if (props.href !== '') { + var a = newElement('a'); + a.href = props.href; + a.appendChild(e); + return a; + } + return e; +} + +function image(props, img) { + switch (img._0.ctor) { + case 'Plain': return plainImage(img._3); + case 'Fitted': return fittedImage(props.width, props.height, img._3); + case 'Cropped': return croppedImage(img,props.width,props.height,img._3); + } +} + +function plainImage(src) { + var img = newElement('img'); + img.src = src; + img.name = src; + img.style.display = "block"; + return img; +} + +function fittedImage(w, h, src) { + var e = newElement('div'); + e.style.position = "relative"; + e.style.overflow = "hidden"; + + var img = newElement('img'); + img.onload = function() { + img.style.position = 'absolute'; + img.style.margin = 'auto'; + + var sw = w, sh = h; + if (w / h > this.width / this.height) { + sh = Math.round(this.height * w / this.width); + } else { + sw = Math.round(this.width * h / this.height); + } + img.style.width = sw + 'px'; + img.style.height = sh + 'px'; + img.style.left = ((w - sw) / 2) + 'px'; + img.style.top = ((h - sh) / 2) + 'px'; + }; + img.src = src; + img.name = src; + e.appendChild(img); + return e; +} + +function croppedImage(elem, w, h, src) { + var pos = elem._0._0; + var e = newElement('div'); + e.style.position = "relative"; + e.style.overflow = "hidden"; + + var img = newElement('img'); + img.onload = function() { + img.style.position = 'absolute'; + img.style.margin = 'auto'; + var sw = w / elem._1, sh = h / elem._2; + img.style.width = ((this.width * sw)|0) + 'px'; + img.style.height = ((this.height * sh)|0) + 'px'; + img.style.left = ((- pos._0 * sw)|0) + 'px'; + img.style.top = ((- pos._1 * sh)|0) + 'px'; + }; + img.src = src; + img.name = src; + e.appendChild(img); + return e; +} + +function goIn(e) { e.style.position = 'absolute'; return e; } +function goDown(e) { return e } +function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; } +function flowWith(f, array) { + var container = newElement('div'); + for (var i = array.length; i--; ) { + container.appendChild(f(render(array[i]))); + } + return container; +} + +function flow(dir,elist) { + var array = fromList(elist); + switch(dir.ctor) { + case "DDown": array.reverse(); + case "DUp": return flowWith(goDown,array); + case "DRight": array.reverse(); + case "DLeft": return flowWith(goRight,array); + case "DOut": array.reverse(); + case "DIn": return flowWith(goIn,array); + } +} + +function toPos(pos) { + switch(pos.ctor) { + case "Absolute": return pos._0 + "px"; + case "Relative": return (pos._0 * 100) + "%"; + } +} + +function setPos(pos,w,h,e) { + e.style.position = 'absolute'; + e.style.margin = 'auto'; + var transform = ''; + switch(pos.horizontal.ctor) { + case 'P': e.style.right = toPos(pos.x); break; + case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) '; + case 'N': e.style.left = toPos(pos.x); break; + } + switch(pos.vertical.ctor) { + case 'N': e.style.bottom = toPos(pos.y); break; + case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)'; + case 'P': e.style.top = toPos(pos.y); break; + } + if (transform !== '') addTransform(e.style, transform); + return e; +} + +function container(pos,elem) { + var e = render(elem); + setPos(pos, elem.props.width, elem.props.height, e); + var div = newElement('div'); + div.style.position = 'relative'; + div.style.overflow = 'hidden'; + div.appendChild(e); + return div; +} + +function rawHtml(html) { + var e = newElement('div'); + e.innerHTML = html; + return e; +} + +function render(elem) { return setProps(elem.props, makeElement(elem)); } +function makeElement(e) { + var elem = e.element; + switch(elem.ctor) { + case 'Image': return image(e.props, elem); + case 'Flow': return flow(elem._0, elem._1); + case 'Container': return container(elem._0, elem._1); + case 'Spacer': return newElement('div'); + case 'RawHtml': return rawHtml(elem._0); + case 'Custom': return elem.render(elem.model); + } +} + +function update(node, curr, next) { + if (node.tagName === 'A') { node = node.firstChild; } + if (curr.props.id === next.props.id) return updateProps(node, curr, next); + if (curr.element.ctor !== next.element.ctor) { + node.parentNode.replaceChild(render(next),node); + return true; + } + var nextE = next.element, currE = curr.element; + switch(nextE.ctor) { + case "Spacer": break; + case "RawHtml": + if (nextE._0 !== currE._0) node.innerHTML = nextE._0; + break; + case "Image": + if (nextE._0.ctor === 'Plain') { + if (nextE._3 !== currE._3) node.src = nextE._3; + } else if (!eq(nextE,currE) || + next.props.width !== curr.props.width || + next.props.height !== curr.props.height) { + node.parentNode.replaceChild(render(next),node); + return true; + } + break; + case "Flow": + var arr = fromList(nextE._1); + for (var i = arr.length; i--; ) { arr[i] = arr[i].element.ctor; } + if (nextE._0.ctor !== currE._0.ctor) { + node.parentNode.replaceChild(render(next),node); + return true; + } + var nexts = fromList(nextE._1); + var kids = node.childNodes; + if (nexts.length !== kids.length) { + node.parentNode.replaceChild(render(next),node); + return true; + } + var currs = fromList(currE._1); + var goDir = function(x) { return x; }; + switch(nextE._0.ctor) { + case "DDown": case "DUp": goDir = goDown; break; + case "DRight": case "DLeft": goDir = goRight; break; + case "DOut": case "DIn": goDir = goIn; break; + } + for (var i = kids.length; i-- ;) { + update(kids[i],currs[i],nexts[i]); + goDir(kids[i]); + } + break; + case "Container": + var inner = node.firstChild; + if (!update(inner, currE._1, nextE._1)) { + if (nextE._0.horizontal.ctor !== currE._0.horizontal.ctor) { + inner.style.left = inner.style.right = 'none'; + removeTransform(inner.style); + } + if (nextE._0.vertical.ctor !== currE._0.vertical.ctor) { + inner.style.top = inner.style.bottom = 'none'; + removeTransform(inner.style); + } + } + setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, inner); + break; + case "Custom": + if (currE.type === nextE.type) { + var done = nextE.update(node, currE.model, nextE.model); + if (done) return; + } else { + return node.parentNode.replaceChild(render(next), node); + } + } + updateProps(node, curr, next); +} + +function updateProps(node, curr, next) { + var props = next.props, currP = curr.props, e = node; + if (props.width !== currP.width) e.style.width = (props.width |0) + 'px'; + if (props.height !== currP.height) e.style.height = (props.height|0) + 'px'; + if (props.opacity !== 1 && props.opacity !== currP.opacity) { + e.style.opacity = props.opacity; + } + var nextColor = (props.color.ctor === 'Just' ? + extract(props.color._0) : 'transparent'); + if (e.style.backgroundColor !== nextColor) { + e.style.backgroundColor = nextColor; + } + if (props.tag !== currP.tag) { e.id = props.tag; } + if (props.href !== currP.href) { + if (currP.href === '') { + var a = newElement('a'); + a.href = props.href; + a.appendChild(e); + e.parentNode.replaceChild(a,e); + } else { + node.parentNode.href = props.href; + } + } +} + +return { render:render, update:update }; + +}; \ No newline at end of file diff --git a/runtime/Render/Utils.js b/runtime/Render/Utils.js new file mode 100644 index 0000000..aa4a6cf --- /dev/null +++ b/runtime/Render/Utils.js @@ -0,0 +1,49 @@ + +ElmRuntime.Render.Utils = function() { +'use strict'; + +function newElement(elementType) { + var e = document.createElement(elementType); + e.style.padding = "0"; + e.style.margin = "0"; + return e; +} + +function addTo(container, elem) { + container.appendChild(elem); +} + +function extract(c) { + if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; } + return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')'; +} + +function addTransform(style, trans) { + style.transform = trans; + style.msTransform = trans; + style.MozTransform = trans; + style.webkitTransform = trans; + style.OTransform = trans; +} + +function removeTransform(style) { + style.transform = 'none'; + style.msTransform = 'none'; + style.MozTransform = 'none'; + style.webkitTransform = 'none'; + style.OTransform = 'none'; +} + +var List = Elm.Native.List({}); + +return {addTo:addTo, + newElement:newElement, + extract : extract, + fromList: List.toArray, + fromString: function(s) { return List.toArray(s).join(''); }, + toString: List.fromArray, + eq: Elm.Native.Utils({}).eq, + addTransform: addTransform, + removeTransform: removeTransform + }; +}; diff --git a/runtime/Utils.js b/runtime/Utils.js new file mode 100644 index 0000000..fa44af2 --- /dev/null +++ b/runtime/Utils.js @@ -0,0 +1,53 @@ + +(function() { +'use strict'; + +ElmRuntime.Display = { FULLSCREEN: 0, COMPONENT: 1, NONE: 2 }; + +ElmRuntime.counter = 0; +ElmRuntime.guid = function() { return ElmRuntime.counter++; } + +ElmRuntime.use = function(M) { + if (typeof M === 'function') M = M(); + return M; +}; + +function isAlive(input) { + if (!('defaultNumberOfKids' in input)) return true; + var len = input.kids.length; + if (len === 0) return false; + if (len > input.defaultNumberOfKids) return true; + var alive = false; + for (var i = len; i--; ) { + alive = alive || isAlive(input.kids[i]); + } + return alive; +} + +ElmRuntime.filterDeadInputs = function(inputs) { + var temp = []; + for (var i = inputs.length; i--; ) { + if (isAlive(inputs[i])) temp.push(inputs[i]); + } + return temp; +}; + +// define the draw function +var vendors = ['ms', 'moz', 'webkit', 'o']; +for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { + window.requestAnimationFrame = window[vendors[i]+'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[i]+'CancelAnimationFrame'] || + window[vendors[i]+'CancelRequestAnimationFrame']; +} + +if (window.requestAnimationFrame && window.cancelAnimationFrame) { + var previous = 0; + ElmRuntime.draw = function(callback) { + window.cancelAnimationFrame(previous); + previous = window.requestAnimationFrame(callback); + }; +} else { + ElmRuntime.draw = function(callback) { callback(); }; +} + +}()); diff --git a/elm/LICENSE b/server/LICENSE similarity index 100% rename from elm/LICENSE rename to server/LICENSE diff --git a/elm-server/Server.hs b/server/Server.hs similarity index 93% rename from elm-server/Server.hs rename to server/Server.hs index 776b151..72fcf7c 100644 --- a/elm-server/Server.hs +++ b/server/Server.hs @@ -16,7 +16,8 @@ runtime = "/elm-" ++ showVersion version ++ ".js" serve :: String -> IO () serve libLoc = do - putStrLn ("Elm Server " ++ showVersion version ++ ": running at <http://localhost:8000>") + putStrLn ("Elm Server " ++ showVersion version ++ + ": running at <http://localhost:8000>") putStrLn "Just refresh a page to recompile it!" simpleHTTP nullConf $ do _ <- compressedResponseFilter @@ -43,7 +44,7 @@ main = getArgs >>= parse parse :: [String] -> IO () parse ("--help":_) = putStrLn usage parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version) -parse [] = serve =<< Elm.runtimeLocation +parse [] = serve =<< Elm.runtime parse [arg] | "--runtime-location=" `isPrefixOf` arg = serve . tail $ dropWhile (/='=') arg diff --git a/elm-server/Setup.hs b/server/Setup.hs similarity index 100% rename from elm-server/Setup.hs rename to server/Setup.hs diff --git a/elm-server/elm-server.cabal b/server/elm-server.cabal similarity index 94% rename from elm-server/elm-server.cabal rename to server/elm-server.cabal index a4f85e2..68c4568 100644 --- a/elm-server/elm-server.cabal +++ b/server/elm-server.cabal @@ -1,5 +1,5 @@ Name: elm-server -Version: 0.7 +Version: 0.8 Synopsis: The Elm language server. Description: This package provides a standalone, Happstack-based Elm server. @@ -35,4 +35,4 @@ Executable elm-server happstack-server == 7.1.1 || == 7.1.7 || == 7.0.2, deepseq, filepath, - Elm >= 0.7 + Elm >= 0.8