├── .gitignore ├── README.md ├── examples ├── fractal-architecture │ ├── README.md │ ├── elm.json │ ├── index.html │ └── src │ │ ├── App │ │ ├── Counter │ │ │ ├── Messages.elm │ │ │ ├── Model.elm │ │ │ ├── Subscriptions.elm │ │ │ ├── Update.elm │ │ │ └── View.elm │ │ ├── Messages.elm │ │ ├── Model.elm │ │ ├── Subscriptions.elm │ │ ├── Update.elm │ │ └── View.elm │ │ ├── Main.elm │ │ └── Utils.elm ├── generic-update │ ├── Main.elm │ ├── README.md │ └── elm.json ├── http-get │ ├── Main.elm │ ├── README.md │ └── elm.json ├── http-json-server │ ├── README.md │ ├── data.json │ ├── elm.json │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ └── src │ │ ├── Main.elm │ │ ├── favicon.ico │ │ ├── index.js │ │ ├── main.css │ │ └── registerServiceWorker.js ├── key-combinations │ ├── Main.elm │ ├── README.md │ └── elm.json ├── module-composition-tagger │ ├── Form.elm │ ├── Form │ │ └── Field.elm │ ├── Main.elm │ ├── README.md │ └── elm.json ├── module-composition │ ├── Helper.elm │ ├── Input.elm │ ├── Main.elm │ ├── README.md │ └── elm.json ├── ports │ ├── Main.elm │ ├── README.md │ ├── elm.json │ ├── index.html │ └── index.js ├── random-initial-seed │ ├── elm.json │ └── src │ │ └── Main.elm ├── random-user-seed │ ├── Main.elm │ ├── README.md │ └── elm.json └── select2-integration │ ├── .gitignore │ ├── README.md │ ├── elm.json │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo.svg │ └── manifest.json │ └── src │ ├── App.elm │ ├── Main.elm │ ├── favicon.ico │ ├── index.js │ ├── main.css │ └── registerServiceWorker.js ├── package.json └── tasks └── publish.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | .idea/dictionaries 10 | .idea/vcs.xml 11 | .idea/jsLibraryMappings.xml 12 | 13 | # Sensitive or high-churn files: 14 | .idea/dataSources.ids 15 | .idea/dataSources.xml 16 | .idea/dataSources.local.xml 17 | .idea/sqlDataSources.xml 18 | .idea/dynamic.xml 19 | .idea/uiDesigner.xml 20 | 21 | # Gradle: 22 | .idea/gradle.xml 23 | .idea/libraries 24 | 25 | # Mongo Explorer plugin: 26 | .idea/mongoSettings.xml 27 | 28 | ## File-based project format: 29 | *.iws 30 | 31 | ## Plugin-specific files: 32 | 33 | # IntelliJ 34 | /out/ 35 | 36 | # mpeltonen/sbt-idea plugin 37 | .idea_modules/ 38 | 39 | # JIRA plugin 40 | atlassian-ide-plugin.xml 41 | 42 | # Crashlytics plugin (for Android Studio and IntelliJ) 43 | com_crashlytics_export_strings.xml 44 | crashlytics.properties 45 | crashlytics-build.properties 46 | fabric.properties 47 | ### Elm template 48 | # elm-package generated files 49 | elm-stuff/ 50 | # elm-repl generated files 51 | repl-temp-* 52 | ### Node template 53 | # Logs 54 | logs 55 | *.log 56 | npm-debug.log* 57 | 58 | # Runtime data 59 | pids 60 | *.pid 61 | *.seed 62 | 63 | # Directory for instrumented libs generated by jscoverage/JSCover 64 | lib-cov 65 | 66 | # Coverage directory used by tools like istanbul 67 | coverage 68 | 69 | # nyc test coverage 70 | .nyc_output 71 | 72 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 73 | .grunt 74 | 75 | # node-waf configuration 76 | .lock-wscript 77 | 78 | # Compiled binary addons (http://nodejs.org/api/addons.html) 79 | build/Release 80 | 81 | # Dependency directories 82 | node_modules 83 | jspm_packages 84 | 85 | # Optional npm cache directory 86 | .npm 87 | 88 | # Optional REPL history 89 | .node_repl_history 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practical examples in Elm 2 | 3 | A collection of examples with advanced techniques for real-world Elm apps. 4 | 5 | *Note:* 6 | Most of these examples haven't been updated for some time. They do not represent the sate-of-art code, but rather a general idea on how you might tackle different problems. 7 | 8 | ## Examples 9 | 10 | - [Elm Fractal Architecture](examples/fractal-architecture) 11 | - [HTTP GET with Elm](examples/http-get) 12 | - [Key combinations with Subscription](examples/key-combinations) 13 | - [Generic update function](examples/generic-update) 14 | - [Module composition in Elm](examples/module-composition) 15 | - [Module composition in Elm with tagger function](examples/module-composition-tagger) 16 | - [JavaScript interop with Elm](examples/ports) 17 | - [Random value with user-specified seed](examples/random-user-seed) 18 | - [Select2 integration into Elm application](examples/select2-integration) 19 | - [Elm SPA using Create Elm App](https://github.com/halfzebra/elm-spa-example) 20 | 21 | ## I want more examples 22 | 23 | Check-out the collection of curated examples at [Awesome Elm - Examples](https://github.com/isRuslan/awesome-elm#examples). 24 | 25 | ## I need help 26 | 27 | Hit me on Twitter with ideas or requests for new examples [@eduardkyvenko](https://twitter.com/eduardkyvenko) 28 | 29 | Don't be a stranger, stop by at [Elm Slack](https://elmlang.slack.com/)! 30 | -------------------------------------------------------------------------------- /examples/fractal-architecture/README.md: -------------------------------------------------------------------------------- 1 | # Elm Fractal Architecture example 2 | 3 | An example of Elm project organisation with a self-resembling architecture. 4 | 5 | Compose View, Update, Message, Model, Subscriptions and Commands with Fractal Architecture. 6 | 7 | Features: 8 | - Module splitting 9 | - Usage of `Browser.element` 10 | - Module composition 11 | - [Subscription batching](src/App/Subscriptions.elm) for subscribing to `Keyboard` messages from child modules 12 | 13 | ## Building the example 14 | 15 | Since this example features `Browser.element` usage, it is impossible to build it with `elm reactor`. 16 | 17 | You have to explicitly specify the `--output=index.js` 18 | 19 | ```sh 20 | $ elm make src/Main.elm --output=index.js 21 | ``` 22 | -------------------------------------------------------------------------------- /examples/fractal-architecture/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src/" 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/json": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/fractal-architecture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Counter/Messages.elm: -------------------------------------------------------------------------------- 1 | module App.Counter.Messages exposing (Msg(..)) 2 | 3 | 4 | type Msg 5 | = Up 6 | | Down 7 | | Keydown String 8 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Counter/Model.elm: -------------------------------------------------------------------------------- 1 | module App.Counter.Model exposing (Model, init) 2 | 3 | 4 | type alias Model = 5 | Int 6 | 7 | 8 | init : Int -> Model 9 | init start = 10 | start 11 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Counter/Subscriptions.elm: -------------------------------------------------------------------------------- 1 | module App.Counter.Subscriptions exposing (subscriptions) 2 | 3 | import App.Counter.Messages exposing (..) 4 | import App.Counter.Model exposing (..) 5 | import Browser.Events as Events 6 | import Json.Decode as Decode 7 | 8 | 9 | subscriptions : Model -> Sub Msg 10 | subscriptions model = 11 | Events.onKeyDown (Decode.map Keydown keyDecoder) 12 | 13 | 14 | keyDecoder : Decode.Decoder String 15 | keyDecoder = 16 | Decode.field "key" Decode.string 17 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Counter/Update.elm: -------------------------------------------------------------------------------- 1 | module App.Counter.Update exposing (update) 2 | 3 | import App.Counter.Messages exposing (..) 4 | import App.Counter.Model exposing (..) 5 | 6 | 7 | update : Msg -> Model -> ( Model, Cmd Msg ) 8 | update msg model = 9 | case msg of 10 | Up -> 11 | ( model + 1, Cmd.none ) 12 | 13 | Down -> 14 | ( model - 1, Cmd.none ) 15 | 16 | Keydown code -> 17 | case code of 18 | "ArrowUp" -> 19 | update Up model 20 | 21 | "ArrowDown" -> 22 | update Down model 23 | 24 | _ -> 25 | ( model, Cmd.none ) 26 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Counter/View.elm: -------------------------------------------------------------------------------- 1 | module App.Counter.View exposing (view) 2 | 3 | import App.Counter.Messages exposing (..) 4 | import App.Counter.Model exposing (..) 5 | import Debug 6 | import Html exposing (Html, button, div, text) 7 | import Html.Events exposing (onClick) 8 | 9 | 10 | view : Model -> Html Msg 11 | view model = 12 | div 13 | [] 14 | [ button [ onClick Up ] [ text "+" ] 15 | , text (Debug.toString model) 16 | , button [ onClick Down ] [ text "-" ] 17 | ] 18 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Messages.elm: -------------------------------------------------------------------------------- 1 | module App.Messages exposing (Msg(..)) 2 | 3 | import App.Counter.Messages 4 | 5 | 6 | type Msg 7 | = NoOp 8 | | CounterMsg App.Counter.Messages.Msg 9 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Model.elm: -------------------------------------------------------------------------------- 1 | module App.Model exposing (Flags, Model, init) 2 | 3 | import App.Counter.Model 4 | import App.Messages exposing (Msg) 5 | 6 | 7 | type alias Model = 8 | { dev : Bool 9 | , counter : App.Counter.Model.Model 10 | } 11 | 12 | 13 | {-| We can use abstract type if it is constructed with Elm's primitive values. 14 | -} 15 | type alias Flags = 16 | { dev : Bool 17 | , counter : Int 18 | } 19 | 20 | 21 | init : Flags -> ( Model, Cmd Msg ) 22 | init flags = 23 | let 24 | { dev, counter } = 25 | flags 26 | in 27 | ( Model dev counter, Cmd.none ) 28 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Subscriptions.elm: -------------------------------------------------------------------------------- 1 | module App.Subscriptions exposing (subscriptions) 2 | 3 | import App.Counter.Subscriptions 4 | import App.Messages exposing (..) 5 | import App.Model exposing (Model) 6 | 7 | 8 | {-| This is how you can organize subscribtions from child modules. 9 | -} 10 | subscriptions : Model -> Sub Msg 11 | subscriptions model = 12 | let 13 | counterSub = 14 | App.Counter.Subscriptions.subscriptions model.counter 15 | in 16 | Sub.batch [ Sub.map CounterMsg counterSub ] 17 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/Update.elm: -------------------------------------------------------------------------------- 1 | module App.Update exposing (update) 2 | 3 | import App.Counter.Messages 4 | import App.Counter.Update 5 | import App.Messages exposing (..) 6 | import App.Model exposing (Model) 7 | import Utils exposing (log) 8 | 9 | 10 | update : Msg -> Model -> ( Model, Cmd Msg ) 11 | update msg model = 12 | let 13 | logMsg = 14 | log model.dev "MESSAGE: " 15 | in 16 | case logMsg msg of 17 | NoOp -> 18 | ( model, Cmd.none ) 19 | 20 | CounterMsg counterMsg -> 21 | let 22 | ( counterModel, counterCmd ) = 23 | App.Counter.Update.update counterMsg model.counter 24 | in 25 | ( { model | counter = counterModel } 26 | , Cmd.map CounterMsg counterCmd 27 | ) 28 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/App/View.elm: -------------------------------------------------------------------------------- 1 | module App.View exposing (view) 2 | 3 | import App.Counter.View 4 | import App.Messages exposing (..) 5 | import App.Model exposing (Model) 6 | import Html exposing (Html, div, text) 7 | 8 | 9 | view : Model -> Html Msg 10 | view model = 11 | div [] 12 | [ text "Try pressing up & down arrow keys on keyboard" 13 | , Html.map CounterMsg (App.Counter.View.view model.counter) 14 | ] 15 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import App.Messages exposing (Msg) 4 | import App.Model exposing (Flags, Model, init) 5 | import App.Subscriptions exposing (subscriptions) 6 | import App.Update exposing (update) 7 | import App.View exposing (view) 8 | import Browser 9 | 10 | 11 | main : Program Flags Model Msg 12 | main = 13 | Browser.element 14 | { init = init 15 | , update = update 16 | , view = view 17 | , subscriptions = subscriptions 18 | } 19 | -------------------------------------------------------------------------------- /examples/fractal-architecture/src/Utils.elm: -------------------------------------------------------------------------------- 1 | module Utils exposing (log) 2 | 3 | 4 | log : Bool -> String -> a -> a 5 | log dev label val = 6 | if dev == True then 7 | Debug.log label val 8 | 9 | else 10 | val 11 | -------------------------------------------------------------------------------- /examples/generic-update/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Checkbox, Model, Msg(..), init, main, update, view) 2 | 3 | import Browser 4 | import Dict exposing (Dict) 5 | import Html exposing (Html, div, input, label, text) 6 | import Html.Attributes exposing (checked, type_) 7 | import Html.Events exposing (onCheck) 8 | 9 | 10 | main : Program () Model Msg 11 | main = 12 | Browser.sandbox { init = init, view = view, update = update } 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Checkbox = 20 | { name : String 21 | , checked : Bool 22 | } 23 | 24 | 25 | type alias Model = 26 | { name : String 27 | , checkboxes : Dict String Checkbox 28 | } 29 | 30 | 31 | init : Model 32 | init = 33 | { name = "" 34 | , checkboxes = 35 | -- We store the the state for modules in a Dictionary 36 | Dict.fromList 37 | [ ( "advertising" 38 | , { name = "Advertising" 39 | , checked = False 40 | } 41 | ) 42 | , ( "travel" 43 | , { name = "Travel" 44 | , checked = False 45 | } 46 | ) 47 | , ( "utilities" 48 | , { name = "Utilities" 49 | , checked = False 50 | } 51 | ) 52 | ] 53 | } 54 | 55 | 56 | 57 | -- UPDATE 58 | 59 | 60 | type Msg 61 | = Check String Bool 62 | 63 | 64 | update msg model = 65 | case msg of 66 | Check checkboxId checked -> 67 | let 68 | updateRecord = 69 | Maybe.map (\checkboxData -> { checkboxData | checked = checked }) 70 | 71 | {- Update a single value inside of a dictionary, 72 | using updateRecord function. 73 | 74 | Since we don't know if value with a key checkboxId 75 | is present in the Dictionary, 76 | the updateRecord function is applied to a Maybe value. 77 | -} 78 | checkboxesUpdated = 79 | Dict.update checkboxId 80 | updateRecord 81 | model.checkboxes 82 | in 83 | { model | checkboxes = checkboxesUpdated } 84 | 85 | 86 | 87 | -- VIEW 88 | 89 | 90 | view : Model -> Html Msg 91 | view model = 92 | let 93 | checkbox ( key, data ) = 94 | label [] 95 | [ text data.name 96 | , input 97 | [ type_ "checkbox" 98 | , checked data.checked 99 | 100 | -- Pass the key for accesing the state as a Message payload. 101 | , onCheck (Check key) 102 | ] 103 | [] 104 | ] 105 | in 106 | div [] 107 | (model.checkboxes 108 | |> Dict.toList 109 | |> List.map checkbox 110 | ) 111 | -------------------------------------------------------------------------------- /examples/generic-update/README.md: -------------------------------------------------------------------------------- 1 | # Generic update function 2 | 3 | This example shows, how `update` function of any module might be simplified by using Dictionaries instead of Records. 4 | 5 | This approach is useful, when having many instances of child modules in application. 6 | 7 | ## Building the example 8 | 9 | ```sh 10 | $ elm make Main.elm 11 | ``` 12 | -------------------------------------------------------------------------------- /examples/generic-update/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0" 12 | }, 13 | "indirect": { 14 | "elm/json": "1.0.0", 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/http-get/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Model, Msg(..), Repo, decoder, getRepos, init, main, repoDecoder, sendGet, subscriptions, update, url, view) 2 | 3 | import Browser 4 | import Debug 5 | import Html exposing (Html, button, div, input, p, text) 6 | import Html.Attributes exposing (value) 7 | import Html.Events exposing (onClick, onInput) 8 | import Http exposing (Error(..), Response, get) 9 | import Json.Decode exposing (Decoder, field, int, string) 10 | import Task 11 | import Url.Builder as Url 12 | 13 | 14 | main : Program () Model Msg 15 | main = 16 | Browser.element 17 | { view = view 18 | , init = \() -> init 19 | , update = update 20 | , subscriptions = subscriptions 21 | } 22 | 23 | 24 | subscriptions : Model -> Sub Msg 25 | subscriptions model = 26 | Sub.none 27 | 28 | 29 | type alias Repo = 30 | { id : Int 31 | , full_name : String 32 | } 33 | 34 | 35 | type alias Model = 36 | { query : String 37 | , repos : List Repo 38 | , error : Maybe Error 39 | } 40 | 41 | 42 | init : ( Model, Cmd Msg ) 43 | init = 44 | ( Model "evancz" [] Nothing, Cmd.none ) 45 | 46 | 47 | decoder : Decoder (List Repo) 48 | decoder = 49 | Json.Decode.list repoDecoder 50 | 51 | 52 | repoDecoder : Decoder Repo 53 | repoDecoder = 54 | Json.Decode.map2 Repo 55 | (field "id" int) 56 | (field "full_name" string) 57 | 58 | 59 | url : String -> String 60 | url query = 61 | Url.crossOrigin "https://api.github.com" [ "users", query, "repos" ] [] 62 | 63 | 64 | getRepos : String -> Cmd Msg 65 | getRepos query = 66 | sendGet LoadRepos (url query) decoder 67 | 68 | 69 | type Msg 70 | = UpdateQuery String 71 | | Search 72 | | LoadRepos (Result Http.Error (List Repo)) 73 | 74 | 75 | update : Msg -> Model -> ( Model, Cmd Msg ) 76 | update msg model = 77 | case msg of 78 | UpdateQuery value -> 79 | ( { model | query = value }, Cmd.none ) 80 | 81 | Search -> 82 | ( model, getRepos model.query ) 83 | 84 | LoadRepos maybeRepos -> 85 | case maybeRepos of 86 | Ok repos -> 87 | ( { model | repos = repos }, Cmd.none ) 88 | 89 | Err err -> 90 | ( { model | repos = [], error = Just err }, Cmd.none ) 91 | 92 | 93 | sendGet : (Result Error a -> msg) -> String -> Decoder a -> Cmd msg 94 | sendGet msg theUrl theDecoder = 95 | Http.get theUrl theDecoder 96 | |> Http.send msg 97 | 98 | 99 | view : Model -> Html Msg 100 | view model = 101 | div [] 102 | [ input 103 | [ onInput UpdateQuery, value model.query ] 104 | [] 105 | , button [ onClick Search ] [ text "Search" ] 106 | , div 107 | [] 108 | (List.map (\{ full_name } -> p [] [ text full_name ]) model.repos) 109 | , text 110 | (case model.error of 111 | Nothing -> 112 | "" 113 | 114 | Just error -> 115 | "Error: " ++ Debug.toString error 116 | ) 117 | ] 118 | -------------------------------------------------------------------------------- /examples/http-get/README.md: -------------------------------------------------------------------------------- 1 | # HTTP GET with Elm 2 | 3 | Small example app, which uses public GitHub API 4 | to [List user repositories](https://developer.github.com/v3/repos/#list-user-repositories) by username. 5 | 6 | ## Building the example 7 | 8 | ```sh 9 | $ elm make Main.elm 10 | 11 | or alternatively 12 | 13 | $ elm reactor 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/http-get/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/http": "1.0.0", 13 | "elm/json": "1.0.0", 14 | "elm/url": "1.0.0" 15 | }, 16 | "indirect": { 17 | "elm/time": "1.0.0", 18 | "elm/virtual-dom": "1.0.0" 19 | } 20 | }, 21 | "test-dependencies": { 22 | "direct": {}, 23 | "indirect": {} 24 | } 25 | } -------------------------------------------------------------------------------- /examples/http-json-server/README.md: -------------------------------------------------------------------------------- 1 | # Http with json-server 2 | 3 | ## Running locally 4 | 5 | ```bash 6 | npm i 7 | npm run serve-json 8 | elm-app start 9 | ``` 10 | 11 | This project is bootstrapped with [Create Elm App.](https://github.com/halfzebra/create-elm-app) -------------------------------------------------------------------------------- /examples/http-json-server/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "content": "Hello!" 4 | } 5 | } -------------------------------------------------------------------------------- /examples/http-json-server/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | ".", 5 | "src/" 6 | ], 7 | "elm-version": "0.19.0", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.0", 11 | "elm/core": "1.0.0", 12 | "elm/html": "1.0.0", 13 | "elm/http": "1.0.0", 14 | "elm/json": "1.0.0" 15 | }, 16 | "indirect": { 17 | "elm/time": "1.0.0", 18 | "elm/url": "1.0.0", 19 | "elm/virtual-dom": "1.0.0" 20 | } 21 | }, 22 | "test-dependencies": { 23 | "direct": {}, 24 | "indirect": {} 25 | } 26 | } -------------------------------------------------------------------------------- /examples/http-json-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-json-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "ajv": { 17 | "version": "5.5.2", 18 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 19 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 20 | "requires": { 21 | "co": "^4.6.0", 22 | "fast-deep-equal": "^1.0.0", 23 | "fast-json-stable-stringify": "^2.0.0", 24 | "json-schema-traverse": "^0.3.0" 25 | } 26 | }, 27 | "ansi-align": { 28 | "version": "2.0.0", 29 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", 30 | "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", 31 | "requires": { 32 | "string-width": "^2.0.0" 33 | } 34 | }, 35 | "ansi-regex": { 36 | "version": "3.0.0", 37 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 38 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" 39 | }, 40 | "ansi-styles": { 41 | "version": "3.2.1", 42 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 43 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 44 | "requires": { 45 | "color-convert": "^1.9.0" 46 | } 47 | }, 48 | "array-flatten": { 49 | "version": "1.1.1", 50 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 51 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 52 | }, 53 | "asn1": { 54 | "version": "0.2.4", 55 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 56 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 57 | "requires": { 58 | "safer-buffer": "~2.1.0" 59 | } 60 | }, 61 | "assert-plus": { 62 | "version": "1.0.0", 63 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 64 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 65 | }, 66 | "asynckit": { 67 | "version": "0.4.0", 68 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 69 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 70 | }, 71 | "aws-sign2": { 72 | "version": "0.7.0", 73 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 74 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 75 | }, 76 | "aws4": { 77 | "version": "1.8.0", 78 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 79 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 80 | }, 81 | "basic-auth": { 82 | "version": "2.0.0", 83 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", 84 | "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", 85 | "requires": { 86 | "safe-buffer": "5.1.1" 87 | }, 88 | "dependencies": { 89 | "safe-buffer": { 90 | "version": "5.1.1", 91 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 92 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 93 | } 94 | } 95 | }, 96 | "bcrypt-pbkdf": { 97 | "version": "1.0.2", 98 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 99 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 100 | "optional": true, 101 | "requires": { 102 | "tweetnacl": "^0.14.3" 103 | } 104 | }, 105 | "body-parser": { 106 | "version": "1.18.3", 107 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 108 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 109 | "requires": { 110 | "bytes": "3.0.0", 111 | "content-type": "~1.0.4", 112 | "debug": "2.6.9", 113 | "depd": "~1.1.2", 114 | "http-errors": "~1.6.3", 115 | "iconv-lite": "0.4.23", 116 | "on-finished": "~2.3.0", 117 | "qs": "6.5.2", 118 | "raw-body": "2.3.3", 119 | "type-is": "~1.6.16" 120 | } 121 | }, 122 | "boxen": { 123 | "version": "1.3.0", 124 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", 125 | "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", 126 | "requires": { 127 | "ansi-align": "^2.0.0", 128 | "camelcase": "^4.0.0", 129 | "chalk": "^2.0.1", 130 | "cli-boxes": "^1.0.0", 131 | "string-width": "^2.0.0", 132 | "term-size": "^1.2.0", 133 | "widest-line": "^2.0.0" 134 | } 135 | }, 136 | "bytes": { 137 | "version": "3.0.0", 138 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 139 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 140 | }, 141 | "camelcase": { 142 | "version": "4.1.0", 143 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", 144 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" 145 | }, 146 | "capture-stack-trace": { 147 | "version": "1.0.1", 148 | "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", 149 | "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" 150 | }, 151 | "caseless": { 152 | "version": "0.12.0", 153 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 154 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 155 | }, 156 | "chalk": { 157 | "version": "2.4.1", 158 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 159 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 160 | "requires": { 161 | "ansi-styles": "^3.2.1", 162 | "escape-string-regexp": "^1.0.5", 163 | "supports-color": "^5.3.0" 164 | } 165 | }, 166 | "ci-info": { 167 | "version": "1.5.1", 168 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.5.1.tgz", 169 | "integrity": "sha512-fKFIKXaYiL1exImwJ0AhR/6jxFPSKQBk2ayV5NiNoruUs2+rxC2kNw0EG+1Z9dugZRdCrppskQ8DN2cyaUM1Hw==" 170 | }, 171 | "cli-boxes": { 172 | "version": "1.0.0", 173 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", 174 | "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" 175 | }, 176 | "cliui": { 177 | "version": "4.1.0", 178 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", 179 | "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", 180 | "requires": { 181 | "string-width": "^2.1.1", 182 | "strip-ansi": "^4.0.0", 183 | "wrap-ansi": "^2.0.0" 184 | } 185 | }, 186 | "co": { 187 | "version": "4.6.0", 188 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 189 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 190 | }, 191 | "code-point-at": { 192 | "version": "1.1.0", 193 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 194 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 195 | }, 196 | "color-convert": { 197 | "version": "1.9.3", 198 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 199 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 200 | "requires": { 201 | "color-name": "1.1.3" 202 | } 203 | }, 204 | "color-name": { 205 | "version": "1.1.3", 206 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 207 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 208 | }, 209 | "combined-stream": { 210 | "version": "1.0.7", 211 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 212 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 213 | "requires": { 214 | "delayed-stream": "~1.0.0" 215 | } 216 | }, 217 | "compressible": { 218 | "version": "2.0.15", 219 | "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz", 220 | "integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==", 221 | "requires": { 222 | "mime-db": ">= 1.36.0 < 2" 223 | } 224 | }, 225 | "compression": { 226 | "version": "1.7.3", 227 | "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", 228 | "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", 229 | "requires": { 230 | "accepts": "~1.3.5", 231 | "bytes": "3.0.0", 232 | "compressible": "~2.0.14", 233 | "debug": "2.6.9", 234 | "on-headers": "~1.0.1", 235 | "safe-buffer": "5.1.2", 236 | "vary": "~1.1.2" 237 | } 238 | }, 239 | "configstore": { 240 | "version": "3.1.2", 241 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", 242 | "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", 243 | "requires": { 244 | "dot-prop": "^4.1.0", 245 | "graceful-fs": "^4.1.2", 246 | "make-dir": "^1.0.0", 247 | "unique-string": "^1.0.0", 248 | "write-file-atomic": "^2.0.0", 249 | "xdg-basedir": "^3.0.0" 250 | } 251 | }, 252 | "connect-pause": { 253 | "version": "0.1.1", 254 | "resolved": "https://registry.npmjs.org/connect-pause/-/connect-pause-0.1.1.tgz", 255 | "integrity": "sha1-smmyu4Ldsaw9tQmcD7WCq6mfs3o=" 256 | }, 257 | "content-disposition": { 258 | "version": "0.5.2", 259 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 260 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 261 | }, 262 | "content-type": { 263 | "version": "1.0.4", 264 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 265 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 266 | }, 267 | "cookie": { 268 | "version": "0.3.1", 269 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 270 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 271 | }, 272 | "cookie-signature": { 273 | "version": "1.0.6", 274 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 275 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 276 | }, 277 | "core-util-is": { 278 | "version": "1.0.2", 279 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 280 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 281 | }, 282 | "cors": { 283 | "version": "2.8.4", 284 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", 285 | "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", 286 | "requires": { 287 | "object-assign": "^4", 288 | "vary": "^1" 289 | } 290 | }, 291 | "create-error-class": { 292 | "version": "3.0.2", 293 | "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", 294 | "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", 295 | "requires": { 296 | "capture-stack-trace": "^1.0.0" 297 | } 298 | }, 299 | "cross-spawn": { 300 | "version": "5.1.0", 301 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 302 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 303 | "requires": { 304 | "lru-cache": "^4.0.1", 305 | "shebang-command": "^1.2.0", 306 | "which": "^1.2.9" 307 | } 308 | }, 309 | "crypto-random-string": { 310 | "version": "1.0.0", 311 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", 312 | "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" 313 | }, 314 | "dashdash": { 315 | "version": "1.14.1", 316 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 317 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 318 | "requires": { 319 | "assert-plus": "^1.0.0" 320 | } 321 | }, 322 | "debug": { 323 | "version": "2.6.9", 324 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 325 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 326 | "requires": { 327 | "ms": "2.0.0" 328 | } 329 | }, 330 | "decamelize": { 331 | "version": "1.2.0", 332 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 333 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 334 | }, 335 | "deep-extend": { 336 | "version": "0.6.0", 337 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 338 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 339 | }, 340 | "delayed-stream": { 341 | "version": "1.0.0", 342 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 343 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 344 | }, 345 | "depd": { 346 | "version": "1.1.2", 347 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 348 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 349 | }, 350 | "destroy": { 351 | "version": "1.0.4", 352 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 353 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 354 | }, 355 | "dot-prop": { 356 | "version": "4.2.0", 357 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", 358 | "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", 359 | "requires": { 360 | "is-obj": "^1.0.0" 361 | } 362 | }, 363 | "duplexer3": { 364 | "version": "0.1.4", 365 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 366 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" 367 | }, 368 | "ecc-jsbn": { 369 | "version": "0.1.2", 370 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 371 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 372 | "optional": true, 373 | "requires": { 374 | "jsbn": "~0.1.0", 375 | "safer-buffer": "^2.1.0" 376 | } 377 | }, 378 | "ee-first": { 379 | "version": "1.1.1", 380 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 381 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 382 | }, 383 | "encodeurl": { 384 | "version": "1.0.2", 385 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 386 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 387 | }, 388 | "errorhandler": { 389 | "version": "1.5.0", 390 | "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.0.tgz", 391 | "integrity": "sha1-6rpkyl1UKjEayUX1gt78M2Fl2fQ=", 392 | "requires": { 393 | "accepts": "~1.3.3", 394 | "escape-html": "~1.0.3" 395 | } 396 | }, 397 | "escape-html": { 398 | "version": "1.0.3", 399 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 400 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 401 | }, 402 | "escape-string-regexp": { 403 | "version": "1.0.5", 404 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 405 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 406 | }, 407 | "etag": { 408 | "version": "1.8.1", 409 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 410 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 411 | }, 412 | "execa": { 413 | "version": "0.7.0", 414 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", 415 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", 416 | "requires": { 417 | "cross-spawn": "^5.0.1", 418 | "get-stream": "^3.0.0", 419 | "is-stream": "^1.1.0", 420 | "npm-run-path": "^2.0.0", 421 | "p-finally": "^1.0.0", 422 | "signal-exit": "^3.0.0", 423 | "strip-eof": "^1.0.0" 424 | } 425 | }, 426 | "express": { 427 | "version": "4.16.3", 428 | "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", 429 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 430 | "requires": { 431 | "accepts": "~1.3.5", 432 | "array-flatten": "1.1.1", 433 | "body-parser": "1.18.2", 434 | "content-disposition": "0.5.2", 435 | "content-type": "~1.0.4", 436 | "cookie": "0.3.1", 437 | "cookie-signature": "1.0.6", 438 | "debug": "2.6.9", 439 | "depd": "~1.1.2", 440 | "encodeurl": "~1.0.2", 441 | "escape-html": "~1.0.3", 442 | "etag": "~1.8.1", 443 | "finalhandler": "1.1.1", 444 | "fresh": "0.5.2", 445 | "merge-descriptors": "1.0.1", 446 | "methods": "~1.1.2", 447 | "on-finished": "~2.3.0", 448 | "parseurl": "~1.3.2", 449 | "path-to-regexp": "0.1.7", 450 | "proxy-addr": "~2.0.3", 451 | "qs": "6.5.1", 452 | "range-parser": "~1.2.0", 453 | "safe-buffer": "5.1.1", 454 | "send": "0.16.2", 455 | "serve-static": "1.13.2", 456 | "setprototypeof": "1.1.0", 457 | "statuses": "~1.4.0", 458 | "type-is": "~1.6.16", 459 | "utils-merge": "1.0.1", 460 | "vary": "~1.1.2" 461 | }, 462 | "dependencies": { 463 | "body-parser": { 464 | "version": "1.18.2", 465 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 466 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 467 | "requires": { 468 | "bytes": "3.0.0", 469 | "content-type": "~1.0.4", 470 | "debug": "2.6.9", 471 | "depd": "~1.1.1", 472 | "http-errors": "~1.6.2", 473 | "iconv-lite": "0.4.19", 474 | "on-finished": "~2.3.0", 475 | "qs": "6.5.1", 476 | "raw-body": "2.3.2", 477 | "type-is": "~1.6.15" 478 | } 479 | }, 480 | "iconv-lite": { 481 | "version": "0.4.19", 482 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 483 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 484 | }, 485 | "qs": { 486 | "version": "6.5.1", 487 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 488 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 489 | }, 490 | "raw-body": { 491 | "version": "2.3.2", 492 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 493 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 494 | "requires": { 495 | "bytes": "3.0.0", 496 | "http-errors": "1.6.2", 497 | "iconv-lite": "0.4.19", 498 | "unpipe": "1.0.0" 499 | }, 500 | "dependencies": { 501 | "depd": { 502 | "version": "1.1.1", 503 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 504 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 505 | }, 506 | "http-errors": { 507 | "version": "1.6.2", 508 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 509 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 510 | "requires": { 511 | "depd": "1.1.1", 512 | "inherits": "2.0.3", 513 | "setprototypeof": "1.0.3", 514 | "statuses": ">= 1.3.1 < 2" 515 | } 516 | }, 517 | "setprototypeof": { 518 | "version": "1.0.3", 519 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 520 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 521 | } 522 | } 523 | }, 524 | "safe-buffer": { 525 | "version": "5.1.1", 526 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 527 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 528 | }, 529 | "statuses": { 530 | "version": "1.4.0", 531 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 532 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 533 | } 534 | } 535 | }, 536 | "express-urlrewrite": { 537 | "version": "1.2.0", 538 | "resolved": "https://registry.npmjs.org/express-urlrewrite/-/express-urlrewrite-1.2.0.tgz", 539 | "integrity": "sha1-jmZ7d2H/HH/9sO+gXWQDU4fII+s=", 540 | "requires": { 541 | "debug": "*", 542 | "path-to-regexp": "^1.0.3" 543 | }, 544 | "dependencies": { 545 | "path-to-regexp": { 546 | "version": "1.7.0", 547 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", 548 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 549 | "requires": { 550 | "isarray": "0.0.1" 551 | } 552 | } 553 | } 554 | }, 555 | "extend": { 556 | "version": "3.0.2", 557 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 558 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 559 | }, 560 | "extsprintf": { 561 | "version": "1.3.0", 562 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 563 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 564 | }, 565 | "fast-deep-equal": { 566 | "version": "1.1.0", 567 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", 568 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" 569 | }, 570 | "fast-json-stable-stringify": { 571 | "version": "2.0.0", 572 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 573 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 574 | }, 575 | "finalhandler": { 576 | "version": "1.1.1", 577 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 578 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 579 | "requires": { 580 | "debug": "2.6.9", 581 | "encodeurl": "~1.0.2", 582 | "escape-html": "~1.0.3", 583 | "on-finished": "~2.3.0", 584 | "parseurl": "~1.3.2", 585 | "statuses": "~1.4.0", 586 | "unpipe": "~1.0.0" 587 | }, 588 | "dependencies": { 589 | "statuses": { 590 | "version": "1.4.0", 591 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 592 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 593 | } 594 | } 595 | }, 596 | "find-up": { 597 | "version": "2.1.0", 598 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 599 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 600 | "requires": { 601 | "locate-path": "^2.0.0" 602 | } 603 | }, 604 | "forever-agent": { 605 | "version": "0.6.1", 606 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 607 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 608 | }, 609 | "form-data": { 610 | "version": "2.3.2", 611 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", 612 | "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", 613 | "requires": { 614 | "asynckit": "^0.4.0", 615 | "combined-stream": "1.0.6", 616 | "mime-types": "^2.1.12" 617 | }, 618 | "dependencies": { 619 | "combined-stream": { 620 | "version": "1.0.6", 621 | "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", 622 | "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", 623 | "requires": { 624 | "delayed-stream": "~1.0.0" 625 | } 626 | } 627 | } 628 | }, 629 | "forwarded": { 630 | "version": "0.1.2", 631 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 632 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 633 | }, 634 | "fresh": { 635 | "version": "0.5.2", 636 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 637 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 638 | }, 639 | "get-caller-file": { 640 | "version": "1.0.3", 641 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 642 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" 643 | }, 644 | "get-stream": { 645 | "version": "3.0.0", 646 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 647 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" 648 | }, 649 | "getpass": { 650 | "version": "0.1.7", 651 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 652 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 653 | "requires": { 654 | "assert-plus": "^1.0.0" 655 | } 656 | }, 657 | "global-dirs": { 658 | "version": "0.1.1", 659 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", 660 | "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", 661 | "requires": { 662 | "ini": "^1.3.4" 663 | } 664 | }, 665 | "got": { 666 | "version": "6.7.1", 667 | "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", 668 | "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", 669 | "requires": { 670 | "create-error-class": "^3.0.0", 671 | "duplexer3": "^0.1.4", 672 | "get-stream": "^3.0.0", 673 | "is-redirect": "^1.0.0", 674 | "is-retry-allowed": "^1.0.0", 675 | "is-stream": "^1.0.0", 676 | "lowercase-keys": "^1.0.0", 677 | "safe-buffer": "^5.0.1", 678 | "timed-out": "^4.0.0", 679 | "unzip-response": "^2.0.1", 680 | "url-parse-lax": "^1.0.0" 681 | } 682 | }, 683 | "graceful-fs": { 684 | "version": "4.1.11", 685 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 686 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 687 | }, 688 | "har-schema": { 689 | "version": "2.0.0", 690 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 691 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 692 | }, 693 | "har-validator": { 694 | "version": "5.1.0", 695 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", 696 | "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", 697 | "requires": { 698 | "ajv": "^5.3.0", 699 | "har-schema": "^2.0.0" 700 | } 701 | }, 702 | "has-flag": { 703 | "version": "3.0.0", 704 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 705 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 706 | }, 707 | "http-errors": { 708 | "version": "1.6.3", 709 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 710 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 711 | "requires": { 712 | "depd": "~1.1.2", 713 | "inherits": "2.0.3", 714 | "setprototypeof": "1.1.0", 715 | "statuses": ">= 1.4.0 < 2" 716 | } 717 | }, 718 | "http-signature": { 719 | "version": "1.2.0", 720 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 721 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 722 | "requires": { 723 | "assert-plus": "^1.0.0", 724 | "jsprim": "^1.2.2", 725 | "sshpk": "^1.7.0" 726 | } 727 | }, 728 | "iconv-lite": { 729 | "version": "0.4.23", 730 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 731 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 732 | "requires": { 733 | "safer-buffer": ">= 2.1.2 < 3" 734 | } 735 | }, 736 | "import-lazy": { 737 | "version": "2.1.0", 738 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", 739 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" 740 | }, 741 | "imurmurhash": { 742 | "version": "0.1.4", 743 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 744 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" 745 | }, 746 | "inherits": { 747 | "version": "2.0.3", 748 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 749 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 750 | }, 751 | "ini": { 752 | "version": "1.3.5", 753 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 754 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" 755 | }, 756 | "invert-kv": { 757 | "version": "1.0.0", 758 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 759 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" 760 | }, 761 | "ipaddr.js": { 762 | "version": "1.8.0", 763 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 764 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 765 | }, 766 | "is-ci": { 767 | "version": "1.2.1", 768 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", 769 | "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", 770 | "requires": { 771 | "ci-info": "^1.5.0" 772 | } 773 | }, 774 | "is-fullwidth-code-point": { 775 | "version": "2.0.0", 776 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 777 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" 778 | }, 779 | "is-installed-globally": { 780 | "version": "0.1.0", 781 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", 782 | "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", 783 | "requires": { 784 | "global-dirs": "^0.1.0", 785 | "is-path-inside": "^1.0.0" 786 | } 787 | }, 788 | "is-npm": { 789 | "version": "1.0.0", 790 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", 791 | "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" 792 | }, 793 | "is-obj": { 794 | "version": "1.0.1", 795 | "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 796 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" 797 | }, 798 | "is-path-inside": { 799 | "version": "1.0.1", 800 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 801 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 802 | "requires": { 803 | "path-is-inside": "^1.0.1" 804 | } 805 | }, 806 | "is-promise": { 807 | "version": "2.1.0", 808 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 809 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" 810 | }, 811 | "is-redirect": { 812 | "version": "1.0.0", 813 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", 814 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" 815 | }, 816 | "is-retry-allowed": { 817 | "version": "1.1.0", 818 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", 819 | "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" 820 | }, 821 | "is-stream": { 822 | "version": "1.1.0", 823 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 824 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 825 | }, 826 | "is-typedarray": { 827 | "version": "1.0.0", 828 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 829 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 830 | }, 831 | "isarray": { 832 | "version": "0.0.1", 833 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 834 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 835 | }, 836 | "isexe": { 837 | "version": "2.0.0", 838 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 839 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 840 | }, 841 | "isstream": { 842 | "version": "0.1.2", 843 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 844 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 845 | }, 846 | "jju": { 847 | "version": "1.4.0", 848 | "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", 849 | "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=" 850 | }, 851 | "jsbn": { 852 | "version": "0.1.1", 853 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 854 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 855 | "optional": true 856 | }, 857 | "json-parse-helpfulerror": { 858 | "version": "1.0.3", 859 | "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", 860 | "integrity": "sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w=", 861 | "requires": { 862 | "jju": "^1.1.0" 863 | } 864 | }, 865 | "json-schema": { 866 | "version": "0.2.3", 867 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 868 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 869 | }, 870 | "json-schema-traverse": { 871 | "version": "0.3.1", 872 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 873 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" 874 | }, 875 | "json-server": { 876 | "version": "0.14.0", 877 | "resolved": "https://registry.npmjs.org/json-server/-/json-server-0.14.0.tgz", 878 | "integrity": "sha512-8RVRAb1TO6LlCny6+8GC+sXDsESYv7gv7fSLdVANklVt866I416/7Z5fdqrtzSru92nyreddgavbEk8pjqcWoA==", 879 | "requires": { 880 | "body-parser": "^1.18.3", 881 | "chalk": "^2.4.1", 882 | "compression": "^1.7.2", 883 | "connect-pause": "^0.1.1", 884 | "cors": "^2.8.4", 885 | "errorhandler": "^1.2.0", 886 | "express": "^4.16.3", 887 | "express-urlrewrite": "^1.2.0", 888 | "json-parse-helpfulerror": "^1.0.3", 889 | "lodash": "^4.17.10", 890 | "lodash-id": "^0.14.0", 891 | "lowdb": "^0.15.0", 892 | "method-override": "^2.3.10", 893 | "morgan": "^1.9.0", 894 | "nanoid": "^1.0.2", 895 | "object-assign": "^4.0.1", 896 | "please-upgrade-node": "^3.0.2", 897 | "pluralize": "^7.0.0", 898 | "request": "^2.87.0", 899 | "server-destroy": "^1.0.1", 900 | "update-notifier": "^2.5.0", 901 | "yargs": "^10.1.2" 902 | } 903 | }, 904 | "json-stringify-safe": { 905 | "version": "5.0.1", 906 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 907 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 908 | }, 909 | "jsprim": { 910 | "version": "1.4.1", 911 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 912 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 913 | "requires": { 914 | "assert-plus": "1.0.0", 915 | "extsprintf": "1.3.0", 916 | "json-schema": "0.2.3", 917 | "verror": "1.10.0" 918 | } 919 | }, 920 | "latest-version": { 921 | "version": "3.1.0", 922 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", 923 | "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", 924 | "requires": { 925 | "package-json": "^4.0.0" 926 | } 927 | }, 928 | "lcid": { 929 | "version": "1.0.0", 930 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 931 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 932 | "requires": { 933 | "invert-kv": "^1.0.0" 934 | } 935 | }, 936 | "locate-path": { 937 | "version": "2.0.0", 938 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 939 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 940 | "requires": { 941 | "p-locate": "^2.0.0", 942 | "path-exists": "^3.0.0" 943 | } 944 | }, 945 | "lodash": { 946 | "version": "4.17.11", 947 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 948 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 949 | }, 950 | "lodash-id": { 951 | "version": "0.14.0", 952 | "resolved": "https://registry.npmjs.org/lodash-id/-/lodash-id-0.14.0.tgz", 953 | "integrity": "sha1-uvSJNOVDobXWNG+MhGmLGoyAOJY=" 954 | }, 955 | "lowdb": { 956 | "version": "0.15.5", 957 | "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-0.15.5.tgz", 958 | "integrity": "sha1-mt4QXfiqVzaS0SIWIrhUFPv0+pY=", 959 | "requires": { 960 | "graceful-fs": "^4.1.3", 961 | "is-promise": "^2.1.0", 962 | "json-parse-helpfulerror": "^1.0.3", 963 | "lodash": "4", 964 | "steno": "^0.4.1" 965 | } 966 | }, 967 | "lowercase-keys": { 968 | "version": "1.0.1", 969 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 970 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" 971 | }, 972 | "lru-cache": { 973 | "version": "4.1.3", 974 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", 975 | "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", 976 | "requires": { 977 | "pseudomap": "^1.0.2", 978 | "yallist": "^2.1.2" 979 | } 980 | }, 981 | "make-dir": { 982 | "version": "1.3.0", 983 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", 984 | "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", 985 | "requires": { 986 | "pify": "^3.0.0" 987 | } 988 | }, 989 | "media-typer": { 990 | "version": "0.3.0", 991 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 992 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 993 | }, 994 | "mem": { 995 | "version": "1.1.0", 996 | "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", 997 | "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", 998 | "requires": { 999 | "mimic-fn": "^1.0.0" 1000 | } 1001 | }, 1002 | "merge-descriptors": { 1003 | "version": "1.0.1", 1004 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1005 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 1006 | }, 1007 | "method-override": { 1008 | "version": "2.3.10", 1009 | "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz", 1010 | "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=", 1011 | "requires": { 1012 | "debug": "2.6.9", 1013 | "methods": "~1.1.2", 1014 | "parseurl": "~1.3.2", 1015 | "vary": "~1.1.2" 1016 | } 1017 | }, 1018 | "methods": { 1019 | "version": "1.1.2", 1020 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1021 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1022 | }, 1023 | "mime": { 1024 | "version": "1.4.1", 1025 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 1026 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 1027 | }, 1028 | "mime-db": { 1029 | "version": "1.36.0", 1030 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", 1031 | "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" 1032 | }, 1033 | "mime-types": { 1034 | "version": "2.1.20", 1035 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", 1036 | "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", 1037 | "requires": { 1038 | "mime-db": "~1.36.0" 1039 | } 1040 | }, 1041 | "mimic-fn": { 1042 | "version": "1.2.0", 1043 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 1044 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" 1045 | }, 1046 | "minimist": { 1047 | "version": "1.2.0", 1048 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1049 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 1050 | }, 1051 | "morgan": { 1052 | "version": "1.9.1", 1053 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 1054 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", 1055 | "requires": { 1056 | "basic-auth": "~2.0.0", 1057 | "debug": "2.6.9", 1058 | "depd": "~1.1.2", 1059 | "on-finished": "~2.3.0", 1060 | "on-headers": "~1.0.1" 1061 | } 1062 | }, 1063 | "ms": { 1064 | "version": "2.0.0", 1065 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1066 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1067 | }, 1068 | "nanoid": { 1069 | "version": "1.2.3", 1070 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.2.3.tgz", 1071 | "integrity": "sha512-BAnxAdaihzMoszwhqRy8FPOX+dijs7esUEUYTIQ1KsOSKmCVNYnitAMmBDFxYzA6VQYvuUKw7o2K1AcMBTGzIg==" 1072 | }, 1073 | "negotiator": { 1074 | "version": "0.6.1", 1075 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 1076 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 1077 | }, 1078 | "npm-run-path": { 1079 | "version": "2.0.2", 1080 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 1081 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 1082 | "requires": { 1083 | "path-key": "^2.0.0" 1084 | } 1085 | }, 1086 | "number-is-nan": { 1087 | "version": "1.0.1", 1088 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1089 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 1090 | }, 1091 | "oauth-sign": { 1092 | "version": "0.9.0", 1093 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 1094 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 1095 | }, 1096 | "object-assign": { 1097 | "version": "4.1.1", 1098 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1099 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 1100 | }, 1101 | "on-finished": { 1102 | "version": "2.3.0", 1103 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1104 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1105 | "requires": { 1106 | "ee-first": "1.1.1" 1107 | } 1108 | }, 1109 | "on-headers": { 1110 | "version": "1.0.1", 1111 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", 1112 | "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" 1113 | }, 1114 | "os-locale": { 1115 | "version": "2.1.0", 1116 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", 1117 | "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", 1118 | "requires": { 1119 | "execa": "^0.7.0", 1120 | "lcid": "^1.0.0", 1121 | "mem": "^1.1.0" 1122 | } 1123 | }, 1124 | "p-finally": { 1125 | "version": "1.0.0", 1126 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 1127 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" 1128 | }, 1129 | "p-limit": { 1130 | "version": "1.3.0", 1131 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 1132 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 1133 | "requires": { 1134 | "p-try": "^1.0.0" 1135 | } 1136 | }, 1137 | "p-locate": { 1138 | "version": "2.0.0", 1139 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 1140 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 1141 | "requires": { 1142 | "p-limit": "^1.1.0" 1143 | } 1144 | }, 1145 | "p-try": { 1146 | "version": "1.0.0", 1147 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 1148 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" 1149 | }, 1150 | "package-json": { 1151 | "version": "4.0.1", 1152 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", 1153 | "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", 1154 | "requires": { 1155 | "got": "^6.7.1", 1156 | "registry-auth-token": "^3.0.1", 1157 | "registry-url": "^3.0.3", 1158 | "semver": "^5.1.0" 1159 | } 1160 | }, 1161 | "parseurl": { 1162 | "version": "1.3.2", 1163 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 1164 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 1165 | }, 1166 | "path-exists": { 1167 | "version": "3.0.0", 1168 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1169 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" 1170 | }, 1171 | "path-is-inside": { 1172 | "version": "1.0.2", 1173 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1174 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" 1175 | }, 1176 | "path-key": { 1177 | "version": "2.0.1", 1178 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1179 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" 1180 | }, 1181 | "path-to-regexp": { 1182 | "version": "0.1.7", 1183 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1184 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1185 | }, 1186 | "performance-now": { 1187 | "version": "2.1.0", 1188 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 1189 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 1190 | }, 1191 | "pify": { 1192 | "version": "3.0.0", 1193 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 1194 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" 1195 | }, 1196 | "please-upgrade-node": { 1197 | "version": "3.1.1", 1198 | "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", 1199 | "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", 1200 | "requires": { 1201 | "semver-compare": "^1.0.0" 1202 | } 1203 | }, 1204 | "pluralize": { 1205 | "version": "7.0.0", 1206 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", 1207 | "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" 1208 | }, 1209 | "prepend-http": { 1210 | "version": "1.0.4", 1211 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", 1212 | "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" 1213 | }, 1214 | "proxy-addr": { 1215 | "version": "2.0.4", 1216 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 1217 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 1218 | "requires": { 1219 | "forwarded": "~0.1.2", 1220 | "ipaddr.js": "1.8.0" 1221 | } 1222 | }, 1223 | "pseudomap": { 1224 | "version": "1.0.2", 1225 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1226 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1227 | }, 1228 | "psl": { 1229 | "version": "1.1.29", 1230 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", 1231 | "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" 1232 | }, 1233 | "punycode": { 1234 | "version": "1.4.1", 1235 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1236 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 1237 | }, 1238 | "qs": { 1239 | "version": "6.5.2", 1240 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 1241 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 1242 | }, 1243 | "range-parser": { 1244 | "version": "1.2.0", 1245 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 1246 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 1247 | }, 1248 | "raw-body": { 1249 | "version": "2.3.3", 1250 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 1251 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 1252 | "requires": { 1253 | "bytes": "3.0.0", 1254 | "http-errors": "1.6.3", 1255 | "iconv-lite": "0.4.23", 1256 | "unpipe": "1.0.0" 1257 | } 1258 | }, 1259 | "rc": { 1260 | "version": "1.2.8", 1261 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 1262 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 1263 | "requires": { 1264 | "deep-extend": "^0.6.0", 1265 | "ini": "~1.3.0", 1266 | "minimist": "^1.2.0", 1267 | "strip-json-comments": "~2.0.1" 1268 | } 1269 | }, 1270 | "registry-auth-token": { 1271 | "version": "3.3.2", 1272 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", 1273 | "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", 1274 | "requires": { 1275 | "rc": "^1.1.6", 1276 | "safe-buffer": "^5.0.1" 1277 | } 1278 | }, 1279 | "registry-url": { 1280 | "version": "3.1.0", 1281 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", 1282 | "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", 1283 | "requires": { 1284 | "rc": "^1.0.1" 1285 | } 1286 | }, 1287 | "request": { 1288 | "version": "2.88.0", 1289 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 1290 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 1291 | "requires": { 1292 | "aws-sign2": "~0.7.0", 1293 | "aws4": "^1.8.0", 1294 | "caseless": "~0.12.0", 1295 | "combined-stream": "~1.0.6", 1296 | "extend": "~3.0.2", 1297 | "forever-agent": "~0.6.1", 1298 | "form-data": "~2.3.2", 1299 | "har-validator": "~5.1.0", 1300 | "http-signature": "~1.2.0", 1301 | "is-typedarray": "~1.0.0", 1302 | "isstream": "~0.1.2", 1303 | "json-stringify-safe": "~5.0.1", 1304 | "mime-types": "~2.1.19", 1305 | "oauth-sign": "~0.9.0", 1306 | "performance-now": "^2.1.0", 1307 | "qs": "~6.5.2", 1308 | "safe-buffer": "^5.1.2", 1309 | "tough-cookie": "~2.4.3", 1310 | "tunnel-agent": "^0.6.0", 1311 | "uuid": "^3.3.2" 1312 | } 1313 | }, 1314 | "require-directory": { 1315 | "version": "2.1.1", 1316 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1317 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" 1318 | }, 1319 | "require-main-filename": { 1320 | "version": "1.0.1", 1321 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 1322 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" 1323 | }, 1324 | "safe-buffer": { 1325 | "version": "5.1.2", 1326 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1327 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1328 | }, 1329 | "safer-buffer": { 1330 | "version": "2.1.2", 1331 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1332 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1333 | }, 1334 | "semver": { 1335 | "version": "5.5.1", 1336 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", 1337 | "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" 1338 | }, 1339 | "semver-compare": { 1340 | "version": "1.0.0", 1341 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 1342 | "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" 1343 | }, 1344 | "semver-diff": { 1345 | "version": "2.1.0", 1346 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", 1347 | "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", 1348 | "requires": { 1349 | "semver": "^5.0.3" 1350 | } 1351 | }, 1352 | "send": { 1353 | "version": "0.16.2", 1354 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 1355 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 1356 | "requires": { 1357 | "debug": "2.6.9", 1358 | "depd": "~1.1.2", 1359 | "destroy": "~1.0.4", 1360 | "encodeurl": "~1.0.2", 1361 | "escape-html": "~1.0.3", 1362 | "etag": "~1.8.1", 1363 | "fresh": "0.5.2", 1364 | "http-errors": "~1.6.2", 1365 | "mime": "1.4.1", 1366 | "ms": "2.0.0", 1367 | "on-finished": "~2.3.0", 1368 | "range-parser": "~1.2.0", 1369 | "statuses": "~1.4.0" 1370 | }, 1371 | "dependencies": { 1372 | "statuses": { 1373 | "version": "1.4.0", 1374 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 1375 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 1376 | } 1377 | } 1378 | }, 1379 | "serve-static": { 1380 | "version": "1.13.2", 1381 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 1382 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 1383 | "requires": { 1384 | "encodeurl": "~1.0.2", 1385 | "escape-html": "~1.0.3", 1386 | "parseurl": "~1.3.2", 1387 | "send": "0.16.2" 1388 | } 1389 | }, 1390 | "server-destroy": { 1391 | "version": "1.0.1", 1392 | "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", 1393 | "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=" 1394 | }, 1395 | "set-blocking": { 1396 | "version": "2.0.0", 1397 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 1398 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 1399 | }, 1400 | "setprototypeof": { 1401 | "version": "1.1.0", 1402 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 1403 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 1404 | }, 1405 | "shebang-command": { 1406 | "version": "1.2.0", 1407 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1408 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1409 | "requires": { 1410 | "shebang-regex": "^1.0.0" 1411 | } 1412 | }, 1413 | "shebang-regex": { 1414 | "version": "1.0.0", 1415 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1416 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" 1417 | }, 1418 | "signal-exit": { 1419 | "version": "3.0.2", 1420 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1421 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 1422 | }, 1423 | "sshpk": { 1424 | "version": "1.14.2", 1425 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", 1426 | "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", 1427 | "requires": { 1428 | "asn1": "~0.2.3", 1429 | "assert-plus": "^1.0.0", 1430 | "bcrypt-pbkdf": "^1.0.0", 1431 | "dashdash": "^1.12.0", 1432 | "ecc-jsbn": "~0.1.1", 1433 | "getpass": "^0.1.1", 1434 | "jsbn": "~0.1.0", 1435 | "safer-buffer": "^2.0.2", 1436 | "tweetnacl": "~0.14.0" 1437 | } 1438 | }, 1439 | "statuses": { 1440 | "version": "1.5.0", 1441 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1442 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1443 | }, 1444 | "steno": { 1445 | "version": "0.4.4", 1446 | "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", 1447 | "integrity": "sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=", 1448 | "requires": { 1449 | "graceful-fs": "^4.1.3" 1450 | } 1451 | }, 1452 | "string-width": { 1453 | "version": "2.1.1", 1454 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1455 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1456 | "requires": { 1457 | "is-fullwidth-code-point": "^2.0.0", 1458 | "strip-ansi": "^4.0.0" 1459 | } 1460 | }, 1461 | "strip-ansi": { 1462 | "version": "4.0.0", 1463 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1464 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1465 | "requires": { 1466 | "ansi-regex": "^3.0.0" 1467 | } 1468 | }, 1469 | "strip-eof": { 1470 | "version": "1.0.0", 1471 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 1472 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" 1473 | }, 1474 | "strip-json-comments": { 1475 | "version": "2.0.1", 1476 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1477 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 1478 | }, 1479 | "supports-color": { 1480 | "version": "5.5.0", 1481 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1482 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1483 | "requires": { 1484 | "has-flag": "^3.0.0" 1485 | } 1486 | }, 1487 | "term-size": { 1488 | "version": "1.2.0", 1489 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", 1490 | "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", 1491 | "requires": { 1492 | "execa": "^0.7.0" 1493 | } 1494 | }, 1495 | "timed-out": { 1496 | "version": "4.0.1", 1497 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", 1498 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" 1499 | }, 1500 | "tough-cookie": { 1501 | "version": "2.4.3", 1502 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 1503 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 1504 | "requires": { 1505 | "psl": "^1.1.24", 1506 | "punycode": "^1.4.1" 1507 | } 1508 | }, 1509 | "tunnel-agent": { 1510 | "version": "0.6.0", 1511 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1512 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1513 | "requires": { 1514 | "safe-buffer": "^5.0.1" 1515 | } 1516 | }, 1517 | "tweetnacl": { 1518 | "version": "0.14.5", 1519 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1520 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 1521 | "optional": true 1522 | }, 1523 | "type-is": { 1524 | "version": "1.6.16", 1525 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 1526 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 1527 | "requires": { 1528 | "media-typer": "0.3.0", 1529 | "mime-types": "~2.1.18" 1530 | } 1531 | }, 1532 | "unique-string": { 1533 | "version": "1.0.0", 1534 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", 1535 | "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", 1536 | "requires": { 1537 | "crypto-random-string": "^1.0.0" 1538 | } 1539 | }, 1540 | "unpipe": { 1541 | "version": "1.0.0", 1542 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1543 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1544 | }, 1545 | "unzip-response": { 1546 | "version": "2.0.1", 1547 | "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", 1548 | "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" 1549 | }, 1550 | "update-notifier": { 1551 | "version": "2.5.0", 1552 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", 1553 | "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", 1554 | "requires": { 1555 | "boxen": "^1.2.1", 1556 | "chalk": "^2.0.1", 1557 | "configstore": "^3.0.0", 1558 | "import-lazy": "^2.1.0", 1559 | "is-ci": "^1.0.10", 1560 | "is-installed-globally": "^0.1.0", 1561 | "is-npm": "^1.0.0", 1562 | "latest-version": "^3.0.0", 1563 | "semver-diff": "^2.0.0", 1564 | "xdg-basedir": "^3.0.0" 1565 | } 1566 | }, 1567 | "url-parse-lax": { 1568 | "version": "1.0.0", 1569 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", 1570 | "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", 1571 | "requires": { 1572 | "prepend-http": "^1.0.1" 1573 | } 1574 | }, 1575 | "utils-merge": { 1576 | "version": "1.0.1", 1577 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1578 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1579 | }, 1580 | "uuid": { 1581 | "version": "3.3.2", 1582 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1583 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 1584 | }, 1585 | "vary": { 1586 | "version": "1.1.2", 1587 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1588 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1589 | }, 1590 | "verror": { 1591 | "version": "1.10.0", 1592 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1593 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1594 | "requires": { 1595 | "assert-plus": "^1.0.0", 1596 | "core-util-is": "1.0.2", 1597 | "extsprintf": "^1.2.0" 1598 | } 1599 | }, 1600 | "which": { 1601 | "version": "1.3.1", 1602 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1603 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1604 | "requires": { 1605 | "isexe": "^2.0.0" 1606 | } 1607 | }, 1608 | "which-module": { 1609 | "version": "2.0.0", 1610 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 1611 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" 1612 | }, 1613 | "widest-line": { 1614 | "version": "2.0.0", 1615 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", 1616 | "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", 1617 | "requires": { 1618 | "string-width": "^2.1.1" 1619 | } 1620 | }, 1621 | "wrap-ansi": { 1622 | "version": "2.1.0", 1623 | "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 1624 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 1625 | "requires": { 1626 | "string-width": "^1.0.1", 1627 | "strip-ansi": "^3.0.1" 1628 | }, 1629 | "dependencies": { 1630 | "ansi-regex": { 1631 | "version": "2.1.1", 1632 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 1633 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 1634 | }, 1635 | "is-fullwidth-code-point": { 1636 | "version": "1.0.0", 1637 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1638 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1639 | "requires": { 1640 | "number-is-nan": "^1.0.0" 1641 | } 1642 | }, 1643 | "string-width": { 1644 | "version": "1.0.2", 1645 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1646 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1647 | "requires": { 1648 | "code-point-at": "^1.0.0", 1649 | "is-fullwidth-code-point": "^1.0.0", 1650 | "strip-ansi": "^3.0.0" 1651 | } 1652 | }, 1653 | "strip-ansi": { 1654 | "version": "3.0.1", 1655 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1656 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1657 | "requires": { 1658 | "ansi-regex": "^2.0.0" 1659 | } 1660 | } 1661 | } 1662 | }, 1663 | "write-file-atomic": { 1664 | "version": "2.3.0", 1665 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", 1666 | "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", 1667 | "requires": { 1668 | "graceful-fs": "^4.1.11", 1669 | "imurmurhash": "^0.1.4", 1670 | "signal-exit": "^3.0.2" 1671 | } 1672 | }, 1673 | "xdg-basedir": { 1674 | "version": "3.0.0", 1675 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", 1676 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" 1677 | }, 1678 | "y18n": { 1679 | "version": "3.2.1", 1680 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 1681 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" 1682 | }, 1683 | "yallist": { 1684 | "version": "2.1.2", 1685 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1686 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1687 | }, 1688 | "yargs": { 1689 | "version": "10.1.2", 1690 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", 1691 | "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", 1692 | "requires": { 1693 | "cliui": "^4.0.0", 1694 | "decamelize": "^1.1.1", 1695 | "find-up": "^2.1.0", 1696 | "get-caller-file": "^1.0.1", 1697 | "os-locale": "^2.0.0", 1698 | "require-directory": "^2.1.1", 1699 | "require-main-filename": "^1.0.1", 1700 | "set-blocking": "^2.0.0", 1701 | "string-width": "^2.0.0", 1702 | "which-module": "^2.0.0", 1703 | "y18n": "^3.2.1", 1704 | "yargs-parser": "^8.1.0" 1705 | } 1706 | }, 1707 | "yargs-parser": { 1708 | "version": "8.1.0", 1709 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", 1710 | "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", 1711 | "requires": { 1712 | "camelcase": "^4.1.0" 1713 | } 1714 | } 1715 | } 1716 | } 1717 | -------------------------------------------------------------------------------- /examples/http-json-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-json-server", 3 | "version": "1.0.0", 4 | "description": "This project is bootstrapped with [Create Elm App](https://github.com/halfzebra/create-elm-app).", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "serve-json": "json-server data.json --port 3004" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "json-server": "^0.14.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/http-json-server/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halfzebra/elm-examples/0b79ff2f79717553c9c9e2b7b4e44d78e97ccb9e/examples/http-json-server/public/favicon.ico -------------------------------------------------------------------------------- /examples/http-json-server/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Elm App 9 | 10 | 11 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/http-json-server/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Data, Model, Msg(..), apiUrl, decoder, encoder, init, main, update, view) 2 | 3 | import Browser 4 | import Debug 5 | import Html exposing (Html, button, div, input, text) 6 | import Html.Events exposing (onClick, onInput) 7 | import Http exposing (Body, Error) 8 | import Json.Decode exposing (Decoder) 9 | import Json.Encode 10 | 11 | 12 | 13 | ---- MODEL ---- 14 | 15 | 16 | type alias Data = 17 | { content : String } 18 | 19 | 20 | type alias Model = 21 | { data : Maybe Data 22 | , inputValue : String 23 | } 24 | 25 | 26 | init : ( Model, Cmd Msg ) 27 | init = 28 | ( { data = Nothing, inputValue = "" }, Cmd.none ) 29 | 30 | 31 | 32 | ---- UPDATE ---- 33 | 34 | 35 | decoder : Decoder Data 36 | decoder = 37 | Json.Decode.map Data (Json.Decode.field "content" Json.Decode.string) 38 | 39 | 40 | encoder : String -> Body 41 | encoder inputValue = 42 | [ ( "content", Json.Encode.string inputValue ) ] 43 | |> Json.Encode.object 44 | |> Http.jsonBody 45 | 46 | 47 | type Msg 48 | = Send 49 | | Response (Result Error Data) 50 | | InputUpdate String 51 | | SendData 52 | | SendDataResponse (Result Error Data) 53 | 54 | 55 | apiUrl : String 56 | apiUrl = 57 | "http://localhost:3004/data" 58 | 59 | 60 | update : Msg -> Model -> ( Model, Cmd Msg ) 61 | update msg model = 62 | case msg of 63 | Send -> 64 | ( model 65 | , Http.send Response (Http.get apiUrl decoder) 66 | ) 67 | 68 | Response res -> 69 | case res of 70 | Ok data -> 71 | ( { model | data = Just data }, Cmd.none ) 72 | 73 | Err err -> 74 | ( model, Cmd.none ) 75 | 76 | InputUpdate value -> 77 | ( { model | inputValue = value }, Cmd.none ) 78 | 79 | SendData -> 80 | ( model 81 | , Http.send Response 82 | (Http.post 83 | apiUrl 84 | (encoder model.inputValue) 85 | decoder 86 | ) 87 | ) 88 | 89 | SendDataResponse res -> 90 | case res of 91 | Ok data -> 92 | ( { model | data = Just data }, Cmd.none ) 93 | 94 | Err err -> 95 | ( model, Cmd.none ) 96 | 97 | 98 | 99 | ---- VIEW ---- 100 | 101 | 102 | view : Model -> Html Msg 103 | view model = 104 | div [] 105 | [ div [] [ text (Debug.toString model.data) ] 106 | , input [ onInput InputUpdate ] [] 107 | , button [ onClick Send ] [ text "Get the data" ] 108 | , button [ onClick SendData ] [ text "Send data to server" ] 109 | ] 110 | 111 | 112 | 113 | ---- PROGRAM ---- 114 | 115 | 116 | main : Program () Model Msg 117 | main = 118 | Browser.element 119 | { view = view 120 | , init = \() -> init 121 | , update = update 122 | , subscriptions = \_ -> Sub.none 123 | } 124 | -------------------------------------------------------------------------------- /examples/http-json-server/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halfzebra/elm-examples/0b79ff2f79717553c9c9e2b7b4e44d78e97ccb9e/examples/http-json-server/src/favicon.ico -------------------------------------------------------------------------------- /examples/http-json-server/src/index.js: -------------------------------------------------------------------------------- 1 | import './main.css'; 2 | import { Elm } from './Main.elm'; 3 | import registerServiceWorker from './registerServiceWorker'; 4 | 5 | Elm.Main.init({ 6 | node: document.getElementById('root') 7 | }); 8 | 9 | registerServiceWorker(); 10 | -------------------------------------------------------------------------------- /examples/http-json-server/src/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Source Sans Pro', 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif; 3 | margin: 0; 4 | text-align: center; 5 | color: #293c4b; 6 | } 7 | 8 | h1 { 9 | font-size: 30px; 10 | } 11 | 12 | img { 13 | margin: 20px 0; 14 | max-width: 200px; 15 | } 16 | -------------------------------------------------------------------------------- /examples/http-json-server/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /examples/key-combinations/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Model, Msg(..), init, main, subscriptions, update, view) 2 | 3 | import Browser 4 | import Browser.Events as Events 5 | import Debug 6 | import Html exposing (Html, text) 7 | import Json.Decode as Decode 8 | 9 | 10 | main : Program () Model Msg 11 | main = 12 | Browser.element 13 | { view = view 14 | , init = \() -> init 15 | , subscriptions = subscriptions 16 | , update = update 17 | } 18 | 19 | 20 | 21 | -- See https://github.com/elm/browser/blob/1.0.0/notes/keyboard.md 22 | 23 | 24 | type alias Model = 25 | List String 26 | 27 | 28 | type Msg 29 | = KeyDowns String 30 | | ClearPressed 31 | 32 | 33 | init : ( Model, Cmd Msg ) 34 | init = 35 | ( [], Cmd.none ) 36 | 37 | 38 | update : Msg -> Model -> ( Model, Cmd Msg ) 39 | update msg model = 40 | case msg of 41 | KeyDowns code -> 42 | ( if List.member code model then 43 | model 44 | 45 | else 46 | code :: model 47 | , Cmd.none 48 | ) 49 | 50 | -- Flush the whole model on `keyup`, helps to remove not pressed keys, if focus was lost from the window. 51 | ClearPressed -> 52 | ( [], Cmd.none ) 53 | 54 | 55 | view : Model -> Html Msg 56 | view model = 57 | text (Debug.toString model) 58 | 59 | 60 | subscriptions : Model -> Sub Msg 61 | subscriptions model = 62 | Sub.batch 63 | [ Events.onKeyDown (Decode.map KeyDowns keyDecoder) 64 | , Events.onKeyUp (Decode.succeed ClearPressed) 65 | ] 66 | 67 | 68 | keyDecoder : Decode.Decoder String 69 | keyDecoder = 70 | Decode.field "key" Decode.string 71 | -------------------------------------------------------------------------------- /examples/key-combinations/README.md: -------------------------------------------------------------------------------- 1 | # Key combinations with Subscription 2 | 3 | Example with a Subscription setup for tracking pressed key combinations on keybard. 4 | 5 | ## Building the example 6 | 7 | ```sh 8 | $ elm make Main.elm 9 | ``` 10 | -------------------------------------------------------------------------------- /examples/key-combinations/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/json": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/module-composition-tagger/Form.elm: -------------------------------------------------------------------------------- 1 | module Form exposing (Model, Msg(..), fieldDictionary, fieldMessageTagger, init, update, view) 2 | 3 | import Form.Field 4 | import Html exposing (Html, text) 5 | 6 | 7 | 8 | -- MODEL 9 | 10 | 11 | type alias Model = 12 | { field : Form.Field.Model 13 | , isSubmitted : Bool 14 | } 15 | 16 | 17 | init : Model 18 | init = 19 | { field = "" 20 | , isSubmitted = False 21 | } 22 | 23 | 24 | 25 | -- Translator wiring for parent module. 26 | -- Define a Record with a shape of a Dictionary from Form.Field 27 | 28 | 29 | fieldDictionary : Form.Field.Dictionary Msg 30 | fieldDictionary = 31 | { onInternalMessage = FieldMsg 32 | , onOutcomingMessageSubmit = Submit 33 | } 34 | 35 | 36 | {-| Partially apply Form.Field.translator function 37 | to carry message mappings from fieldDictionary Record 38 | -} 39 | fieldMessageTagger : Form.Field.Tagger Msg 40 | fieldMessageTagger = 41 | Form.Field.tagger fieldDictionary 42 | 43 | 44 | type Msg 45 | = FieldMsg Form.Field.Internal 46 | | Submit 47 | 48 | 49 | update : Msg -> Model -> Model 50 | update msg model = 51 | case msg of 52 | -- Run update routine for child module as usual. 53 | FieldMsg inMsg -> 54 | { model | field = Form.Field.update inMsg model.field } 55 | 56 | Submit -> 57 | { model | isSubmitted = True } 58 | 59 | 60 | view : Model -> Html Msg 61 | view model = 62 | if model.isSubmitted == False then 63 | Html.map fieldMessageTagger (Form.Field.view model.field) 64 | 65 | else 66 | text 67 | """ 68 | Congratulations! 69 | You have succesxfully submitted the form, 70 | written in Elm using tagger. 71 | """ 72 | -------------------------------------------------------------------------------- /examples/module-composition-tagger/Form/Field.elm: -------------------------------------------------------------------------------- 1 | module Form.Field exposing (Dictionary, Internal(..), Model, Msg(..), Outcoming(..), Tagger, tagger, update, view) 2 | 3 | import Html exposing (Html, button, div, input, text) 4 | import Html.Attributes exposing (value) 5 | import Html.Events exposing (onClick, onInput) 6 | 7 | 8 | type alias Model = 9 | String 10 | 11 | 12 | type Internal 13 | = Update String 14 | 15 | 16 | type Outcoming 17 | = Submit 18 | 19 | 20 | type Msg 21 | = InMsg Internal 22 | | OutMsg Outcoming 23 | 24 | 25 | type alias Dictionary parentMsg = 26 | { onInternalMessage : Internal -> parentMsg 27 | , onOutcomingMessageSubmit : parentMsg 28 | } 29 | 30 | 31 | type alias Tagger parentMsg = 32 | Msg -> parentMsg 33 | 34 | 35 | tagger : Dictionary parentMsg -> Tagger parentMsg 36 | tagger { onInternalMessage, onOutcomingMessageSubmit } msg = 37 | case msg of 38 | InMsg internal -> 39 | onInternalMessage internal 40 | 41 | OutMsg Submit -> 42 | onOutcomingMessageSubmit 43 | 44 | 45 | update : Internal -> Model -> Model 46 | update msg model = 47 | case msg of 48 | Update val -> 49 | val 50 | 51 | 52 | view : Model -> Html Msg 53 | view model = 54 | div [] 55 | [ input [ onInput (InMsg << Update), value model ] [] 56 | , button [ onClick (OutMsg Submit) ] [ text "Submit" ] 57 | ] 58 | -------------------------------------------------------------------------------- /examples/module-composition-tagger/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import Browser 4 | import Form exposing (Model, Msg, init, update, view) 5 | 6 | 7 | main : Program () Model Msg 8 | main = 9 | Browser.sandbox { view = view, update = update, init = init } 10 | -------------------------------------------------------------------------------- /examples/module-composition-tagger/README.md: -------------------------------------------------------------------------------- 1 | # Module composition in Elm with tagger function 2 | 3 | Example app, featuring the usage of tagger function for message mapping in view composition. 4 | 5 | The term is originated from official docs, where a function with type signature of `a -> msg` is defined as [tagger](http://package.elm-lang.org/packages/elm-lang/html/1.1.0/Html-Events#targetValue) 6 | 7 | It is also often referred as [Translator](https://medium.com/@alex.lew/the-translator-pattern-a-model-for-child-to-parent-communication-in-elm-f4bfaa1d3f98) pattern. 8 | 9 | ## Motivation 10 | The key takeaway of this example is that you can use the second argument of [Html.App.map](http://package.elm-lang.org/packages/elm-lang/html/1.1.0/Html-App#map) to have more control over the message flow in your top-level `update` function. 11 | 12 | The idea, introduced in the article, improves on `tagger` formula and might be used as an inspiration for generic APIs. 13 | 14 | Please consider this example: 15 | ```elm 16 | import Child 17 | 18 | 19 | type Msg 20 | = SomeMsg 21 | | ToChild Child.Msg 22 | 23 | 24 | -- Tagger function, for better control over the message flow. 25 | 26 | 27 | tagger : Child.Msg -> Msg 28 | tagger msg = 29 | case msg of 30 | Child.SomeMsg -> 31 | SomeMsg 32 | 33 | _ -> 34 | ToChild msg 35 | 36 | 37 | -- Top-level view 38 | 39 | 40 | view : Model -> Html Msg 41 | view model = 42 | Cmd.map tagger (Child.view model.childState) 43 | 44 | ``` 45 | 46 | ## Building the example 47 | 48 | ```sh 49 | $ elm make Main.elm 50 | ``` 51 | -------------------------------------------------------------------------------- /examples/module-composition-tagger/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0" 12 | }, 13 | "indirect": { 14 | "elm/json": "1.0.0", 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/module-composition/Helper.elm: -------------------------------------------------------------------------------- 1 | module Helper exposing (Model, Msg(..), init, update, view) 2 | 3 | {- This module has functions for showing and hiding the text -} 4 | 5 | import Html exposing (Html, div, text) 6 | 7 | 8 | type alias Model = 9 | { text : String 10 | , visible : Bool 11 | } 12 | 13 | 14 | init : String -> ( Model, Cmd Msg ) 15 | init text = 16 | {- Returning Cmd Msg from child module is not necessary, 17 | and the signature of init and update function might be simplified to: 18 | 19 | String -> Model 20 | Msg -> Model -> Model 21 | 22 | Here I return Cmd.none just to follow Fractal Architecture pattern. 23 | -} 24 | ( Model text False, Cmd.none ) 25 | 26 | 27 | type Msg 28 | = Show 29 | | Hide 30 | 31 | 32 | view : Model -> Html Msg 33 | view model = 34 | if model.visible == True then 35 | div [] [ text model.text ] 36 | 37 | else 38 | text "" 39 | 40 | 41 | update : Msg -> Model -> ( Model, Cmd Msg ) 42 | update msg model = 43 | case msg of 44 | Show -> 45 | ( { model | visible = True }, Cmd.none ) 46 | 47 | Hide -> 48 | ( { model | visible = False }, Cmd.none ) 49 | -------------------------------------------------------------------------------- /examples/module-composition/Input.elm: -------------------------------------------------------------------------------- 1 | module Input exposing (Model, Msg(..), init, update, view) 2 | 3 | {- This is an input module, which emits messages, when user types anything, 4 | focuses on it, or when focus leaves the field. 5 | -} 6 | 7 | import Html exposing (Html, input) 8 | import Html.Attributes exposing (type_, value) 9 | import Html.Events exposing (onBlur, onFocus, onInput) 10 | 11 | 12 | type alias Model = 13 | String 14 | 15 | 16 | init : Model -> ( Model, Cmd Msg ) 17 | init text = 18 | ( text, Cmd.none ) 19 | 20 | 21 | type Msg 22 | = Update Model 23 | | Focus 24 | | Blur 25 | 26 | 27 | view : Model -> Html Msg 28 | view model = 29 | input 30 | [ type_ "text" 31 | , onInput Update 32 | , onFocus Focus 33 | , onBlur Blur 34 | , value model 35 | ] 36 | [] 37 | 38 | 39 | update : Msg -> Model -> ( Model, Cmd Msg ) 40 | update msg model = 41 | case msg of 42 | Update value -> 43 | ( value, Cmd.none ) 44 | 45 | -- Ignore the rest of the messages. 46 | _ -> 47 | ( model, Cmd.none ) 48 | -------------------------------------------------------------------------------- /examples/module-composition/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Model, Msg(..), init, main, subscriptions, update, view) 2 | 3 | import Browser 4 | import Helper 5 | import Html exposing (Html, div, text) 6 | import Input 7 | 8 | 9 | main : Program () Model Msg 10 | main = 11 | Browser.element 12 | { view = view 13 | , init = \() -> init 14 | , update = update 15 | , subscriptions = subscriptions 16 | } 17 | 18 | 19 | subscriptions : Model -> Sub Msg 20 | subscriptions model = 21 | Sub.none 22 | 23 | 24 | type alias Model = 25 | { name : Input.Model 26 | , helper : Helper.Model 27 | } 28 | 29 | 30 | init : ( Model, Cmd Msg ) 31 | init = 32 | let 33 | -- Omit the Cmd from child's init, because we know that it's Cmd.none 34 | ( nameModel, _ ) = 35 | Input.init "John" 36 | 37 | ( helperModel, _ ) = 38 | Helper.init "Please enter your name" 39 | in 40 | ( Model nameModel helperModel, Cmd.none ) 41 | 42 | 43 | type Msg 44 | = NameMsg Input.Msg 45 | | HelperMsg Helper.Msg 46 | 47 | 48 | view : Model -> Html Msg 49 | view model = 50 | div [] 51 | [ text model.name 52 | , Html.map NameMsg (Input.view model.name) 53 | , Html.map HelperMsg (Helper.view model.helper) 54 | ] 55 | 56 | 57 | update : Msg -> Model -> ( Model, Cmd Msg ) 58 | update msg model = 59 | case msg of 60 | NameMsg childMsg -> 61 | case childMsg of 62 | {- We have intercepted a message from child module. 63 | 64 | This part of the update function might be moved 65 | to a separate function for better readability. 66 | -} 67 | Input.Focus -> 68 | update (HelperMsg Helper.Show) model 69 | 70 | Input.Blur -> 71 | update (HelperMsg Helper.Hide) model 72 | 73 | -- The default message passing routine. 74 | _ -> 75 | let 76 | ( nameModel, nameCmd ) = 77 | Input.update childMsg model.name 78 | in 79 | ( { model | name = nameModel } 80 | , Cmd.map NameMsg nameCmd 81 | ) 82 | 83 | HelperMsg childMsg -> 84 | let 85 | ( helperModel, helperCmd ) = 86 | Helper.update childMsg model.helper 87 | in 88 | ( { model | helper = helperModel } 89 | , Cmd.map HelperMsg helperCmd 90 | ) 91 | -------------------------------------------------------------------------------- /examples/module-composition/README.md: -------------------------------------------------------------------------------- 1 | # Module composition in Elm 2 | 3 | This example features the simplest way for establishing module communication. 4 | 5 | [@rtfeldman](https://github.com/rtfeldman/) on [Design of Large Elm apps](https://groups.google.com/forum/#!msg/elm-discuss/_cfOu88oCx4/6tVXN2TGAgAJ) 6 | 7 | > The first three things you should reach for are, in no particular order: 8 | > - Splitting `view` into smaller functions (without reorganizing `Model` or `update`) 9 | > - Splitting `Model` into smaller values (without reorganizing `view` or `update`) 10 | > - Splitting `update` into smaller functions (without reorganizing `Model` or `view`) 11 | > 12 | > Do one of these 3 things, one at a time, over and over, until either you're thinking "I need to split out some of this to reuse it elsewhere" (in which case you enter the realm of API design, and there is no one-size-fits-all answer to what you should do next), or you find yourself thinking "even after these small refactors, there is a big chunk of code that still feels unwieldy, and it's self-contained enough that I could separate it out into essentially its own little application, and have it communicate with the rest of the application, and that communication overhead sounds like it would be worth it." 13 | 14 | ## Motivation 15 | 16 | Elm implements uni-directional message passing, 17 | so you can not send a message directly from child to parent. 18 | 19 | To mimic child-to-parent message passing, we have to send a message from the 20 | child and [capture it in parent's update](Main.elm#L61) function. 21 | 22 | While [Input](Input.elm#L21) module has defined more than one message, only `Update` 23 | will have effect on the state. 24 | 25 | ```elm 26 | update : Msg -> Model -> ( Model, Cmd Msg ) 27 | update msg model = 28 | case msg of 29 | Update value -> 30 | ( value, Cmd.none ) 31 | 32 | -- Ignore the rest of the messages. 33 | _ -> 34 | ( model, Cmd.none ) 35 | ``` 36 | 37 | ## Building the example 38 | 39 | ```sh 40 | $ elm make Main.elm 41 | ``` 42 | 43 | ## More information on module composition in Elm 44 | 45 | For more ideas, I highly recommend watching [API Design Session - elm-autocomplete with Greg Ziegan](https://www.youtube.com/watch?v=KSuCYUqY058) 46 | -------------------------------------------------------------------------------- /examples/module-composition/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/virtual-dom": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/json": "1.0.0", 16 | "elm/time": "1.0.0", 17 | "elm/url": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/ports/Main.elm: -------------------------------------------------------------------------------- 1 | port module Main exposing (Model, Msg(..), init, input, main, output, subscriptions, update, view) 2 | 3 | import Browser 4 | import Html exposing (..) 5 | import Html.Attributes exposing (..) 6 | import String 7 | import Task 8 | 9 | 10 | main : Program () Model Msg 11 | main = 12 | Browser.element 13 | { init = \() -> init 14 | , view = view 15 | , update = update 16 | , subscriptions = subscriptions 17 | } 18 | 19 | 20 | 21 | -- SUBSCRIPTIONS 22 | 23 | 24 | {-| With an outgoing port, I want to tell JavaScript to send some value to Elm. 25 | That does not require sending data to JavaScript, so I send an empty Tuple. 26 | 27 | Note, that you can not specify the exact message type of port commands. 28 | 29 | Both port functions can be exported and used outside of the module. 30 | Since output does not emit any messages, we have type annotation definition with a generic `msg`, 31 | so it's easier to use it outside of this module 32 | and you don't have to use Cmd.map to re-map a non-existing message type. 33 | 34 | The subscription as well can be used outside of this module, 35 | you can use any message type to receive messages from the port. 36 | 37 | -} 38 | port output : () -> Cmd msg 39 | 40 | 41 | port input : (Int -> msg) -> Sub msg 42 | 43 | 44 | subscriptions : Model -> Sub Msg 45 | subscriptions model = 46 | input Get 47 | 48 | 49 | 50 | -- MODEL 51 | 52 | 53 | type alias Model = 54 | { number : Int } 55 | 56 | 57 | 58 | -- VIEW 59 | 60 | 61 | view : Model -> Html Msg 62 | view model = 63 | text (String.fromInt model.number) 64 | 65 | 66 | 67 | -- UPDATE 68 | 69 | 70 | type Msg 71 | = Get Int 72 | 73 | 74 | update : Msg -> Model -> ( Model, Cmd Msg ) 75 | update msg model = 76 | case Debug.log "MESSAGE: " msg of 77 | Get x -> 78 | ( Model x, Cmd.none ) 79 | 80 | 81 | 82 | -- INIT 83 | 84 | 85 | init : ( Model, Cmd Msg ) 86 | init = 87 | {- Send a message through port upon initialization. -} 88 | ( Model 0, output () ) 89 | -------------------------------------------------------------------------------- /examples/ports/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript interop with Elm 2 | 3 | This is an example of passing messages from Elm to JavaScript and backwards. 4 | 5 | It sends a hole `()` or empty Tuple to JavaScript, as a message and retrieves a numeric value. 6 | 7 | Inspired by [Trouble Connecting Ports and Subscriptions] [question] 8 | 9 | See more on the matter in the official docs for [JavaScript Interop] [ports] 10 | 11 | ## Building the example 12 | 13 | Since this example features port module, it is impossible to build it with `elm reactor`. 14 | 15 | You have to explicitly specify the `--output=index.js` 16 | 17 | ```sh 18 | $ elm make Main.elm --output=index.js 19 | ``` 20 | 21 | [ports]: 22 | [question]: 23 | -------------------------------------------------------------------------------- /examples/ports/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0" 12 | }, 13 | "indirect": { 14 | "elm/json": "1.0.0", 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.0" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } -------------------------------------------------------------------------------- /examples/ports/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Elm Ports 6 | 7 | 8 | 9 |
10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/random-initial-seed/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/random": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/json": "1.0.0", 16 | "elm/time": "1.0.0", 17 | "elm/url": "1.0.0", 18 | "elm/virtual-dom": "1.0.0" 19 | } 20 | }, 21 | "test-dependencies": { 22 | "direct": {}, 23 | "indirect": {} 24 | } 25 | } -------------------------------------------------------------------------------- /examples/random-initial-seed/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Model, Msg(..), main, seedGenerator, update, view) 2 | 3 | import Browser 4 | import Debug 5 | import Html exposing (button, div, text) 6 | import Html.Events exposing (onClick) 7 | import Random exposing (Generator, Seed) 8 | 9 | 10 | 11 | -- TODO 12 | 13 | 14 | main = 15 | Browser.element 16 | { init = 17 | \() -> 18 | ( { seed = Nothing, stack = [] } 19 | -- Initial command to create independent Seed. 20 | , Random.generate Update seedGenerator 21 | ) 22 | , view = view 23 | , update = update 24 | , subscriptions = \model -> Sub.none 25 | } 26 | 27 | 28 | view model = 29 | div [] 30 | [ button 31 | [ onClick PutRandomNumber ] 32 | [ text "Put a random value on a stack" ] 33 | , text (Debug.toString model.stack) 34 | ] 35 | 36 | 37 | type alias Model = 38 | { seed : Maybe Seed 39 | , stack : List Int 40 | } 41 | 42 | 43 | type Msg 44 | = Update Seed 45 | | PutRandomNumber 46 | 47 | 48 | seedGenerator : Generator Seed 49 | seedGenerator = 50 | Random.int Random.minInt Random.maxInt 51 | |> Random.map Random.initialSeed 52 | 53 | 54 | update msg model = 55 | case msg of 56 | Update seed -> 57 | -- Preserve newly initialized Seed state. 58 | ( { model | seed = Just seed }, Cmd.none ) 59 | 60 | PutRandomNumber -> 61 | let 62 | -- In case if seed was present, new model will contain the new value and a new state for the seed. 63 | newModel : Model 64 | newModel = 65 | model.seed 66 | |> Maybe.map (Random.step (Random.int 0 10)) 67 | |> Maybe.map 68 | (\( number, seed ) -> 69 | { model | seed = Just seed, stack = number :: model.stack } 70 | ) 71 | |> Maybe.withDefault model 72 | in 73 | ( newModel 74 | , Cmd.none 75 | ) 76 | -------------------------------------------------------------------------------- /examples/random-user-seed/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (Model, Msg(..), generator, init, main, update, view) 2 | 3 | import Browser 4 | import Debug 5 | import Html exposing (Html, button, div, input, text) 6 | import Html.Attributes exposing (placeholder, value) 7 | import Html.Events exposing (onClick, onInput) 8 | import Random exposing (Generator, Seed) 9 | import String 10 | 11 | 12 | generator : Int -> Generator (List Int) 13 | generator length = 14 | Random.list length (Random.int 0 100) 15 | 16 | 17 | view : Model -> Html Msg 18 | view model = 19 | div 20 | [] 21 | (input [ value model.input, placeholder "Enter numeric seed", onInput Update ] [] 22 | :: (case model.state of 23 | Ok state -> 24 | [ button [ onClick Next ] [ text "Next" ], text (Debug.toString (Tuple.first state)) ] 25 | 26 | Err msg -> 27 | [ text msg ] 28 | ) 29 | ) 30 | 31 | 32 | type Msg 33 | = Update String 34 | | CreateSeed 35 | | Next 36 | 37 | 38 | update : Msg -> Model -> Model 39 | update msg model = 40 | case msg of 41 | Update val -> 42 | update CreateSeed { model | input = val } 43 | 44 | CreateSeed -> 45 | case String.toInt model.input of 46 | Nothing -> 47 | { model | state = Err (model.input ++ " is not a valid Int") } 48 | 49 | Just theInt -> 50 | let 51 | seed = 52 | Random.initialSeed theInt 53 | 54 | newState = 55 | Random.step (generator 10) seed 56 | in 57 | { model | state = Ok newState } 58 | 59 | Next -> 60 | { model | state = Result.map (Random.step (generator 10) << Tuple.second) model.state } 61 | 62 | 63 | type alias Model = 64 | { state : Result String ( List Int, Seed ) 65 | , input : String 66 | } 67 | 68 | 69 | init : Model 70 | init = 71 | Model (Err "Seed is not available") "" 72 | 73 | 74 | main : Program () Model Msg 75 | main = 76 | Browser.sandbox 77 | { view = view 78 | , init = init 79 | , update = update 80 | } 81 | -------------------------------------------------------------------------------- /examples/random-user-seed/README.md: -------------------------------------------------------------------------------- 1 | # Random value with user-specified seed 2 | 3 | Example app for generating a list of 10 integers, using user-specified seed. 4 | 5 | It is also possible to step through generator to get next 10 random values. 6 | 7 | ## Building the example 8 | 9 | ```sh 10 | $ elm make Main.elm 11 | ``` 12 | -------------------------------------------------------------------------------- /examples/random-user-seed/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "." 5 | ], 6 | "elm-version": "0.19.0", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.0", 10 | "elm/core": "1.0.0", 11 | "elm/html": "1.0.0", 12 | "elm/random": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/json": "1.0.0", 16 | "elm/time": "1.0.0", 17 | "elm/url": "1.0.0", 18 | "elm/virtual-dom": "1.0.0" 19 | } 20 | }, 21 | "test-dependencies": { 22 | "direct": {}, 23 | "indirect": {} 24 | } 25 | } -------------------------------------------------------------------------------- /examples/select2-integration/.gitignore: -------------------------------------------------------------------------------- 1 | # Distribution 2 | build/ 3 | 4 | # elm-package generated files 5 | elm-stuff 6 | 7 | # elm-repl generated files 8 | repl-temp-* 9 | 10 | # Dependency directories 11 | node_modules 12 | 13 | # Desktop Services Store on macOS 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /examples/select2-integration/README.md: -------------------------------------------------------------------------------- 1 | Running demo of this application is available [here.](https://halfzebra.github.io/elm-examples/select2-integration/dist/) 2 | 3 | This project was bootstrapped with [Create Elm App.](https://github.com/halfzebra/create-elm-app) 4 | 5 | Below you will find some information on how to perform common tasks. 6 | You can find the most recent version of this guide [here](https://github.com/halfzebra/create-elm-app/blob/master/template/README.md). 7 | 8 | ## Building the example 9 | 10 | ```sh 11 | $ npm install create-elm-app -g # Install CreateElm App 12 | $ npm install # install local NPM deps 13 | $ elm-app build # Build the example 14 | ``` -------------------------------------------------------------------------------- /examples/select2-integration/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": ["src"], 4 | "elm-version": "0.19.0", 5 | "dependencies": { 6 | "direct": { 7 | "elm/browser": "1.0.0", 8 | "elm/core": "1.0.0", 9 | "elm/html": "1.0.0" 10 | }, 11 | "indirect": { 12 | "elm/json": "1.0.0", 13 | "elm/time": "1.0.0", 14 | "elm/url": "1.0.0", 15 | "elm/virtual-dom": "1.0.0" 16 | } 17 | }, 18 | "test-dependencies": { 19 | "direct": { 20 | "elm-explorations/test": "1.0.0" 21 | }, 22 | "indirect": { 23 | "elm/random": "1.0.0" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/select2-integration/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "select2-integration", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "almond": { 8 | "version": "0.3.3", 9 | "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz", 10 | "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=" 11 | }, 12 | "jquery": { 13 | "version": "3.3.1", 14 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", 15 | "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" 16 | }, 17 | "jquery-mousewheel": { 18 | "version": "3.1.13", 19 | "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz", 20 | "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=" 21 | }, 22 | "select2": { 23 | "version": "4.0.5", 24 | "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.5.tgz", 25 | "integrity": "sha1-eqxQaSVhmFs007guxV4ib4lg1Ao=", 26 | "requires": { 27 | "almond": "~0.3.1", 28 | "jquery-mousewheel": "~3.1.13" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/select2-integration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "select2-integration", 3 | "version": "1.0.0", 4 | "description": "This project was bootstrapped with [Create Elm App](https://github.com/halfzebra/create-elm-app).", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "jquery": "^3.3.1", 17 | "select2": "^4.0.5" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/select2-integration/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halfzebra/elm-examples/0b79ff2f79717553c9c9e2b7b4e44d78e97ccb9e/examples/select2-integration/public/favicon.ico -------------------------------------------------------------------------------- /examples/select2-integration/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | Elm App 15 | 16 | 17 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/select2-integration/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | 14 | 15 | 22 | 23 | 26 | 27 | 30 | 31 | 34 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/select2-integration/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Elm App", 3 | "name": "Create Elm App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/select2-integration/src/App.elm: -------------------------------------------------------------------------------- 1 | port module App exposing (Model, Msg(..), init, input, options, output, subscriptions, update, view) 2 | 3 | import Dict exposing (Dict) 4 | import Html exposing (Html, div, text) 5 | import Html.Attributes exposing (id) 6 | 7 | 8 | type alias Model = 9 | { selection : Maybe String } 10 | 11 | 12 | modelToString : Model -> String 13 | modelToString model = 14 | case model.selection of 15 | Nothing -> 16 | "Nothing" 17 | 18 | Just s -> 19 | "Just " ++ s 20 | 21 | 22 | init : ( Model, Cmd Msg ) 23 | init = 24 | ( Model Nothing, output (Dict.toList options) ) 25 | 26 | 27 | type Msg 28 | = Select String 29 | 30 | 31 | update : Msg -> Model -> ( Model, Cmd Msg ) 32 | update msg model = 33 | case msg of 34 | Select val -> 35 | let 36 | option : Maybe String 37 | option = 38 | Dict.get val options 39 | in 40 | ( { model | selection = option }, Cmd.none ) 41 | 42 | 43 | view : Model -> Html Msg 44 | view model = 45 | div 46 | [] 47 | [ text (modelToString model) 48 | , div [ id "select2-container" ] [] 49 | ] 50 | 51 | 52 | port output : List ( String, String ) -> Cmd msg 53 | 54 | 55 | port input : (String -> msg) -> Sub msg 56 | 57 | 58 | options : Dict String String 59 | options = 60 | Dict.fromList 61 | [ ( "US", "United States" ) 62 | , ( "UK", "United Kingdom" ) 63 | , ( "UY", "Uruguay" ) 64 | , ( "UZ", "Uzbekistan" ) 65 | ] 66 | 67 | 68 | subscriptions : Model -> Sub Msg 69 | subscriptions model = 70 | input Select 71 | -------------------------------------------------------------------------------- /examples/select2-integration/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import App exposing (..) 4 | import Browser 5 | 6 | 7 | main : Program () Model Msg 8 | main = 9 | Browser.element { view = view, init = \() -> init, update = update, subscriptions = subscriptions } 10 | -------------------------------------------------------------------------------- /examples/select2-integration/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halfzebra/elm-examples/0b79ff2f79717553c9c9e2b7b4e44d78e97ccb9e/examples/select2-integration/src/favicon.ico -------------------------------------------------------------------------------- /examples/select2-integration/src/index.js: -------------------------------------------------------------------------------- 1 | import './main.css'; 2 | import '../node_modules/select2/dist/css/select2.min.css'; 3 | 4 | import { Elm } from './Main.elm'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | import $ from 'jquery'; 8 | import select2 from 'select2'; 9 | 10 | var app = Elm.Main.init({ 11 | node: document.getElementById('root') 12 | }); 13 | 14 | registerServiceWorker(); 15 | 16 | app.ports.output.subscribe(function (options) { 17 | 18 | var $selectContainer = $('#select2-container'); 19 | 20 | // Generate DOM tree with ', { 22 | html: options.map(function (option) { 23 | return $('