├── .gitignore
├── Presentation.pdf
├── README.md
├── elm-tooling.json
├── elm.json
├── index.html
├── package.json
├── review
├── elm.json
└── src
│ └── ReviewConfig.elm
├── screenshot.png
├── src
├── API
│ ├── Image.elm
│ ├── Post.elm
│ └── User.elm
├── Cmd
│ └── Extra.elm
├── Html
│ └── Extra.elm
├── Http
│ └── Extra.elm
├── Main.elm
├── Page
│ ├── Post.elm
│ ├── Posts.elm
│ └── User.elm
├── RemoteData
│ └── Extra.elm
├── Route.elm
├── Store.elm
├── UI.elm
└── UI
│ └── Toast.elm
├── watch-compile.sh
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | elm-stuff/
2 | node_modules/
3 | elm.js
4 |
--------------------------------------------------------------------------------
/Presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Janiczek/elm-store-pattern/5d94ee898e4665b89614727f02077f2920f2d016/Presentation.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # elm-store-pattern
2 |
3 | Presentation and accompanying code demo about the Store pattern in Elm.
4 |
5 | Here's the talk about it: https://youtu.be/BCmNX2Tx5xY
6 |
7 | See `Presentation.pdf` or run the app with `yarn && yarn start`.
8 |
9 | [](https://github.com/Janiczek/elm-store-pattern/raw/main/screenshot.png)
10 |
--------------------------------------------------------------------------------
/elm-tooling.json:
--------------------------------------------------------------------------------
1 | {
2 | "tools": {
3 | "elm": "0.19.1",
4 | "elm-format": "0.8.5",
5 | "elm-json": "0.2.10",
6 | "elm-test-rs": "2.0.1"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src"
5 | ],
6 | "elm-version": "0.19.1",
7 | "dependencies": {
8 | "direct": {
9 | "elm/browser": "1.0.2",
10 | "elm/core": "1.0.5",
11 | "elm/html": "1.0.0",
12 | "elm/http": "2.0.0",
13 | "elm/svg": "1.0.1",
14 | "elm/url": "1.0.0",
15 | "emilianobovetti/elm-toast": "1.1.0",
16 | "krisajenkins/remotedata": "6.0.1"
17 | },
18 | "indirect": {
19 | "elm/bytes": "1.0.8",
20 | "elm/file": "1.0.5",
21 | "elm/json": "1.1.3",
22 | "elm/time": "1.0.0",
23 | "elm/virtual-dom": "1.0.2"
24 | }
25 | },
26 | "test-dependencies": {
27 | "direct": {},
28 | "indirect": {}
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Store pattern example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "license": "BSD-3-Clause",
3 | "scripts": {
4 | "postinstall": "elm-tooling install",
5 | "build": "elm make src/Main.elm --output=elm.js",
6 | "start": "elm-live src/Main.elm --hot --open --pushstate -- --output=elm.js"
7 | },
8 | "devDependencies": {
9 | "elm-live": "^4.0.2",
10 | "elm-review": "^2.7.2",
11 | "elm-tooling": "^1.8.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/review/elm.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "application",
3 | "source-directories": [
4 | "src"
5 | ],
6 | "elm-version": "0.19.1",
7 | "dependencies": {
8 | "direct": {
9 | "elm/core": "1.0.5",
10 | "elm/json": "1.1.3",
11 | "elm/project-metadata-utils": "1.0.2",
12 | "jfmengels/elm-review": "2.7.2",
13 | "jfmengels/elm-review-code-style": "1.0.0",
14 | "jfmengels/elm-review-common": "1.2.0",
15 | "jfmengels/elm-review-debug": "1.0.6",
16 | "jfmengels/elm-review-documentation": "2.0.1",
17 | "jfmengels/elm-review-simplify": "2.0.14",
18 | "jfmengels/elm-review-unused": "1.1.22",
19 | "stil4m/elm-syntax": "7.2.9"
20 | },
21 | "indirect": {
22 | "elm/html": "1.0.0",
23 | "elm/parser": "1.1.0",
24 | "elm/random": "1.0.0",
25 | "elm/regex": "1.0.0",
26 | "elm/time": "1.0.0",
27 | "elm/virtual-dom": "1.0.2",
28 | "elm-community/list-extra": "8.5.2",
29 | "elm-explorations/test": "1.2.2",
30 | "miniBill/elm-unicode": "1.0.2",
31 | "rtfeldman/elm-hex": "1.0.0",
32 | "stil4m/structured-writer": "1.0.3"
33 | }
34 | },
35 | "test-dependencies": {
36 | "direct": {
37 | "elm-explorations/test": "1.2.2"
38 | },
39 | "indirect": {}
40 | }
41 | }
--------------------------------------------------------------------------------
/review/src/ReviewConfig.elm:
--------------------------------------------------------------------------------
1 | module ReviewConfig exposing (config)
2 |
3 | {-| Do not rename the ReviewConfig module or the config function, because
4 | `elm-review` will look for these.
5 |
6 | To add packages that contain rules, add them to this review project using
7 |
8 | `elm install author/packagename`
9 |
10 | when inside the directory containing this file.
11 |
12 | -}
13 |
14 | import Docs.ReviewAtDocs
15 | import NoDebug.Log
16 | import NoDebug.TodoOrToString
17 | import NoExposingEverything
18 | import NoImportingEverything
19 | import NoMissingTypeAnnotation
20 | import NoMissingTypeAnnotationInLetIn
21 | import NoMissingTypeExpose
22 | import NoPrematureLetComputation
23 | import NoSimpleLetBody
24 | import NoUnused.CustomTypeConstructorArgs
25 | import NoUnused.CustomTypeConstructors
26 | import NoUnused.Dependencies
27 | import NoUnused.Exports
28 | import NoUnused.Modules
29 | import NoUnused.Parameters
30 | import NoUnused.Patterns
31 | import NoUnused.Variables
32 | import Review.Rule as Rule exposing (Rule)
33 | import Simplify
34 |
35 |
36 | config : List Rule
37 | config =
38 | [ Docs.ReviewAtDocs.rule
39 | , NoExposingEverything.rule
40 | , NoImportingEverything.rule []
41 | , NoMissingTypeAnnotation.rule
42 | , NoMissingTypeAnnotationInLetIn.rule
43 | , NoMissingTypeExpose.rule
44 | , NoSimpleLetBody.rule
45 | , NoPrematureLetComputation.rule
46 | , NoUnused.CustomTypeConstructors.rule []
47 | , NoUnused.CustomTypeConstructorArgs.rule
48 | , NoUnused.Dependencies.rule
49 | , NoUnused.Exports.rule
50 | , NoUnused.Modules.rule
51 | , NoUnused.Parameters.rule
52 | , NoUnused.Patterns.rule
53 | , NoUnused.Variables.rule
54 | , Simplify.rule Simplify.defaults
55 | ]
56 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Janiczek/elm-store-pattern/5d94ee898e4665b89614727f02077f2920f2d016/screenshot.png
--------------------------------------------------------------------------------
/src/API/Image.elm:
--------------------------------------------------------------------------------
1 | module API.Image exposing
2 | ( Image, ImageId
3 | , get
4 | )
5 |
6 | {-|
7 |
8 | @docs Image, ImageId
9 | @docs get
10 |
11 | -}
12 |
13 | import Http
14 | import Http.Extra as Http
15 |
16 |
17 | type alias Image =
18 | { id : ImageId
19 | , content : String
20 | }
21 |
22 |
23 | type alias ImageId =
24 | String
25 |
26 |
27 | get : ImageId -> (Result Http.Error Image -> msg) -> Cmd msg
28 | get imageId toMsg =
29 | if imageId == "400/300" then
30 | Http.mockFailNetworkError 4000 toMsg
31 |
32 | else
33 | Http.mockSuccess 1200
34 | { id = imageId
35 | , content = "https://www.fillmurray.com/" ++ imageId
36 | }
37 | toMsg
38 |
--------------------------------------------------------------------------------
/src/API/Post.elm:
--------------------------------------------------------------------------------
1 | module API.Post exposing
2 | ( Post, PostId
3 | , getAll
4 | , create, PostCreateData
5 | )
6 |
7 | {-|
8 |
9 | @docs Post, PostId
10 | @docs getAll
11 | @docs create, PostCreateData
12 |
13 | -}
14 |
15 | import API.Image exposing (ImageId)
16 | import API.User exposing (UserId)
17 | import Http
18 | import Http.Extra as Http
19 |
20 |
21 | type alias Post =
22 | { id : PostId
23 | , title : String
24 | , authorId : UserId
25 | , content : String
26 | , imageIds : List ImageId
27 | }
28 |
29 |
30 | type alias PostId =
31 | String
32 |
33 |
34 | getAll : (Result Http.Error (List Post) -> msg) -> Cmd msg
35 | getAll toMsg =
36 | Http.mockSuccess 1500
37 | [ Post "1" "First" "42" "Hello" [ "200/300" ]
38 | , Post "2" "Second" "999" "Foo bar" [ "400/300", "300/300" ]
39 | , Post "4" "Other" "42" "Some other post" [ "500/300", "600/300" ]
40 | ]
41 | toMsg
42 |
43 |
44 | type alias PostCreateData =
45 | { title : String
46 | , authorId : UserId
47 | , content : String
48 | }
49 |
50 |
51 | create : PostCreateData -> (Result Http.Error Post -> msg) -> Cmd msg
52 | create data toMsg =
53 | if data.title == "B" then
54 | Http.mockFailBadRequestError 1200 toMsg
55 |
56 | else
57 | Http.mockSuccess 2500
58 | { id = String.fromInt (String.length data.title + String.length data.content) -- whatever
59 | , title = data.title
60 | , authorId = data.authorId
61 | , content = data.content
62 | , imageIds = []
63 | }
64 | toMsg
65 |
--------------------------------------------------------------------------------
/src/API/User.elm:
--------------------------------------------------------------------------------
1 | module API.User exposing (User, UserId, getAll)
2 |
3 | {-|
4 |
5 | @docs User, UserId, getAll
6 |
7 | -}
8 |
9 | import Http
10 | import Http.Extra as Http
11 |
12 |
13 | type alias User =
14 | { id : UserId
15 | , name : String
16 | }
17 |
18 |
19 | type alias UserId =
20 | String
21 |
22 |
23 | getAll : (Result Http.Error (List User) -> msg) -> Cmd msg
24 | getAll toMsg =
25 | --Http.mockFailNetworkError 2000 toMsg
26 | Http.mockSuccess 2000
27 | [ User "999" "Martin"
28 | , User "42" "Peter"
29 | , User "4" "Casey"
30 | ]
31 | toMsg
32 |
--------------------------------------------------------------------------------
/src/Cmd/Extra.elm:
--------------------------------------------------------------------------------
1 | module Cmd.Extra exposing (andThen, andThenMaybe)
2 |
3 |
4 | andThen :
5 | (model -> ( model, Cmd msg ))
6 | -> ( model, Cmd msg )
7 | -> ( model, Cmd msg )
8 | andThen fn ( oldModel, oldCmd ) =
9 | let
10 | ( newModel, additionalCmd ) =
11 | fn oldModel
12 | in
13 | ( newModel
14 | , Cmd.batch [ oldCmd, additionalCmd ]
15 | )
16 |
17 |
18 | andThenMaybe :
19 | (a -> model -> ( model, Cmd msg ))
20 | -> Maybe a
21 | -> ( model, Cmd msg )
22 | -> ( model, Cmd msg )
23 | andThenMaybe fn maybe modelAndCmd =
24 | case maybe of
25 | Nothing ->
26 | modelAndCmd
27 |
28 | Just thing ->
29 | modelAndCmd
30 | |> andThen (fn thing)
31 |
--------------------------------------------------------------------------------
/src/Html/Extra.elm:
--------------------------------------------------------------------------------
1 | module Html.Extra exposing (spinner, todo)
2 |
3 | import Html exposing (Html)
4 | import Html.Attributes as Attrs
5 | import Svg
6 | import Svg.Attributes as SvgAttrs
7 |
8 |
9 | todo : String -> Html msg
10 | todo message =
11 | Html.div
12 | [ Attrs.class "p-4 bg-red-100 border-red-200 border-2" ]
13 | [ Html.text message ]
14 |
15 |
16 | spinner : Html msg
17 | spinner =
18 | Svg.svg
19 | [ SvgAttrs.class "animate-spin text-red w-6 h-6"
20 | , SvgAttrs.fill "none"
21 | , SvgAttrs.viewBox "0 0 24 24"
22 | ]
23 | [ Svg.circle
24 | [ SvgAttrs.class "opacity-25"
25 | , SvgAttrs.cx "12"
26 | , SvgAttrs.cy "12"
27 | , SvgAttrs.r "10"
28 | , SvgAttrs.stroke "currentColor"
29 | , SvgAttrs.strokeWidth "4"
30 | ]
31 | []
32 | , Svg.path
33 | [ SvgAttrs.class "opacity-75"
34 | , SvgAttrs.fill "currentColor"
35 | , SvgAttrs.d "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
36 | ]
37 | []
38 | ]
39 |
--------------------------------------------------------------------------------
/src/Http/Extra.elm:
--------------------------------------------------------------------------------
1 | module Http.Extra exposing
2 | ( mockFailBadRequestError
3 | --, TODO mockFailDecoderError
4 |
5 | , mockFailNetworkError
6 | , mockSuccess
7 | )
8 |
9 | import Http
10 | import Process
11 | import Task
12 |
13 |
14 | mockSuccess : Float -> a -> (Result Http.Error a -> msg) -> Cmd msg
15 | mockSuccess delay value toMsg =
16 | emitWithDelay delay
17 | (toMsg (Ok value))
18 |
19 |
20 | mockFailNetworkError : Float -> (Result Http.Error a -> msg) -> Cmd msg
21 | mockFailNetworkError delay toMsg =
22 | emitWithDelay delay
23 | (toMsg (Err Http.NetworkError))
24 |
25 |
26 | mockFailBadRequestError : Float -> (Result Http.Error a -> msg) -> Cmd msg
27 | mockFailBadRequestError delay toMsg =
28 | emitWithDelay delay
29 | (toMsg (Err <| Http.BadStatus 400))
30 |
31 |
32 | emitWithDelay : Float -> msg -> Cmd msg
33 | emitWithDelay delay msg =
34 | let
35 | _ =
36 | Debug.log "mock request" msg
37 | in
38 | Process.sleep delay
39 | |> Task.perform (\() -> Debug.log "mock response" msg)
40 |
--------------------------------------------------------------------------------
/src/Main.elm:
--------------------------------------------------------------------------------
1 | module Main exposing (Flags, Model, Msg, Toast, main)
2 |
3 | import API.Post exposing (PostCreateData)
4 | import Browser
5 | import Browser.Navigation
6 | import Cmd.Extra as Cmd
7 | import Dict exposing (Dict)
8 | import Html exposing (Attribute, Html)
9 | import Html.Attributes as Attrs
10 | import Html.Events as Events
11 | import Http
12 | import Page.Post
13 | import Page.Posts
14 | import Page.User
15 | import RemoteData exposing (RemoteData(..), WebData)
16 | import RemoteData.Extra as RemoteData
17 | import Route exposing (Route(..))
18 | import Store exposing (Store)
19 | import Toast
20 | import UI
21 | import UI.Toast
22 | import Url exposing (Url)
23 |
24 |
25 | main : Program Flags Model Msg
26 | main =
27 | Browser.application
28 | { init = init
29 | , update = update
30 | , subscriptions = subscriptions
31 | , view = view
32 | , onUrlChange = UrlChanged
33 | , onUrlRequest = UrlRequested
34 | }
35 |
36 |
37 | type alias Flags =
38 | ()
39 |
40 |
41 | type Toast
42 | = StoreActionSent Store.Action
43 | | StoreActionSuccess Store.Action
44 | | StoreActionFailure Store.Action Http.Error
45 |
46 |
47 | type alias Model =
48 | { store : Store
49 | , route : Route
50 | , navKey : Browser.Navigation.Key
51 | , notifications : Toast.Tray Toast
52 | , failureDetailsModal : Maybe ( Store.Action, Http.Error )
53 | }
54 |
55 |
56 | type Msg
57 | = StoreMsg Store.Msg
58 | | ToastMsg Toast.Msg
59 | | UrlChanged Url
60 | | UrlRequested Browser.UrlRequest
61 | | CreatePost PostCreateData
62 | | OpenFailureDetails Store.Action Http.Error
63 | | CloseFailureDetails
64 | | CopyFailureDetails
65 |
66 |
67 | init : Flags -> Url -> Browser.Navigation.Key -> ( Model, Cmd Msg )
68 | init () url navKey =
69 | let
70 | route : Route
71 | route =
72 | Route.fromUrl url
73 |
74 | store : Store
75 | store =
76 | Store.init
77 |
78 | requests : List Store.Action
79 | requests =
80 | dataRequests store route
81 | in
82 | { store = store
83 | , route = route
84 | , navKey = navKey
85 | , notifications = Toast.tray
86 | , failureDetailsModal = Nothing
87 | }
88 | |> sendDataRequests requests
89 |
90 |
91 | sendDataRequest : Store.Action -> Model -> ( Model, Cmd Msg )
92 | sendDataRequest request model =
93 | let
94 | ( newStore, storeCmd ) =
95 | model.store
96 | |> Store.runAction request
97 | in
98 | ( { model | store = newStore }
99 | , Cmd.map StoreMsg storeCmd
100 | )
101 |
102 |
103 | sendDataRequests : List Store.Action -> Model -> ( Model, Cmd Msg )
104 | sendDataRequests requests model =
105 | List.foldl
106 | (\request modelAndCmd ->
107 | modelAndCmd
108 | |> Cmd.andThen (sendDataRequest request)
109 | )
110 | ( model, Cmd.none )
111 | requests
112 |
113 |
114 | storeMsgToast : Store.Msg -> Maybe Toast
115 | storeMsgToast storeMsg =
116 | case storeMsg of
117 | Store.HttpError action err ->
118 | Just (StoreActionFailure action err)
119 |
120 | Store.GotPosts _ ->
121 | Nothing
122 |
123 | Store.GotUsers _ ->
124 | Nothing
125 |
126 | Store.GotImage _ ->
127 | Nothing
128 |
129 | Store.CreatedPost action _ ->
130 | Just (StoreActionSuccess action)
131 |
132 |
133 | update : Msg -> Model -> ( Model, Cmd Msg )
134 | update msg model =
135 | case msg of
136 | StoreMsg storeMsg ->
137 | let
138 | ( newStore, storeCmd ) =
139 | Store.update storeMsg model.store
140 |
141 | requests : List Store.Action
142 | requests =
143 | dataRequests newStore model.route
144 |
145 | maybeToast : Maybe Toast
146 | maybeToast =
147 | storeMsgToast storeMsg
148 | in
149 | ( { model | store = newStore }
150 | , Cmd.map StoreMsg storeCmd
151 | )
152 | |> Cmd.andThen (sendDataRequests requests)
153 | |> Cmd.andThenMaybe addToast maybeToast
154 |
155 | ToastMsg toastMsg ->
156 | let
157 | ( newNotifications, toastCmd ) =
158 | Toast.update toastMsg model.notifications
159 | in
160 | ( { model | notifications = newNotifications }
161 | , Cmd.map ToastMsg toastCmd
162 | )
163 |
164 | UrlChanged url ->
165 | let
166 | newRoute : Route
167 | newRoute =
168 | Route.fromUrl url
169 |
170 | requests : List Store.Action
171 | requests =
172 | dataRequests model.store newRoute
173 | in
174 | ( { model | route = newRoute }
175 | , Cmd.none
176 | )
177 | |> Cmd.andThen (sendDataRequests requests)
178 |
179 | UrlRequested request ->
180 | case request of
181 | Browser.Internal url ->
182 | ( model, Browser.Navigation.pushUrl model.navKey (Url.toString url) )
183 |
184 | Browser.External urlString ->
185 | ( model, Browser.Navigation.load urlString )
186 |
187 | CreatePost data ->
188 | let
189 | request : Store.Action
190 | request =
191 | Store.CreatePost data
192 | in
193 | model
194 | |> sendDataRequest request
195 | |> Cmd.andThen (addToast (StoreActionSent request))
196 |
197 | OpenFailureDetails action err ->
198 | ( { model | failureDetailsModal = Just ( action, err ) }
199 | , Cmd.none
200 | )
201 |
202 | CloseFailureDetails ->
203 | ( { model | failureDetailsModal = Nothing }
204 | , Cmd.none
205 | )
206 |
207 | CopyFailureDetails ->
208 | let
209 | _ =
210 | Debug.log "TODO copy failure"
211 | in
212 | ( model
213 | , Cmd.none
214 | )
215 |
216 |
217 | addToast : Toast -> Model -> ( Model, Cmd Msg )
218 | addToast toast model =
219 | let
220 | ( newNotifications, toastCmd ) =
221 | Toast.add model.notifications (createToast toast)
222 | in
223 | ( { model | notifications = newNotifications }
224 | , Cmd.map ToastMsg toastCmd
225 | )
226 |
227 |
228 | dataRequests : Store -> Route -> List Store.Action
229 | dataRequests store route =
230 | case route of
231 | PostsRoute ->
232 | Page.Posts.dataRequests
233 |
234 | PostRoute postId ->
235 | Page.Post.dataRequests store postId
236 |
237 | UserRoute _ ->
238 | Page.User.dataRequests
239 |
240 | NotFoundRoute ->
241 | []
242 |
243 |
244 | subscriptions : Model -> Sub Msg
245 | subscriptions _ =
246 | Sub.none
247 |
248 |
249 | postsPageConfig : Page.Posts.Config Msg
250 | postsPageConfig =
251 | { createPost = CreatePost
252 | }
253 |
254 |
255 | view : Model -> Browser.Document Msg
256 | view model =
257 | { title = "Example Store app"
258 | , body =
259 | [ Html.div
260 | [ Attrs.class "p-4 gap-4 flex flex-col" ]
261 | [ storeLoadView model.store
262 | , navView model.store model.route
263 | , case model.route of
264 | PostsRoute ->
265 | Page.Posts.view postsPageConfig model.store
266 |
267 | PostRoute postId ->
268 | Page.Post.view model.store postId
269 |
270 | UserRoute userId ->
271 | Page.User.view model.store userId
272 |
273 | NotFoundRoute ->
274 | Html.text "Page not found"
275 | , model.failureDetailsModal
276 | |> Maybe.map failureDetailsModalView
277 | |> Maybe.withDefault (Html.text "")
278 | ]
279 | , notificationsView model.notifications
280 | ]
281 | }
282 |
283 |
284 | failureDetailsModalView : ( Store.Action, Http.Error ) -> Html Msg
285 | failureDetailsModalView _ =
286 | let
287 | url : String
288 | url =
289 | "POST https://api.example.com/endpoint"
290 |
291 | request : String
292 | request =
293 | """{
294 | "title": "New post",
295 | "authorId": "123",
296 | "content": "Hello there!"
297 | }"""
298 |
299 | response : String
300 | response =
301 | """{
302 | "error": "name_already_exists"
303 | }"""
304 |
305 | curl : String
306 | curl =
307 | """curl 'https://api.example.com/endpoint' \\
308 | -X 'POST' \\
309 | --data-binary '{ "title": "New post", "authorId": "123", "content": "Hello there!" }'"""
310 | in
311 | Html.div [ Attrs.class "absolute inset-20 h-min z-20 flex flex-col border-2 border-orange-300 bg-orange-200" ]
312 | [ Html.div
313 | [ Attrs.class "p-2 flex flex-col gap-2 overflow-y-auto" ]
314 | [ Html.p [] [ Html.text "Something went wrong... Please send this to our support:" ]
315 | , Html.div []
316 | [ Html.h3 [] [ Html.text "Endpoint:" ]
317 | , Html.code [ Attrs.class UI.code ] [ Html.text url ]
318 | ]
319 | , Html.div []
320 | [ Html.h3 [] [ Html.text "Request:" ]
321 | , Html.code [ Attrs.class UI.code ] [ Html.text request ]
322 | ]
323 | , Html.div []
324 | [ Html.h3 [] [ Html.text "Response:" ]
325 | , Html.code [ Attrs.class UI.code ] [ Html.text response ]
326 | ]
327 | , Html.div []
328 | [ Html.h3 [] [ Html.text "CURL:" ]
329 | , Html.code [ Attrs.class UI.code ] [ Html.text curl ]
330 | ]
331 | ]
332 | , Html.div [ Attrs.class "flex flex-row gap-2 p-2" ]
333 | [ Html.button
334 | [ Events.onClick CopyFailureDetails
335 | , Attrs.class UI.blueButton
336 | ]
337 | [ Html.text "Copy to clipboard" ]
338 | , Html.button
339 | [ Events.onClick CloseFailureDetails
340 | , Attrs.class UI.redButton
341 | ]
342 | [ Html.text "Close" ]
343 | ]
344 | ]
345 |
346 |
347 | notificationsView : Toast.Tray Toast -> Html Msg
348 | notificationsView tray =
349 | Html.div
350 | [ Attrs.class "absolute top-4 right-4 z-10" ]
351 | [ Toast.render toastView tray (Toast.config ToastMsg) ]
352 |
353 |
354 | createToast : Toast -> Toast.Toast Toast
355 | createToast toast =
356 | case toast of
357 | StoreActionSent _ ->
358 | toast
359 | |> Toast.expireIn 3000
360 | |> Toast.withExitTransition 900
361 |
362 | StoreActionSuccess _ ->
363 | toast
364 | |> Toast.expireIn 3000
365 | |> Toast.withExitTransition 900
366 |
367 | StoreActionFailure _ _ ->
368 | toast
369 | |> Toast.persistent
370 | |> Toast.withExitTransition 900
371 |
372 |
373 | toastView : List (Attribute Msg) -> Toast.Info Toast -> Html Msg
374 | toastView attrs toast =
375 | (case toast.content of
376 | StoreActionSent action ->
377 | case action of
378 | Store.GetPosts ->
379 | Nothing
380 |
381 | Store.GetUsers ->
382 | Nothing
383 |
384 | Store.GetImage _ ->
385 | Nothing
386 |
387 | Store.CreatePost post ->
388 | Just <|
389 | UI.Toast.sent
390 | { close = ToastMsg (Toast.exit toast.id) }
391 | ("Creating post '"
392 | ++ post.title
393 | ++ "'"
394 | )
395 |
396 | StoreActionSuccess action ->
397 | case action of
398 | Store.GetPosts ->
399 | Nothing
400 |
401 | Store.GetUsers ->
402 | Nothing
403 |
404 | Store.GetImage _ ->
405 | Nothing
406 |
407 | Store.CreatePost post ->
408 | Just <|
409 | UI.Toast.success
410 | { close = ToastMsg (Toast.exit toast.id) }
411 | ("Created post '"
412 | ++ post.title
413 | ++ "'"
414 | )
415 |
416 | StoreActionFailure action err ->
417 | let
418 | failure : String -> Maybe (Html Msg)
419 | failure message =
420 | Just <|
421 | UI.Toast.failure
422 | { close = ToastMsg (Toast.exit toast.id)
423 | , openDetails = OpenFailureDetails action err
424 | }
425 | message
426 | in
427 | case action of
428 | Store.GetPosts ->
429 | failure "Failed to get posts"
430 |
431 | Store.GetUsers ->
432 | failure "Failed to get users"
433 |
434 | Store.GetImage id ->
435 | failure
436 | ("Failed to get image '"
437 | ++ id
438 | ++ "'"
439 | )
440 |
441 | Store.CreatePost post ->
442 | failure
443 | ("Failed to create post '"
444 | ++ post.title
445 | ++ "'"
446 | )
447 | )
448 | |> Maybe.map
449 | (\html ->
450 | Html.div
451 | (Attrs.classList
452 | [ ( "transition duration-300 transform-gpu", True )
453 | , ( "opacity-0 translate-x-full", toast.phase == Toast.Exit )
454 | ]
455 | :: attrs
456 | )
457 | [ html ]
458 | )
459 | |> Maybe.withDefault (Html.text "")
460 |
461 |
462 | navView : Store -> Route -> Html Msg
463 | navView store currentRoute =
464 | let
465 | routeLabel : Route -> String
466 | routeLabel route =
467 | case route of
468 | PostsRoute ->
469 | "All Posts"
470 |
471 | PostRoute id ->
472 | "Post: "
473 | ++ (RemoteData.get id store.posts
474 | |> RemoteData.map (\{ title } -> "\"" ++ title ++ "\"")
475 | |> RemoteData.withDefault ("#" ++ id)
476 | )
477 |
478 | UserRoute id ->
479 | "User: "
480 | ++ (RemoteData.get id store.users
481 | |> RemoteData.map .name
482 | |> RemoteData.withDefault ("#" ++ id)
483 | )
484 |
485 | NotFoundRoute ->
486 | "Not Found"
487 |
488 | stableRoutes : List Route
489 | stableRoutes =
490 | [ PostsRoute ]
491 |
492 | allRoutes : List Route
493 | allRoutes =
494 | if List.member currentRoute stableRoutes then
495 | stableRoutes
496 |
497 | else
498 | stableRoutes ++ [ currentRoute ]
499 | in
500 | Html.div [ Attrs.class "flex flex-row gap-2" ]
501 | (Html.text "Nav: "
502 | :: (allRoutes
503 | |> List.map
504 | (\route ->
505 | Html.a
506 | [ Attrs.href (Route.toString route)
507 | , Attrs.classList
508 | [ ( UI.a, True )
509 | , ( "font-bold", route == currentRoute )
510 | ]
511 | ]
512 | [ Html.text (routeLabel route) ]
513 | )
514 | )
515 | )
516 |
517 |
518 | storeLoadView : Store -> Html msg
519 | storeLoadView store =
520 | let
521 | row : String -> String -> Html msg
522 | row label content =
523 | Html.tr []
524 | [ Html.td [ Attrs.class UI.td ] [ Html.text label ]
525 | , Html.td [ Attrs.class UI.td ] [ Html.text content ]
526 | ]
527 |
528 | webdataSquare : WebData a -> String
529 | webdataSquare data =
530 | case data of
531 | NotAsked ->
532 | "⬜️"
533 |
534 | Loading ->
535 | "🟨"
536 |
537 | Failure _ ->
538 | "🟥"
539 |
540 | Success _ ->
541 | "🟩"
542 |
543 | webdataDict : String -> WebData (Dict comparable a) -> Html msg
544 | webdataDict label data =
545 | row label
546 | (webdataSquare data
547 | ++ (data
548 | |> RemoteData.map (\dict_ -> " Dict (" ++ String.fromInt (Dict.size dict_) ++ " items)")
549 | |> RemoteData.withDefault ""
550 | )
551 | )
552 |
553 | dictWebdata : String -> Dict comparable (WebData a) -> Html msg
554 | dictWebdata label dict =
555 | let
556 | contents : String
557 | contents =
558 | if Dict.isEmpty dict then
559 | "empty"
560 |
561 | else
562 | dict
563 | |> Dict.values
564 | |> List.map webdataSquare
565 | |> String.concat
566 | in
567 | row label ("Dict (" ++ contents ++ ")")
568 | in
569 | Html.div
570 | [ Attrs.class "text-slate-400" ]
571 | [ Html.h2
572 | [ Attrs.class "font-bold mb-2 border-b border-b-4 border-slate-200" ]
573 | [ Html.text "Store status" ]
574 | , Html.table
575 | []
576 | [ webdataDict "posts" store.posts
577 | , webdataDict "users" store.users
578 | , dictWebdata "images" store.images
579 | ]
580 | ]
581 |
--------------------------------------------------------------------------------
/src/Page/Post.elm:
--------------------------------------------------------------------------------
1 | module Page.Post exposing (dataRequests, view)
2 |
3 | import API.Image exposing (Image)
4 | import API.Post exposing (Post, PostId)
5 | import API.User exposing (User)
6 | import Html exposing (Html)
7 | import Html.Attributes as Attrs
8 | import RemoteData
9 | import RemoteData.Extra as RemoteData
10 | import Route exposing (Route(..))
11 | import Store exposing (Store)
12 | import UI
13 |
14 |
15 | dataRequests : Store -> PostId -> List Store.Action
16 | dataRequests store postId =
17 | let
18 | staticRequests : List Store.Action
19 | staticRequests =
20 | [ Store.GetPosts
21 | , Store.GetUsers
22 | ]
23 |
24 | dynamicRequests : List Store.Action
25 | dynamicRequests =
26 | RemoteData.get postId store.posts
27 | |> RemoteData.map .imageIds
28 | |> RemoteData.withDefault []
29 | |> List.map Store.GetImage
30 | in
31 | staticRequests ++ dynamicRequests
32 |
33 |
34 | view : Store -> PostId -> Html msg
35 | view store postId =
36 | let
37 | title : String
38 | title =
39 | RemoteData.get postId store.posts
40 | |> RemoteData.map (.title >> (\s -> "\"" ++ s ++ "\""))
41 | |> RemoteData.withDefault ("#" ++ postId)
42 | |> (\s -> "Post: " ++ s)
43 | in
44 | Html.div
45 | []
46 | [ Html.h1
47 | [ Attrs.class UI.h1 ]
48 | [ Html.text title ]
49 | , RemoteData.view title (RemoteData.get postId store.posts) <|
50 | \post ->
51 | RemoteData.view "Author" (RemoteData.get post.authorId store.users) <|
52 | \user ->
53 | RemoteData.view "Images" (RemoteData.traverse (\imageId -> RemoteData.get_ imageId store.images) post.imageIds) <|
54 | \images -> postView post user images
55 | ]
56 |
57 |
58 | postView : Post -> User -> List Image -> Html msg
59 | postView post user images =
60 | Html.div [ Attrs.class "gap-2 flex flex-col" ]
61 | [ Html.div []
62 | [ Html.text "Author: "
63 | , Html.a
64 | [ Attrs.href (Route.toString (UserRoute user.id))
65 | , Attrs.class UI.a
66 | ]
67 | [ Html.text user.name ]
68 | ]
69 | , Html.div [] [ Html.text post.content ]
70 | , Html.div [] (images |> List.map (\image -> Html.img [ Attrs.src image.content ] []))
71 | ]
72 |
--------------------------------------------------------------------------------
/src/Page/Posts.elm:
--------------------------------------------------------------------------------
1 | module Page.Posts exposing (Config, dataRequests, view)
2 |
3 | import API.Post exposing (Post, PostCreateData, PostId)
4 | import API.User exposing (User, UserId)
5 | import Dict exposing (Dict)
6 | import Html exposing (Html)
7 | import Html.Attributes as Attrs
8 | import Html.Events as Events
9 | import RemoteData.Extra as RemoteData
10 | import Route exposing (Route(..))
11 | import Store exposing (Store)
12 | import UI
13 |
14 |
15 | dataRequests : List Store.Action
16 | dataRequests =
17 | [ Store.GetPosts
18 | , Store.GetUsers
19 | ]
20 |
21 |
22 | type alias Config msg =
23 | { createPost : PostCreateData -> msg
24 | }
25 |
26 |
27 | view : Config msg -> Store -> Html msg
28 | view config store =
29 | Html.div
30 | []
31 | [ Html.h1
32 | [ Attrs.class UI.h1 ]
33 | [ Html.text "Posts" ]
34 | , RemoteData.view "Posts" store.posts <|
35 | \posts ->
36 | RemoteData.view "Users" store.users <|
37 | \users ->
38 | postsView config posts users
39 | ]
40 |
41 |
42 | postsView : Config msg -> Dict PostId Post -> Dict UserId User -> Html msg
43 | postsView config posts users =
44 | Html.div
45 | [ Attrs.class "flex flex-col gap-2" ]
46 | [ Html.table [ Attrs.class "w-min" ]
47 | [ Html.thead []
48 | [ Html.tr []
49 | ([ "ID"
50 | , "Title"
51 | , "Author"
52 | , "Images"
53 | ]
54 | |> List.map
55 | (\title ->
56 | Html.th
57 | [ Attrs.class UI.th ]
58 | [ Html.text title ]
59 | )
60 | )
61 | ]
62 | , Html.tbody []
63 | (posts
64 | |> Dict.values
65 | |> List.map (postRowView users)
66 | )
67 | ]
68 | , Html.div
69 | [ Attrs.class "flex flex-row gap-2" ]
70 | [ Html.button
71 | [ Events.onClick
72 | (config.createPost
73 | { title = "A"
74 | , authorId = "4"
75 | , content = "I am A!"
76 | }
77 | )
78 | , Attrs.class UI.blueButton
79 | ]
80 | [ Html.text "Create post A" ]
81 | , Html.button
82 | [ Events.onClick
83 | (config.createPost
84 | { title = "B"
85 | , authorId = "42"
86 | , content = "B side"
87 | }
88 | )
89 | , Attrs.class UI.blueButton
90 | ]
91 | [ Html.text "Create post B" ]
92 | , Html.button
93 | [ Events.onClick
94 | (config.createPost
95 | { title = "C"
96 | , authorId = "999"
97 | , content = "C C C C C"
98 | }
99 | )
100 | , Attrs.class UI.blueButton
101 | ]
102 | [ Html.text "Create post C" ]
103 | ]
104 | ]
105 |
106 |
107 | postRowView : Dict UserId User -> Post -> Html msg
108 | postRowView users post =
109 | let
110 | cell : ( String, Maybe Route ) -> Html msg
111 | cell ( text, maybeRoute ) =
112 | Html.td
113 | [ Attrs.class UI.td
114 | ]
115 | [ maybeRoute
116 | |> Maybe.map
117 | (\route ->
118 | Html.a
119 | [ Attrs.href (Route.toString route)
120 | , Attrs.class UI.a
121 | ]
122 | [ Html.text text ]
123 | )
124 | |> Maybe.withDefault (Html.text text)
125 | ]
126 | in
127 | Html.tr []
128 | ([ ( post.id, Just (PostRoute post.id) )
129 | , ( post.title, Just (PostRoute post.id) )
130 | , ( Dict.get post.authorId users
131 | |> Maybe.map .name
132 | |> Maybe.withDefault ("#" ++ post.authorId)
133 | , Just (UserRoute post.authorId)
134 | )
135 | , ( String.repeat (List.length post.imageIds) "🌆"
136 | , Nothing
137 | )
138 | ]
139 | |> List.map cell
140 | )
141 |
--------------------------------------------------------------------------------
/src/Page/User.elm:
--------------------------------------------------------------------------------
1 | module Page.User exposing (dataRequests, view)
2 |
3 | import API.User exposing (User, UserId)
4 | import Html exposing (Html)
5 | import Html.Attributes as Attrs
6 | import RemoteData
7 | import RemoteData.Extra as RemoteData
8 | import Store exposing (Store)
9 | import UI
10 |
11 |
12 | dataRequests : List Store.Action
13 | dataRequests =
14 | [ Store.GetUsers ]
15 |
16 |
17 | view : Store -> UserId -> Html msg
18 | view store userId =
19 | let
20 | title : String
21 | title =
22 | RemoteData.get userId store.users
23 | |> RemoteData.map .name
24 | |> RemoteData.withDefault ("#" ++ userId)
25 | |> (\s -> "User: " ++ s)
26 | in
27 | Html.div
28 | []
29 | [ Html.h1
30 | [ Attrs.class UI.h1 ]
31 | [ Html.text title ]
32 | , RemoteData.view title (RemoteData.get userId store.users) <|
33 | \user -> userView user
34 | ]
35 |
36 |
37 | userView : User -> Html msg
38 | userView user =
39 | Html.ul []
40 | [ Html.li [] [ Html.text <| "ID: " ++ user.id ]
41 | , Html.li [] [ Html.text <| "Name: " ++ user.name ]
42 | ]
43 |
--------------------------------------------------------------------------------
/src/RemoteData/Extra.elm:
--------------------------------------------------------------------------------
1 | module RemoteData.Extra exposing (get, get_, traverse, view)
2 |
3 | import Dict exposing (Dict)
4 | import Html exposing (Html)
5 | import Html.Attributes as Attrs
6 | import Html.Extra as Html
7 | import Http
8 | import RemoteData exposing (RemoteData(..), WebData)
9 |
10 |
11 | view : String -> WebData a -> (a -> Html msg) -> Html msg
12 | view label data successView =
13 | case data of
14 | NotAsked ->
15 | Html.text ""
16 |
17 | Loading ->
18 | Html.div [ Attrs.class "inline-flex flex-col shrink items-center gap-2" ]
19 | [ Html.span [] [ Html.text <| "Loading " ++ label ++ "..." ]
20 | , Html.spinner
21 | ]
22 |
23 | Failure err ->
24 | Html.todo <| "Error view for " ++ label ++ ": " ++ Debug.toString err
25 |
26 | Success value ->
27 | successView value
28 |
29 |
30 | get : comparable -> WebData (Dict comparable a) -> WebData a
31 | get key data =
32 | data
33 | |> RemoteData.andThen
34 | (\dict ->
35 | Dict.get key dict
36 | |> RemoteData.fromMaybe
37 | (Http.BadBody ("key '" ++ Debug.toString key ++ "' not found"))
38 | )
39 |
40 |
41 | get_ : comparable -> Dict comparable (WebData a) -> WebData a
42 | get_ key dict =
43 | Dict.get key dict
44 | |> Maybe.withDefault (Failure (Http.BadBody ("key '" ++ Debug.toString key ++ "' not found")))
45 |
46 |
47 | traverse : (a -> RemoteData x b) -> List a -> RemoteData x (List b)
48 | traverse fn list =
49 | List.foldl
50 | (\x acc -> RemoteData.map2 (::) (fn x) acc)
51 | (Success [])
52 | list
53 |
--------------------------------------------------------------------------------
/src/Route.elm:
--------------------------------------------------------------------------------
1 | module Route exposing (Route(..), fromUrl, toString)
2 |
3 | import API.Post exposing (PostId)
4 | import API.User exposing (UserId)
5 | import Url exposing (Url)
6 | import Url.Builder
7 | import Url.Parser exposing ((>), Parser)
8 |
9 |
10 | type Route
11 | = PostsRoute
12 | | PostRoute PostId
13 | | UserRoute UserId
14 | | NotFoundRoute
15 |
16 |
17 | toString : Route -> String
18 | toString route =
19 | let
20 | segments : List String
21 | segments =
22 | case route of
23 | PostsRoute ->
24 | [ "posts" ]
25 |
26 | PostRoute postId ->
27 | [ "posts", postId ]
28 |
29 | UserRoute userId ->
30 | [ "users", userId ]
31 |
32 | NotFoundRoute ->
33 | [ "not-found" ]
34 | in
35 | Url.Builder.absolute segments []
36 |
37 |
38 | fromUrl : Url -> Route
39 | fromUrl url =
40 | Url.Parser.parse parser url
41 | |> Maybe.withDefault NotFoundRoute
42 |
43 |
44 | parser : Parser (Route -> Route) Route
45 | parser =
46 | Url.Parser.oneOf
47 | [ Url.Parser.map PostsRoute Url.Parser.top
48 | , Url.Parser.map PostsRoute <| Url.Parser.s "posts"
49 | , Url.Parser.map PostRoute <| Url.Parser.s "posts" > Url.Parser.string
50 | , Url.Parser.map UserRoute <| Url.Parser.s "users" > Url.Parser.string
51 | , Url.Parser.map NotFoundRoute <| Url.Parser.s "not-found"
52 | ]
53 |
--------------------------------------------------------------------------------
/src/Store.elm:
--------------------------------------------------------------------------------
1 | module Store exposing
2 | ( Store, init
3 | , Action(..), runAction
4 | , Msg(..), update
5 | )
6 |
7 | {-|
8 |
9 | @docs Store, init
10 | @docs Action, runAction
11 | @docs Msg, update
12 |
13 | -}
14 |
15 | import API.Image exposing (Image, ImageId)
16 | import API.Post exposing (Post, PostCreateData, PostId)
17 | import API.User exposing (User, UserId)
18 | import Dict exposing (Dict)
19 | import Http
20 | import RemoteData exposing (RemoteData(..), WebData)
21 |
22 |
23 | type alias Store =
24 | { -- we're loading all posts at once
25 | -- GET /api/posts
26 | posts : WebData (Dict PostId Post)
27 | , -- we're loading all users at once
28 | -- GET /api/users/
29 | users : WebData (Dict UserId User)
30 | , -- we're lazy loading images as needed
31 | -- GET /api/images/
32 | images : Dict ImageId (WebData Image)
33 | }
34 |
35 |
36 | {-| As in, Request
37 | -}
38 | type Action
39 | = GetPosts
40 | | GetUsers
41 | | GetImage ImageId
42 | | CreatePost PostCreateData
43 |
44 |
45 | {-| As in, Response
46 | -}
47 | type Msg
48 | = HttpError Action Http.Error -- !
49 | | GotPosts (List Post)
50 | | GotUsers (List User)
51 | | GotImage Image
52 | | CreatedPost Action Post
53 |
54 |
55 | init : Store
56 | init =
57 | { posts = NotAsked
58 | , users = NotAsked
59 | , images = Dict.empty
60 | }
61 |
62 |
63 | runAction : Action -> Store -> ( Store, Cmd Msg )
64 | runAction action store =
65 | case action of
66 | GetPosts ->
67 | if shouldSendRequest store.posts then
68 | ( { store | posts = Loading }
69 | , send action API.Post.getAll GotPosts
70 | )
71 |
72 | else
73 | ( store, Cmd.none )
74 |
75 | GetUsers ->
76 | if shouldSendRequest store.users then
77 | ( { store | users = Loading }
78 | , send action API.User.getAll GotUsers
79 | )
80 |
81 | else
82 | ( store, Cmd.none )
83 |
84 | GetImage imageId ->
85 | if shouldSendRequest_ (Dict.get imageId store.images) then
86 | ( { store | images = Dict.insert imageId Loading store.images }
87 | , send action (API.Image.get imageId) GotImage
88 | )
89 |
90 | else
91 | ( store, Cmd.none )
92 |
93 | CreatePost postCreateData ->
94 | ( store
95 | , send action (API.Post.create postCreateData) (CreatedPost action)
96 | )
97 |
98 |
99 | shouldSendRequest : WebData a -> Bool
100 | shouldSendRequest webdata =
101 | case webdata of
102 | NotAsked ->
103 | True
104 |
105 | Loading ->
106 | False
107 |
108 | Failure _ ->
109 | False
110 |
111 | Success _ ->
112 | False
113 |
114 |
115 | shouldSendRequest_ : Maybe (WebData a) -> Bool
116 | shouldSendRequest_ maybeWebdata =
117 | case maybeWebdata of
118 | Nothing ->
119 | True
120 |
121 | Just webdata ->
122 | shouldSendRequest webdata
123 |
124 |
125 | send : Action -> ((Result Http.Error a -> Msg) -> Cmd Msg) -> (a -> Msg) -> Cmd Msg
126 | send action toCmd toSuccessMsg =
127 | toCmd
128 | (\result ->
129 | case result of
130 | Err err ->
131 | HttpError action err
132 |
133 | Ok success ->
134 | toSuccessMsg success
135 | )
136 |
137 |
138 | update : Msg -> Store -> ( Store, Cmd Msg )
139 | update msg store =
140 | case msg of
141 | GotPosts posts ->
142 | ( { store | posts = Success (dictByIds posts) }
143 | , Cmd.none
144 | )
145 |
146 | GotUsers users ->
147 | ( { store | users = Success (dictByIds users) }
148 | , Cmd.none
149 | )
150 |
151 | GotImage image ->
152 | ( { store | images = Dict.insert image.id (Success image) store.images }
153 | , Cmd.none
154 | )
155 |
156 | CreatedPost _ post ->
157 | ( { store | posts = RemoteData.map (Dict.insert post.id post) store.posts }
158 | , Cmd.none
159 | )
160 |
161 | HttpError action error ->
162 | ( saveFailure action error store
163 | , Cmd.none
164 | )
165 |
166 |
167 | saveFailure : Action -> Http.Error -> Store -> Store
168 | saveFailure action err store =
169 | case action of
170 | GetPosts ->
171 | { store | posts = Failure err }
172 |
173 | GetUsers ->
174 | { store | users = Failure err }
175 |
176 | GetImage imageId ->
177 | { store | images = Dict.insert imageId (Failure err) store.images }
178 |
179 | CreatePost _ ->
180 | store
181 |
182 |
183 | dictByIds : List { a | id : String } -> Dict String { a | id : String }
184 | dictByIds list =
185 | list
186 | |> List.map (\item -> ( item.id, item ))
187 | |> Dict.fromList
188 |
--------------------------------------------------------------------------------
/src/UI.elm:
--------------------------------------------------------------------------------
1 | module UI exposing (a, blueButton, code, h1, redButton, td, th)
2 |
3 |
4 | td : String
5 | td =
6 | "px-2 border-x border-y border-slate-200"
7 |
8 |
9 | th : String
10 | th =
11 | "px-2 bg-slate-100 border-t border-x border-slate-200"
12 |
13 |
14 | h1 : String
15 | h1 =
16 | "font-bold mb-2 border-b border-b-4 border-slate-200"
17 |
18 |
19 | a : String
20 | a =
21 | "underline text-sky-600 hover:text-sky-500"
22 |
23 |
24 | blueButton : String
25 | blueButton =
26 | "px-4 py-2 font-semibold text-sm bg-sky-500 hover:bg-sky-400 text-white rounded-none shadow-sm hover:shadow-md active:bg-sky-300"
27 |
28 |
29 | redButton : String
30 | redButton =
31 | "px-4 py-2 font-semibold text-sm bg-red-500 hover:bg-red-400 text-white rounded-none shadow-sm hover:shadow-md active:bg-red-300"
32 |
33 |
34 | code : String
35 | code =
36 | "flex p-2 text-xs rounded border-2 border-slate-300 bg-slate-50 whitespace-pre-wrap"
37 |
--------------------------------------------------------------------------------
/src/UI/Toast.elm:
--------------------------------------------------------------------------------
1 | module UI.Toast exposing (failure, sent, success)
2 |
3 | import Html exposing (Html)
4 | import Html.Attributes as Attrs
5 | import Html.Events as Events
6 | import Svg
7 | import Svg.Attributes as SvgAttrs
8 | import UI
9 |
10 |
11 | htmlToast : Html msg -> { close : msg } -> Html msg -> Html msg
12 | htmlToast icon { close } contents =
13 | Html.div
14 | [ Attrs.class "flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow-md dark:text-gray-400 dark:bg-gray-800"
15 | , Attrs.attribute "role" "alert"
16 | ]
17 | [ icon
18 | , Html.div
19 | [ Attrs.class "ml-3" ]
20 | [ contents ]
21 | , Html.button
22 | [ Attrs.type_ "button"
23 | , Attrs.class "ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"
24 | , Attrs.attribute "aria-label" "Close"
25 | , Events.onClick close
26 | ]
27 | [ Html.span [ Attrs.class "sr-only" ] [ Html.text "Close" ]
28 | , Svg.svg
29 | [ SvgAttrs.class "w-5 h-5"
30 | , SvgAttrs.fill "currentColor"
31 | , SvgAttrs.viewBox "0 0 20 20"
32 | ]
33 | [ Svg.path
34 | [ SvgAttrs.fillRule "evenodd"
35 | , SvgAttrs.d "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
36 | , SvgAttrs.clipRule "evenodd"
37 | ]
38 | []
39 | ]
40 | ]
41 | ]
42 |
43 |
44 | textToast : Html msg -> { close : msg } -> String -> Html msg
45 | textToast icon c message =
46 | htmlToast
47 | icon
48 | c
49 | (Html.span
50 | [ Attrs.class "text-sm font-normal" ]
51 | [ Html.text message ]
52 | )
53 |
54 |
55 | success : { close : msg } -> String -> Html msg
56 | success close message =
57 | let
58 | successIcon : Html msg
59 | successIcon =
60 | Html.div
61 | [ Attrs.class "inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200" ]
62 | [ Svg.svg
63 | [ SvgAttrs.class "w-5 h-5"
64 | , SvgAttrs.fill "currentColor"
65 | , SvgAttrs.viewBox "0 0 20 20"
66 | ]
67 | [ Svg.path
68 | [ SvgAttrs.fillRule "evenodd"
69 | , SvgAttrs.d "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
70 | , SvgAttrs.clipRule "evenodd"
71 | ]
72 | []
73 | ]
74 | ]
75 | in
76 | textToast successIcon close message
77 |
78 |
79 | failure : { close : msg, openDetails : msg } -> String -> Html msg
80 | failure c message =
81 | let
82 | content : Html msg
83 | content =
84 | Html.div
85 | [ Attrs.class "text-sm font-normal" ]
86 | [ Html.p [] [ Html.text message ]
87 | , Html.button
88 | [ Events.onClick c.openDetails
89 | , Attrs.class UI.redButton
90 | ]
91 | [ Html.text "Details" ]
92 | ]
93 |
94 | failureIcon : Html msg
95 | failureIcon =
96 | Html.div
97 | [ Attrs.class "inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-red-500 bg-red-100 rounded-lg dark:bg-red-800 dark:text-red-200" ]
98 | [ Svg.svg
99 | [ SvgAttrs.class "w-5 h-5"
100 | , SvgAttrs.fill "currentColor"
101 | , SvgAttrs.viewBox "0 0 20 20"
102 | ]
103 | [ Svg.path
104 | [ SvgAttrs.fillRule "evenodd"
105 | , SvgAttrs.d "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
106 | , SvgAttrs.clipRule "evenodd"
107 | ]
108 | []
109 | ]
110 | ]
111 | in
112 | htmlToast failureIcon { close = c.close } content
113 |
114 |
115 | sent : { close : msg } -> String -> Html msg
116 | sent close message =
117 | let
118 | sentIcon : Html msg
119 | sentIcon =
120 | Html.div
121 | [ Attrs.class "inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200" ]
122 | [ Svg.svg
123 | [ SvgAttrs.class "w-5 h-5 text-blue-600 dark:text-blue-500"
124 | , SvgAttrs.viewBox "0 0 448 512"
125 | ]
126 | [ Svg.path
127 | [ SvgAttrs.fill "currentColor"
128 | , SvgAttrs.d "M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"
129 | ]
130 | []
131 | ]
132 | ]
133 | in
134 | textToast sentIcon close message
135 |
--------------------------------------------------------------------------------
/watch-compile.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | COLOR_OFF="\e[0m";
4 | DIM="\e[2m";
5 |
6 | function compile {
7 | find src -type f -name '*.elm' | xargs elm make --output=/dev/null
8 | }
9 |
10 | function run {
11 | clear;
12 | tput reset;
13 | echo -en "\033c\033[3J";
14 |
15 | echo -en "${DIM}";
16 | date -R;
17 | echo -en "${COLOR_OFF}";
18 |
19 | compile;
20 | }
21 |
22 | run;
23 |
24 | find src -type f -name '*.elm' | xargs chokidar | while read WHATEVER; do
25 | run;
26 | done;
27 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@sindresorhus/is@^2.0.0":
6 | version "2.1.1"
7 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1"
8 | integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==
9 |
10 | "@szmarczak/http-timer@^4.0.0":
11 | version "4.0.6"
12 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
13 | integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
14 | dependencies:
15 | defer-to-connect "^2.0.0"
16 |
17 | "@types/cacheable-request@^6.0.1":
18 | version "6.0.2"
19 | resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
20 | integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==
21 | dependencies:
22 | "@types/http-cache-semantics" "*"
23 | "@types/keyv" "*"
24 | "@types/node" "*"
25 | "@types/responselike" "*"
26 |
27 | "@types/http-cache-semantics@*":
28 | version "4.0.1"
29 | resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
30 | integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
31 |
32 | "@types/json-buffer@~3.0.0":
33 | version "3.0.0"
34 | resolved "https://registry.yarnpkg.com/@types/json-buffer/-/json-buffer-3.0.0.tgz#85c1ff0f0948fc159810d4b5be35bf8c20875f64"
35 | integrity sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==
36 |
37 | "@types/keyv@*", "@types/keyv@^3.1.1":
38 | version "3.1.4"
39 | resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
40 | integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
41 | dependencies:
42 | "@types/node" "*"
43 |
44 | "@types/node@*":
45 | version "17.0.29"
46 | resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.29.tgz#7f2e1159231d4a077bb660edab0fde373e375a3d"
47 | integrity sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==
48 |
49 | "@types/responselike@*":
50 | version "1.0.0"
51 | resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
52 | integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
53 | dependencies:
54 | "@types/node" "*"
55 |
56 | ansi-escapes@^4.2.1:
57 | version "4.3.2"
58 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
59 | integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
60 | dependencies:
61 | type-fest "^0.21.3"
62 |
63 | ansi-regex@^2.0.0:
64 | version "2.1.1"
65 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
66 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
67 |
68 | ansi-regex@^5.0.1:
69 | version "5.0.1"
70 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
71 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
72 |
73 | ansi-styles@^2.2.1:
74 | version "2.2.1"
75 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
76 | integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
77 |
78 | ansi-styles@^4.0.0, ansi-styles@^4.1.0:
79 | version "4.3.0"
80 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
81 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
82 | dependencies:
83 | color-convert "^2.0.1"
84 |
85 | anymatch@^3.0.1, anymatch@~3.1.2:
86 | version "3.1.2"
87 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
88 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
89 | dependencies:
90 | normalize-path "^3.0.0"
91 | picomatch "^2.0.4"
92 |
93 | async-limiter@^1.0.0:
94 | version "1.0.1"
95 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
96 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
97 |
98 | at-least-node@^1.0.0:
99 | version "1.0.0"
100 | resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
101 | integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
102 |
103 | balanced-match@^1.0.0:
104 | version "1.0.2"
105 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
106 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
107 |
108 | base64-js@^1.3.1:
109 | version "1.5.1"
110 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
111 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
112 |
113 | binary-extensions@^2.0.0:
114 | version "2.2.0"
115 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
116 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
117 |
118 | bl@^4.1.0:
119 | version "4.1.0"
120 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
121 | integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
122 | dependencies:
123 | buffer "^5.5.0"
124 | inherits "^2.0.4"
125 | readable-stream "^3.4.0"
126 |
127 | brace-expansion@^1.1.7:
128 | version "1.1.11"
129 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
130 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
131 | dependencies:
132 | balanced-match "^1.0.0"
133 | concat-map "0.0.1"
134 |
135 | braces@^3.0.2, braces@~3.0.2:
136 | version "3.0.2"
137 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
138 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
139 | dependencies:
140 | fill-range "^7.0.1"
141 |
142 | buffer@^5.5.0:
143 | version "5.7.1"
144 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
145 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
146 | dependencies:
147 | base64-js "^1.3.1"
148 | ieee754 "^1.1.13"
149 |
150 | cacheable-lookup@^2.0.0:
151 | version "2.0.1"
152 | resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz#87be64a18b925234875e10a9bb1ebca4adce6b38"
153 | integrity sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==
154 | dependencies:
155 | "@types/keyv" "^3.1.1"
156 | keyv "^4.0.0"
157 |
158 | cacheable-request@^7.0.1:
159 | version "7.0.2"
160 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
161 | integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==
162 | dependencies:
163 | clone-response "^1.0.2"
164 | get-stream "^5.1.0"
165 | http-cache-semantics "^4.0.0"
166 | keyv "^4.0.0"
167 | lowercase-keys "^2.0.0"
168 | normalize-url "^6.0.1"
169 | responselike "^2.0.0"
170 |
171 | chalk@^1.1.1:
172 | version "1.1.3"
173 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
174 | integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
175 | dependencies:
176 | ansi-styles "^2.2.1"
177 | escape-string-regexp "^1.0.2"
178 | has-ansi "^2.0.0"
179 | strip-ansi "^3.0.0"
180 | supports-color "^2.0.0"
181 |
182 | chalk@^4.0.0, chalk@^4.1.0:
183 | version "4.1.2"
184 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
185 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
186 | dependencies:
187 | ansi-styles "^4.1.0"
188 | supports-color "^7.1.0"
189 |
190 | charenc@0.0.2:
191 | version "0.0.2"
192 | resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
193 | integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
194 |
195 | chokidar@3.0.2:
196 | version "3.0.2"
197 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681"
198 | integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==
199 | dependencies:
200 | anymatch "^3.0.1"
201 | braces "^3.0.2"
202 | glob-parent "^5.0.0"
203 | is-binary-path "^2.1.0"
204 | is-glob "^4.0.1"
205 | normalize-path "^3.0.0"
206 | readdirp "^3.1.1"
207 | optionalDependencies:
208 | fsevents "^2.0.6"
209 |
210 | chokidar@^3.5.2:
211 | version "3.5.3"
212 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
213 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
214 | dependencies:
215 | anymatch "~3.1.2"
216 | braces "~3.0.2"
217 | glob-parent "~5.1.2"
218 | is-binary-path "~2.1.0"
219 | is-glob "~4.0.1"
220 | normalize-path "~3.0.0"
221 | readdirp "~3.6.0"
222 | optionalDependencies:
223 | fsevents "~2.3.2"
224 |
225 | cli-cursor@^3.1.0:
226 | version "3.1.0"
227 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
228 | integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
229 | dependencies:
230 | restore-cursor "^3.1.0"
231 |
232 | cli-spinners@^2.5.0:
233 | version "2.6.1"
234 | resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d"
235 | integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==
236 |
237 | clone-response@^1.0.2:
238 | version "1.0.2"
239 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
240 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
241 | dependencies:
242 | mimic-response "^1.0.0"
243 |
244 | clone@^1.0.2:
245 | version "1.0.4"
246 | resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
247 | integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
248 |
249 | color-convert@^2.0.1:
250 | version "2.0.1"
251 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
252 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
253 | dependencies:
254 | color-name "~1.1.4"
255 |
256 | color-name@~1.1.4:
257 | version "1.1.4"
258 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
259 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
260 |
261 | commander@2.17.1:
262 | version "2.17.1"
263 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
264 | integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
265 |
266 | compress-brotli@^1.3.6:
267 | version "1.3.6"
268 | resolved "https://registry.yarnpkg.com/compress-brotli/-/compress-brotli-1.3.6.tgz#64bd6f21f4f3e9841dbac392f4c29218caf5e9d9"
269 | integrity sha512-au99/GqZtUtiCBliqLFbWlhnCxn+XSYjwZ77q6mKN4La4qOXDoLVPZ50iXr0WmAyMxl8yqoq3Yq4OeQNPPkyeQ==
270 | dependencies:
271 | "@types/json-buffer" "~3.0.0"
272 | json-buffer "~3.0.1"
273 |
274 | concat-map@0.0.1:
275 | version "0.0.1"
276 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
277 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
278 |
279 | crocks@0.12.1:
280 | version "0.12.1"
281 | resolved "https://registry.yarnpkg.com/crocks/-/crocks-0.12.1.tgz#cd5d552da2c0291b0fb72c35f7f66751f458d604"
282 | integrity sha512-2qCRJwBmPlRQXzd50k9gt9PaItultOP8lj/cKSH2Eai9aeBuNqAnDuyolAm9TGn6Pw/4BgbxtPJLU1S+tQ4WMQ==
283 |
284 | cross-spawn@5.0.1:
285 | version "5.0.1"
286 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399"
287 | integrity sha1-o7uzAtsil8vqPATt82lB9GE6o5k=
288 | dependencies:
289 | lru-cache "^4.0.1"
290 | shebang-command "^1.2.0"
291 | which "^1.2.9"
292 |
293 | cross-spawn@^6.0.0:
294 | version "6.0.5"
295 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
296 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
297 | dependencies:
298 | nice-try "^1.0.4"
299 | path-key "^2.0.1"
300 | semver "^5.5.0"
301 | shebang-command "^1.2.0"
302 | which "^1.2.9"
303 |
304 | cross-spawn@^7.0.3:
305 | version "7.0.3"
306 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
307 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
308 | dependencies:
309 | path-key "^3.1.0"
310 | shebang-command "^2.0.0"
311 | which "^2.0.1"
312 |
313 | crypt@0.0.2:
314 | version "0.0.2"
315 | resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
316 | integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
317 |
318 | debug@2.6.9:
319 | version "2.6.9"
320 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
321 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
322 | dependencies:
323 | ms "2.0.0"
324 |
325 | debug@^4.1.1:
326 | version "4.3.4"
327 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
328 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
329 | dependencies:
330 | ms "2.1.2"
331 |
332 | decompress-response@^5.0.0:
333 | version "5.0.0"
334 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
335 | integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==
336 | dependencies:
337 | mimic-response "^2.0.0"
338 |
339 | default-gateway@^4.2.0:
340 | version "4.2.0"
341 | resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
342 | integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==
343 | dependencies:
344 | execa "^1.0.0"
345 | ip-regex "^2.1.0"
346 |
347 | defaults@^1.0.3:
348 | version "1.0.3"
349 | resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
350 | integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
351 | dependencies:
352 | clone "^1.0.2"
353 |
354 | defer-to-connect@^2.0.0:
355 | version "2.0.1"
356 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
357 | integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
358 |
359 | depd@~1.1.2:
360 | version "1.1.2"
361 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
362 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
363 |
364 | destroy@~1.0.4:
365 | version "1.0.4"
366 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
367 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
368 |
369 | duplexer3@^0.1.4:
370 | version "0.1.4"
371 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
372 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
373 |
374 | ee-first@1.1.1:
375 | version "1.1.1"
376 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
377 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
378 |
379 | elm-hot@1.1.4:
380 | version "1.1.4"
381 | resolved "https://registry.yarnpkg.com/elm-hot/-/elm-hot-1.1.4.tgz#4984592b3554670255ea4e08f4e98aa9103ab51f"
382 | integrity sha512-qPDP/o/Fkifriaxaf3E7hHFB5L6Ijihyg8is4A6xna6/h/zebUiNssbQrxywI2oxNUkr6W/leEu/WlIC1tmVnw==
383 |
384 | elm-live@^4.0.2:
385 | version "4.0.2"
386 | resolved "https://registry.yarnpkg.com/elm-live/-/elm-live-4.0.2.tgz#c943f348961e406a7963115a3eeb7cfec38cf4d6"
387 | integrity sha512-4I3UvJxF6MubC14VsgtV11B0zBxaaKtdKKsWquoaa5a3UHBIGW83qgTnt/NxOj4omOLfupaftmDaE4yRMTgTcw==
388 | dependencies:
389 | chalk "^1.1.1"
390 | chokidar "3.0.2"
391 | commander "2.17.1"
392 | crocks "0.12.1"
393 | cross-spawn "5.0.1"
394 | elm-hot "1.1.4"
395 | finalhandler "1.1.2"
396 | http-proxy "1.17.0"
397 | internal-ip "4.3.0"
398 | mime "2.4.3"
399 | open "6.4.0"
400 | pem "1.14.2"
401 | serve-static "1.14.1"
402 | ws "7.1.1"
403 |
404 | elm-review@^2.7.2:
405 | version "2.7.2"
406 | resolved "https://registry.yarnpkg.com/elm-review/-/elm-review-2.7.2.tgz#63ca79687bf0317cfaf2e36357b0914e9ce032ab"
407 | integrity sha512-llkRvxgR2GOmtc7wi2vAM+u9j61Pf1fmPsAbpsE4X0ZfusJv0Dddor3lHNNZ0MmpYzNxpm7npxNqYRXs5JIz9A==
408 | dependencies:
409 | chalk "^4.0.0"
410 | chokidar "^3.5.2"
411 | cross-spawn "^7.0.3"
412 | elm-tooling "^1.6.0"
413 | fast-levenshtein "^3.0.0"
414 | find-up "^4.1.0"
415 | folder-hash "^3.3.0"
416 | fs-extra "^9.0.0"
417 | glob "^7.1.4"
418 | got "^10.7.0"
419 | minimist "^1.2.0"
420 | ora "^5.4.0"
421 | path-key "^3.1.1"
422 | prompts "^2.2.1"
423 | strip-ansi "^6.0.0"
424 | temp "^0.9.1"
425 | terminal-link "^2.1.1"
426 | which "^2.0.2"
427 | wrap-ansi "^6.2.0"
428 |
429 | elm-tooling@^1.6.0, elm-tooling@^1.8.0:
430 | version "1.8.0"
431 | resolved "https://registry.yarnpkg.com/elm-tooling/-/elm-tooling-1.8.0.tgz#366870f95c1eb678f89ac8b7608869c7d3e1d86c"
432 | integrity sha512-IjMvW/VHqxLidlJSAocBGDBmqiZ1NS0lK/UCMRU4ULEEaTVjpSd/9Dv0mH2ok0H0egSTYx19GnrdL4Lq9h+z+A==
433 |
434 | emoji-regex@^8.0.0:
435 | version "8.0.0"
436 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
437 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
438 |
439 | encodeurl@~1.0.2:
440 | version "1.0.2"
441 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
442 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
443 |
444 | end-of-stream@^1.1.0:
445 | version "1.4.4"
446 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
447 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
448 | dependencies:
449 | once "^1.4.0"
450 |
451 | es6-promisify@^6.0.0:
452 | version "6.1.1"
453 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
454 | integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==
455 |
456 | escape-html@~1.0.3:
457 | version "1.0.3"
458 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
459 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
460 |
461 | escape-string-regexp@^1.0.2:
462 | version "1.0.5"
463 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
464 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
465 |
466 | etag@~1.8.1:
467 | version "1.8.1"
468 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
469 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
470 |
471 | eventemitter3@^3.0.0:
472 | version "3.1.2"
473 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
474 | integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
475 |
476 | execa@^1.0.0:
477 | version "1.0.0"
478 | resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
479 | integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
480 | dependencies:
481 | cross-spawn "^6.0.0"
482 | get-stream "^4.0.0"
483 | is-stream "^1.1.0"
484 | npm-run-path "^2.0.0"
485 | p-finally "^1.0.0"
486 | signal-exit "^3.0.0"
487 | strip-eof "^1.0.0"
488 |
489 | fast-levenshtein@^3.0.0:
490 | version "3.0.0"
491 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz#37b899ae47e1090e40e3fd2318e4d5f0142ca912"
492 | integrity sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==
493 | dependencies:
494 | fastest-levenshtein "^1.0.7"
495 |
496 | fastest-levenshtein@^1.0.7:
497 | version "1.0.12"
498 | resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
499 | integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
500 |
501 | fill-range@^7.0.1:
502 | version "7.0.1"
503 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
504 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
505 | dependencies:
506 | to-regex-range "^5.0.1"
507 |
508 | finalhandler@1.1.2:
509 | version "1.1.2"
510 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
511 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
512 | dependencies:
513 | debug "2.6.9"
514 | encodeurl "~1.0.2"
515 | escape-html "~1.0.3"
516 | on-finished "~2.3.0"
517 | parseurl "~1.3.3"
518 | statuses "~1.5.0"
519 | unpipe "~1.0.0"
520 |
521 | find-up@^4.1.0:
522 | version "4.1.0"
523 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
524 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
525 | dependencies:
526 | locate-path "^5.0.0"
527 | path-exists "^4.0.0"
528 |
529 | folder-hash@^3.3.0:
530 | version "3.3.3"
531 | resolved "https://registry.yarnpkg.com/folder-hash/-/folder-hash-3.3.3.tgz#883c8359d54f91b3f02c1a646c00c30e5831365b"
532 | integrity sha512-SDgHBgV+RCjrYs8aUwCb9rTgbTVuSdzvFmLaChsLre1yf+D64khCW++VYciaByZ8Rm0uKF8R/XEpXuTRSGUM1A==
533 | dependencies:
534 | debug "^4.1.1"
535 | graceful-fs "~4.2.0"
536 | minimatch "~3.0.4"
537 |
538 | follow-redirects@^1.0.0:
539 | version "1.14.9"
540 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
541 | integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
542 |
543 | fresh@0.5.2:
544 | version "0.5.2"
545 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
546 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
547 |
548 | fs-extra@^9.0.0:
549 | version "9.1.0"
550 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
551 | integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
552 | dependencies:
553 | at-least-node "^1.0.0"
554 | graceful-fs "^4.2.0"
555 | jsonfile "^6.0.1"
556 | universalify "^2.0.0"
557 |
558 | fs.realpath@^1.0.0:
559 | version "1.0.0"
560 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
561 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
562 |
563 | fsevents@^2.0.6, fsevents@~2.3.2:
564 | version "2.3.2"
565 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
566 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
567 |
568 | get-stream@^4.0.0:
569 | version "4.1.0"
570 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
571 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
572 | dependencies:
573 | pump "^3.0.0"
574 |
575 | get-stream@^5.0.0, get-stream@^5.1.0:
576 | version "5.2.0"
577 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
578 | integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
579 | dependencies:
580 | pump "^3.0.0"
581 |
582 | glob-parent@^5.0.0, glob-parent@~5.1.2:
583 | version "5.1.2"
584 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
585 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
586 | dependencies:
587 | is-glob "^4.0.1"
588 |
589 | glob@^7.1.3, glob@^7.1.4:
590 | version "7.2.0"
591 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
592 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
593 | dependencies:
594 | fs.realpath "^1.0.0"
595 | inflight "^1.0.4"
596 | inherits "2"
597 | minimatch "^3.0.4"
598 | once "^1.3.0"
599 | path-is-absolute "^1.0.0"
600 |
601 | got@^10.7.0:
602 | version "10.7.0"
603 | resolved "https://registry.yarnpkg.com/got/-/got-10.7.0.tgz#62889dbcd6cca32cd6a154cc2d0c6895121d091f"
604 | integrity sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==
605 | dependencies:
606 | "@sindresorhus/is" "^2.0.0"
607 | "@szmarczak/http-timer" "^4.0.0"
608 | "@types/cacheable-request" "^6.0.1"
609 | cacheable-lookup "^2.0.0"
610 | cacheable-request "^7.0.1"
611 | decompress-response "^5.0.0"
612 | duplexer3 "^0.1.4"
613 | get-stream "^5.0.0"
614 | lowercase-keys "^2.0.0"
615 | mimic-response "^2.1.0"
616 | p-cancelable "^2.0.0"
617 | p-event "^4.0.0"
618 | responselike "^2.0.0"
619 | to-readable-stream "^2.0.0"
620 | type-fest "^0.10.0"
621 |
622 | graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@~4.2.0:
623 | version "4.2.10"
624 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
625 | integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
626 |
627 | has-ansi@^2.0.0:
628 | version "2.0.0"
629 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
630 | integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
631 | dependencies:
632 | ansi-regex "^2.0.0"
633 |
634 | has-flag@^4.0.0:
635 | version "4.0.0"
636 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
637 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
638 |
639 | http-cache-semantics@^4.0.0:
640 | version "4.1.0"
641 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
642 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
643 |
644 | http-errors@~1.7.2:
645 | version "1.7.3"
646 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
647 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
648 | dependencies:
649 | depd "~1.1.2"
650 | inherits "2.0.4"
651 | setprototypeof "1.1.1"
652 | statuses ">= 1.5.0 < 2"
653 | toidentifier "1.0.0"
654 |
655 | http-proxy@1.17.0:
656 | version "1.17.0"
657 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
658 | integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==
659 | dependencies:
660 | eventemitter3 "^3.0.0"
661 | follow-redirects "^1.0.0"
662 | requires-port "^1.0.0"
663 |
664 | ieee754@^1.1.13:
665 | version "1.2.1"
666 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
667 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
668 |
669 | inflight@^1.0.4:
670 | version "1.0.6"
671 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
672 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
673 | dependencies:
674 | once "^1.3.0"
675 | wrappy "1"
676 |
677 | inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4:
678 | version "2.0.4"
679 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
680 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
681 |
682 | internal-ip@4.3.0:
683 | version "4.3.0"
684 | resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
685 | integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==
686 | dependencies:
687 | default-gateway "^4.2.0"
688 | ipaddr.js "^1.9.0"
689 |
690 | ip-regex@^2.1.0:
691 | version "2.1.0"
692 | resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
693 | integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
694 |
695 | ipaddr.js@^1.9.0:
696 | version "1.9.1"
697 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
698 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
699 |
700 | is-binary-path@^2.1.0, is-binary-path@~2.1.0:
701 | version "2.1.0"
702 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
703 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
704 | dependencies:
705 | binary-extensions "^2.0.0"
706 |
707 | is-buffer@~1.1.6:
708 | version "1.1.6"
709 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
710 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
711 |
712 | is-extglob@^2.1.1:
713 | version "2.1.1"
714 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
715 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
716 |
717 | is-fullwidth-code-point@^3.0.0:
718 | version "3.0.0"
719 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
720 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
721 |
722 | is-glob@^4.0.1, is-glob@~4.0.1:
723 | version "4.0.3"
724 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
725 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
726 | dependencies:
727 | is-extglob "^2.1.1"
728 |
729 | is-interactive@^1.0.0:
730 | version "1.0.0"
731 | resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
732 | integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
733 |
734 | is-number@^7.0.0:
735 | version "7.0.0"
736 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
737 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
738 |
739 | is-stream@^1.1.0:
740 | version "1.1.0"
741 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
742 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
743 |
744 | is-unicode-supported@^0.1.0:
745 | version "0.1.0"
746 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
747 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
748 |
749 | is-wsl@^1.1.0:
750 | version "1.1.0"
751 | resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
752 | integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
753 |
754 | isexe@^2.0.0:
755 | version "2.0.0"
756 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
757 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
758 |
759 | json-buffer@3.0.1, json-buffer@~3.0.1:
760 | version "3.0.1"
761 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
762 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
763 |
764 | jsonfile@^6.0.1:
765 | version "6.1.0"
766 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
767 | integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
768 | dependencies:
769 | universalify "^2.0.0"
770 | optionalDependencies:
771 | graceful-fs "^4.1.6"
772 |
773 | keyv@^4.0.0:
774 | version "4.2.2"
775 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.2.2.tgz#4b6f602c0228ef4d8214c03c520bef469ed6b768"
776 | integrity sha512-uYS0vKTlBIjNCAUqrjlxmruxOEiZxZIHXyp32sdcGmP+ukFrmWUnE//RcPXJH3Vxrni1H2gsQbjHE0bH7MtMQQ==
777 | dependencies:
778 | compress-brotli "^1.3.6"
779 | json-buffer "3.0.1"
780 |
781 | kleur@^3.0.3:
782 | version "3.0.3"
783 | resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
784 | integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
785 |
786 | locate-path@^5.0.0:
787 | version "5.0.0"
788 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
789 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
790 | dependencies:
791 | p-locate "^4.1.0"
792 |
793 | log-symbols@^4.1.0:
794 | version "4.1.0"
795 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
796 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
797 | dependencies:
798 | chalk "^4.1.0"
799 | is-unicode-supported "^0.1.0"
800 |
801 | lowercase-keys@^2.0.0:
802 | version "2.0.0"
803 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
804 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
805 |
806 | lru-cache@^4.0.1:
807 | version "4.1.5"
808 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
809 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
810 | dependencies:
811 | pseudomap "^1.0.2"
812 | yallist "^2.1.2"
813 |
814 | md5@^2.2.1:
815 | version "2.3.0"
816 | resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
817 | integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
818 | dependencies:
819 | charenc "0.0.2"
820 | crypt "0.0.2"
821 | is-buffer "~1.1.6"
822 |
823 | mime@1.6.0:
824 | version "1.6.0"
825 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
826 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
827 |
828 | mime@2.4.3:
829 | version "2.4.3"
830 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
831 | integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
832 |
833 | mimic-fn@^2.1.0:
834 | version "2.1.0"
835 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
836 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
837 |
838 | mimic-response@^1.0.0:
839 | version "1.0.1"
840 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
841 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
842 |
843 | mimic-response@^2.0.0, mimic-response@^2.1.0:
844 | version "2.1.0"
845 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
846 | integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
847 |
848 | minimatch@^3.0.4:
849 | version "3.1.2"
850 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
851 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
852 | dependencies:
853 | brace-expansion "^1.1.7"
854 |
855 | minimatch@~3.0.4:
856 | version "3.0.8"
857 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1"
858 | integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==
859 | dependencies:
860 | brace-expansion "^1.1.7"
861 |
862 | minimist@^1.2.0, minimist@^1.2.6:
863 | version "1.2.6"
864 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
865 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
866 |
867 | mkdirp@^0.5.1:
868 | version "0.5.6"
869 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
870 | integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
871 | dependencies:
872 | minimist "^1.2.6"
873 |
874 | ms@2.0.0:
875 | version "2.0.0"
876 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
877 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
878 |
879 | ms@2.1.1:
880 | version "2.1.1"
881 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
882 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
883 |
884 | ms@2.1.2:
885 | version "2.1.2"
886 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
887 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
888 |
889 | nice-try@^1.0.4:
890 | version "1.0.5"
891 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
892 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
893 |
894 | normalize-path@^3.0.0, normalize-path@~3.0.0:
895 | version "3.0.0"
896 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
897 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
898 |
899 | normalize-url@^6.0.1:
900 | version "6.1.0"
901 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
902 | integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
903 |
904 | npm-run-path@^2.0.0:
905 | version "2.0.2"
906 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
907 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
908 | dependencies:
909 | path-key "^2.0.0"
910 |
911 | on-finished@~2.3.0:
912 | version "2.3.0"
913 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
914 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
915 | dependencies:
916 | ee-first "1.1.1"
917 |
918 | once@^1.3.0, once@^1.3.1, once@^1.4.0:
919 | version "1.4.0"
920 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
921 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
922 | dependencies:
923 | wrappy "1"
924 |
925 | onetime@^5.1.0:
926 | version "5.1.2"
927 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
928 | integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
929 | dependencies:
930 | mimic-fn "^2.1.0"
931 |
932 | open@6.4.0:
933 | version "6.4.0"
934 | resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
935 | integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==
936 | dependencies:
937 | is-wsl "^1.1.0"
938 |
939 | ora@^5.4.0:
940 | version "5.4.1"
941 | resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
942 | integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
943 | dependencies:
944 | bl "^4.1.0"
945 | chalk "^4.1.0"
946 | cli-cursor "^3.1.0"
947 | cli-spinners "^2.5.0"
948 | is-interactive "^1.0.0"
949 | is-unicode-supported "^0.1.0"
950 | log-symbols "^4.1.0"
951 | strip-ansi "^6.0.0"
952 | wcwidth "^1.0.1"
953 |
954 | os-tmpdir@^1.0.1:
955 | version "1.0.2"
956 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
957 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
958 |
959 | p-cancelable@^2.0.0:
960 | version "2.1.1"
961 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
962 | integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
963 |
964 | p-event@^4.0.0:
965 | version "4.2.0"
966 | resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
967 | integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
968 | dependencies:
969 | p-timeout "^3.1.0"
970 |
971 | p-finally@^1.0.0:
972 | version "1.0.0"
973 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
974 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
975 |
976 | p-limit@^2.2.0:
977 | version "2.3.0"
978 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
979 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
980 | dependencies:
981 | p-try "^2.0.0"
982 |
983 | p-locate@^4.1.0:
984 | version "4.1.0"
985 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
986 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
987 | dependencies:
988 | p-limit "^2.2.0"
989 |
990 | p-timeout@^3.1.0:
991 | version "3.2.0"
992 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
993 | integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
994 | dependencies:
995 | p-finally "^1.0.0"
996 |
997 | p-try@^2.0.0:
998 | version "2.2.0"
999 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
1000 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
1001 |
1002 | parseurl@~1.3.3:
1003 | version "1.3.3"
1004 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
1005 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
1006 |
1007 | path-exists@^4.0.0:
1008 | version "4.0.0"
1009 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
1010 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
1011 |
1012 | path-is-absolute@^1.0.0:
1013 | version "1.0.1"
1014 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
1015 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
1016 |
1017 | path-key@^2.0.0, path-key@^2.0.1:
1018 | version "2.0.1"
1019 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
1020 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
1021 |
1022 | path-key@^3.1.0, path-key@^3.1.1:
1023 | version "3.1.1"
1024 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
1025 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
1026 |
1027 | pem@1.14.2:
1028 | version "1.14.2"
1029 | resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.2.tgz#ab29350416bc3a532c30beeee0d541af897fb9ac"
1030 | integrity sha512-TOnPtq3ZFnCniOZ+rka4pk8UIze9xG1qI+wNE7EmkiR/cg+53uVvk5QbkWZ7M6RsuOxzz62FW1hlAobJr/lTOA==
1031 | dependencies:
1032 | es6-promisify "^6.0.0"
1033 | md5 "^2.2.1"
1034 | os-tmpdir "^1.0.1"
1035 | which "^1.3.1"
1036 |
1037 | picomatch@^2.0.4, picomatch@^2.2.1:
1038 | version "2.3.1"
1039 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
1040 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
1041 |
1042 | prompts@^2.2.1:
1043 | version "2.4.2"
1044 | resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
1045 | integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
1046 | dependencies:
1047 | kleur "^3.0.3"
1048 | sisteransi "^1.0.5"
1049 |
1050 | pseudomap@^1.0.2:
1051 | version "1.0.2"
1052 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
1053 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
1054 |
1055 | pump@^3.0.0:
1056 | version "3.0.0"
1057 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
1058 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
1059 | dependencies:
1060 | end-of-stream "^1.1.0"
1061 | once "^1.3.1"
1062 |
1063 | range-parser@~1.2.1:
1064 | version "1.2.1"
1065 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
1066 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
1067 |
1068 | readable-stream@^3.4.0:
1069 | version "3.6.0"
1070 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
1071 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
1072 | dependencies:
1073 | inherits "^2.0.3"
1074 | string_decoder "^1.1.1"
1075 | util-deprecate "^1.0.1"
1076 |
1077 | readdirp@^3.1.1, readdirp@~3.6.0:
1078 | version "3.6.0"
1079 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
1080 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
1081 | dependencies:
1082 | picomatch "^2.2.1"
1083 |
1084 | requires-port@^1.0.0:
1085 | version "1.0.0"
1086 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
1087 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
1088 |
1089 | responselike@^2.0.0:
1090 | version "2.0.0"
1091 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
1092 | integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
1093 | dependencies:
1094 | lowercase-keys "^2.0.0"
1095 |
1096 | restore-cursor@^3.1.0:
1097 | version "3.1.0"
1098 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
1099 | integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
1100 | dependencies:
1101 | onetime "^5.1.0"
1102 | signal-exit "^3.0.2"
1103 |
1104 | rimraf@~2.6.2:
1105 | version "2.6.3"
1106 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
1107 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
1108 | dependencies:
1109 | glob "^7.1.3"
1110 |
1111 | safe-buffer@~5.2.0:
1112 | version "5.2.1"
1113 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1114 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1115 |
1116 | semver@^5.5.0:
1117 | version "5.7.1"
1118 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
1119 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
1120 |
1121 | send@0.17.1:
1122 | version "0.17.1"
1123 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
1124 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
1125 | dependencies:
1126 | debug "2.6.9"
1127 | depd "~1.1.2"
1128 | destroy "~1.0.4"
1129 | encodeurl "~1.0.2"
1130 | escape-html "~1.0.3"
1131 | etag "~1.8.1"
1132 | fresh "0.5.2"
1133 | http-errors "~1.7.2"
1134 | mime "1.6.0"
1135 | ms "2.1.1"
1136 | on-finished "~2.3.0"
1137 | range-parser "~1.2.1"
1138 | statuses "~1.5.0"
1139 |
1140 | serve-static@1.14.1:
1141 | version "1.14.1"
1142 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
1143 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
1144 | dependencies:
1145 | encodeurl "~1.0.2"
1146 | escape-html "~1.0.3"
1147 | parseurl "~1.3.3"
1148 | send "0.17.1"
1149 |
1150 | setprototypeof@1.1.1:
1151 | version "1.1.1"
1152 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
1153 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
1154 |
1155 | shebang-command@^1.2.0:
1156 | version "1.2.0"
1157 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
1158 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
1159 | dependencies:
1160 | shebang-regex "^1.0.0"
1161 |
1162 | shebang-command@^2.0.0:
1163 | version "2.0.0"
1164 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
1165 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
1166 | dependencies:
1167 | shebang-regex "^3.0.0"
1168 |
1169 | shebang-regex@^1.0.0:
1170 | version "1.0.0"
1171 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
1172 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
1173 |
1174 | shebang-regex@^3.0.0:
1175 | version "3.0.0"
1176 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
1177 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
1178 |
1179 | signal-exit@^3.0.0, signal-exit@^3.0.2:
1180 | version "3.0.7"
1181 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
1182 | integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
1183 |
1184 | sisteransi@^1.0.5:
1185 | version "1.0.5"
1186 | resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
1187 | integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
1188 |
1189 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
1190 | version "1.5.0"
1191 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
1192 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
1193 |
1194 | string-width@^4.1.0:
1195 | version "4.2.3"
1196 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1197 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
1198 | dependencies:
1199 | emoji-regex "^8.0.0"
1200 | is-fullwidth-code-point "^3.0.0"
1201 | strip-ansi "^6.0.1"
1202 |
1203 | string_decoder@^1.1.1:
1204 | version "1.3.0"
1205 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
1206 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
1207 | dependencies:
1208 | safe-buffer "~5.2.0"
1209 |
1210 | strip-ansi@^3.0.0:
1211 | version "3.0.1"
1212 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
1213 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
1214 | dependencies:
1215 | ansi-regex "^2.0.0"
1216 |
1217 | strip-ansi@^6.0.0, strip-ansi@^6.0.1:
1218 | version "6.0.1"
1219 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1220 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
1221 | dependencies:
1222 | ansi-regex "^5.0.1"
1223 |
1224 | strip-eof@^1.0.0:
1225 | version "1.0.0"
1226 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
1227 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
1228 |
1229 | supports-color@^2.0.0:
1230 | version "2.0.0"
1231 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
1232 | integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
1233 |
1234 | supports-color@^7.0.0, supports-color@^7.1.0:
1235 | version "7.2.0"
1236 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1237 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1238 | dependencies:
1239 | has-flag "^4.0.0"
1240 |
1241 | supports-hyperlinks@^2.0.0:
1242 | version "2.2.0"
1243 | resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb"
1244 | integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==
1245 | dependencies:
1246 | has-flag "^4.0.0"
1247 | supports-color "^7.0.0"
1248 |
1249 | temp@^0.9.1:
1250 | version "0.9.4"
1251 | resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.4.tgz#cd20a8580cb63635d0e4e9d4bd989d44286e7620"
1252 | integrity sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==
1253 | dependencies:
1254 | mkdirp "^0.5.1"
1255 | rimraf "~2.6.2"
1256 |
1257 | terminal-link@^2.1.1:
1258 | version "2.1.1"
1259 | resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
1260 | integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==
1261 | dependencies:
1262 | ansi-escapes "^4.2.1"
1263 | supports-hyperlinks "^2.0.0"
1264 |
1265 | to-readable-stream@^2.0.0:
1266 | version "2.1.0"
1267 | resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8"
1268 | integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==
1269 |
1270 | to-regex-range@^5.0.1:
1271 | version "5.0.1"
1272 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1273 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1274 | dependencies:
1275 | is-number "^7.0.0"
1276 |
1277 | toidentifier@1.0.0:
1278 | version "1.0.0"
1279 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
1280 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
1281 |
1282 | type-fest@^0.10.0:
1283 | version "0.10.0"
1284 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.10.0.tgz#7f06b2b9fbfc581068d1341ffabd0349ceafc642"
1285 | integrity sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==
1286 |
1287 | type-fest@^0.21.3:
1288 | version "0.21.3"
1289 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
1290 | integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
1291 |
1292 | universalify@^2.0.0:
1293 | version "2.0.0"
1294 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
1295 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
1296 |
1297 | unpipe@~1.0.0:
1298 | version "1.0.0"
1299 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
1300 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
1301 |
1302 | util-deprecate@^1.0.1:
1303 | version "1.0.2"
1304 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1305 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1306 |
1307 | wcwidth@^1.0.1:
1308 | version "1.0.1"
1309 | resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
1310 | integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
1311 | dependencies:
1312 | defaults "^1.0.3"
1313 |
1314 | which@^1.2.9, which@^1.3.1:
1315 | version "1.3.1"
1316 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1317 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1318 | dependencies:
1319 | isexe "^2.0.0"
1320 |
1321 | which@^2.0.1, which@^2.0.2:
1322 | version "2.0.2"
1323 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
1324 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
1325 | dependencies:
1326 | isexe "^2.0.0"
1327 |
1328 | wrap-ansi@^6.2.0:
1329 | version "6.2.0"
1330 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
1331 | integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
1332 | dependencies:
1333 | ansi-styles "^4.0.0"
1334 | string-width "^4.1.0"
1335 | strip-ansi "^6.0.0"
1336 |
1337 | wrappy@1:
1338 | version "1.0.2"
1339 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1340 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
1341 |
1342 | ws@7.1.1:
1343 | version "7.1.1"
1344 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.1.tgz#f9942dc868b6dffb72c14fd8f2ba05f77a4d5983"
1345 | integrity sha512-o41D/WmDeca0BqYhsr3nJzQyg9NF5X8l/UdnFNux9cS3lwB+swm8qGWX5rn+aD6xfBU3rGmtHij7g7x6LxFU3A==
1346 | dependencies:
1347 | async-limiter "^1.0.0"
1348 |
1349 | yallist@^2.1.2:
1350 | version "2.1.2"
1351 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
1352 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
1353 |
--------------------------------------------------------------------------------