From 5a7c53c3f4ab10ada8ba6a8cd44f56f0e2a075cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Hr=C4=8Dek?= Date: Sat, 14 Dec 2019 17:00:03 +0100 Subject: [PATCH] Implement basic elm viewer Former-commit-id: bb096343c7e818db5ac668c5666e6935c1172916 --- reanimate.cabal | 9 +- src/Reanimate/Driver/Server.hs | 39 +- viewer-elm/.gitignore | 3 + viewer-elm/README.md | 15 + viewer-elm/dist/elm.js | 1 + viewer-elm/dist/index.html | 56 ++ viewer-elm/dist/style.css | 34 + viewer-elm/elm.json | 27 + viewer-elm/package-lock.json | 1327 ++++++++++++++++++++++++++++++++ viewer-elm/package.json | 22 + viewer-elm/src/Main.elm | 376 +++++++++ viewer-elm/src/Ports.elm | 9 + 12 files changed, 1896 insertions(+), 22 deletions(-) create mode 100644 viewer-elm/.gitignore create mode 100644 viewer-elm/README.md create mode 100644 viewer-elm/dist/elm.js create mode 100644 viewer-elm/dist/index.html create mode 100644 viewer-elm/dist/style.css create mode 100644 viewer-elm/elm.json create mode 100644 viewer-elm/package-lock.json create mode 100644 viewer-elm/package.json create mode 100644 viewer-elm/src/Main.elm create mode 100644 viewer-elm/src/Ports.elm diff --git a/reanimate.cabal b/reanimate.cabal index 559df00..fbf3a02 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -23,12 +23,9 @@ description: viewer and auto-reloader. -data-files: viewer/build/*.js - viewer/build/*.html - viewer/build/static/js/2.822530b2.chunk.js - viewer/build/static/js/main.b15b405f.chunk.js - viewer/build/static/js/runtime~main.9eb600ee.js - viewer/build/static/css/main.f7ad3e9b.chunk.css +data-files: viewer-elm/dist/index.html + viewer-elm/dist/elm.js + viewer-elm/dist/style.css data/CIExyz.csv data/CIE_XYZ.csv data/cone_sensitivity_lms.csv diff --git a/src/Reanimate/Driver/Server.hs b/src/Reanimate/Driver/Server.hs index ce8934f..932c586 100644 --- a/src/Reanimate/Driver/Server.hs +++ b/src/Reanimate/Driver/Server.hs @@ -9,15 +9,19 @@ import Control.Concurrent.MVar import Control.Exception (SomeException, catch, finally) import Control.Monad import Control.Monad.Fix (fix) +import Data.Hashable (hash) import Data.Text (Text) import qualified Data.Text as T +import qualified Data.Text.IO as T import qualified Data.Text.Read as T import GHC.Environment (getFullArgs) import Network.WebSockets import Paths_reanimate import Reanimate.Misc (runCmdLazy, runCmd_) -import System.Directory (doesFileExist, findFile, +import System.Directory (createDirectoryIfMissing, + doesFileExist, findFile, listDirectory, makeAbsolute, + removeDirectoryRecursive, withCurrentDirectory) import System.Environment (getProgName) import System.Exit @@ -52,61 +56,64 @@ serve = withManager $ \watch -> do then do putStrLn "Already connected to browser. Rejecting." rejectRequestWith pending defaultRejectRequest - else do + else withSystemTempDirectory "reanimate-svgs" $ \tmpDir -> do + createDirectoryIfMissing True tmpDir conn <- acceptRequest pending slave <- newEmptyMVar let handler = modifyMVar_ slave $ \tid -> do putStrLn "Reloading code..." killThread tid - forkIO $ ignoreErrors $ slaveHandler conn self + forkIO $ ignoreErrors $ slaveHandler conn self tmpDir killSlave = do tid <- takeMVar slave killThread tid stop <- watchFile watch self handler putMVar slave =<< forkIO (return ()) + handler let loop = do - -- FIXME: We don't use fps here. - _fps <- receiveData conn :: IO T.Text + -- FIXME: We don't use msg here. + _msg <- receiveData conn :: IO T.Text handler loop - loop `finally` (swapMVar hasConnectionVar False >> stop >> killSlave) + loop `finally` (removeDirectoryRecursive tmpDir >> swapMVar hasConnectionVar False >> stop >> killSlave) ignoreErrors :: IO () -> IO () ignoreErrors action = action `catch` \(_::SomeException) -> return () openViewer :: IO () openViewer = do - url <- getDataFileName "viewer/build/index.html" + url <- getDataFileName "viewer-elm/dist/index.html" putStrLn "Opening browser..." bSucc <- openBrowser url if bSucc then putStrLn "Browser opened." else hPutStrLn stderr $ "Failed to open browser. Manually visit: " ++ url -slaveHandler :: Connection -> FilePath -> IO () -slaveHandler conn self = +slaveHandler :: Connection -> FilePath -> FilePath -> IO () +slaveHandler conn self svgDir = withCurrentDirectory (takeDirectory self) $ withSystemTempDirectory "reanimate" $ \tmpDir -> withTempFile tmpDir "reanimate.exe" $ \tmpExecutable handle -> do hClose handle - sendTextData conn (T.pack "Compiling") + sendTextData conn (T.pack "status\nCompiling") ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions tmpDir ++ [takeFileName self, "-o", tmpExecutable] case ret of Left err -> - sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err)) + sendTextData conn $ T.pack $ "error\n" ++ unlines (drop 3 (lines err)) Right{} -> runCmdLazy tmpExecutable execOpts $ \getFrame -> do (frameCount,_) <- expectFrame =<< getFrame - sendTextData conn (T.pack $ show frameCount) + sendTextData conn (T.pack $ "frame_count\n" ++ show frameCount) fix $ \loop -> do (frameIdx, frame) <- expectFrame =<< getFrame - sendTextData conn (T.pack $ show frameIdx) - sendTextData conn frame + let fileName = svgDir show (hash frame) <.> "svg" + T.writeFile fileName frame + sendTextData conn (T.pack $ "frame\n" ++ show frameIdx ++ "\n" ++ fileName) loop where execOpts = ["raw", "+RTS", "-N", "-M1G", "-RTS"] expectFrame :: Either String Text -> IO (Integer, Text) expectFrame (Left "") = do - sendTextData conn (T.pack "Done") + sendTextData conn (T.pack "status\nDone") exitSuccess expectFrame (Left err) = do sendTextData conn $ T.pack $ "Error" ++ err @@ -116,7 +123,7 @@ slaveHandler conn self = Left err -> do hPutStrLn stderr (T.unpack frame) hPutStrLn stderr $ "expectFrame: " ++ err - sendTextData conn $ T.pack $ "Error" ++ err + sendTextData conn $ T.pack $ "error\n" ++ err exitWith (ExitFailure 1) Right (frameNumber, rest) -> pure (frameNumber, rest) diff --git a/viewer-elm/.gitignore b/viewer-elm/.gitignore new file mode 100644 index 0000000..ce953a4 --- /dev/null +++ b/viewer-elm/.gitignore @@ -0,0 +1,3 @@ +elm-stuff +node_modules +.idea diff --git a/viewer-elm/README.md b/viewer-elm/README.md new file mode 100644 index 0000000..a6c5ac6 --- /dev/null +++ b/viewer-elm/README.md @@ -0,0 +1,15 @@ +# Reanimate - live reload animation previewer + +## Build it +```bash +cd reanimate/elm-viewer +npm install +npm run build +npm run minify +``` + +## Develop it +```bash +npm install +npm run dev-server +``` diff --git a/viewer-elm/dist/elm.js b/viewer-elm/dist/elm.js new file mode 100644 index 0000000..eafe975 --- /dev/null +++ b/viewer-elm/dist/elm.js @@ -0,0 +1 @@ +!function(n){"use strict";function r(n,r,t){return t.a=n,t.f=r,t}function o(t){return r(2,t,function(r){return function(n){return t(r,n)}})}function b(e){return r(3,e,function(t){return function(r){return function(n){return e(t,r,n)}}})}function s(u){return r(4,u,function(e){return function(t){return function(r){return function(n){return u(e,t,r,n)}}}})}function t(i){return r(5,i,function(u){return function(e){return function(t){return function(r){return function(n){return i(u,e,t,r,n)}}}}})}function e(a){return r(6,a,function(i){return function(u){return function(e){return function(t){return function(r){return function(n){return a(i,u,e,t,r,n)}}}}}})}function u(o){return r(7,o,function(a){return function(i){return function(u){return function(e){return function(t){return function(r){return function(n){return o(a,i,u,e,t,r,n)}}}}}}})}function i(f){return r(8,f,function(o){return function(a){return function(i){return function(u){return function(e){return function(t){return function(r){return function(n){return f(o,a,i,u,e,t,r,n)}}}}}}}})}function a(c){return r(9,c,function(f){return function(o){return function(a){return function(i){return function(u){return function(e){return function(t){return function(r){return function(n){return c(f,o,a,i,u,e,t,r,n)}}}}}}}}})}function d(n,r,t){return 2===n.a?n.f(r,t):n(r)(t)}function h(n,r,t,e){return 3===n.a?n.f(r,t,e):n(r)(t)(e)}function l(n,r,t,e,u){return 4===n.a?n.f(r,t,e,u):n(r)(t)(e)(u)}function $(n,r,t,e,u,i){return 5===n.a?n.f(r,t,e,u,i):n(r)(t)(e)(u)(i)}function g(n,r,t,e,u,i,a){return 6===n.a?n.f(r,t,e,u,i,a):n(r)(t)(e)(u)(i)(a)}function m(n,r){for(var t,e=[],u=f(n,r,0,e);u&&(t=e.pop());u=f(t.a,t.b,0,e));return u}function f(n,r,t,e){if(n===r)return!0;if("object"!=typeof n||null===n||null===r)return"function"==typeof n&&D(5),!1;if(100"}function D(n){throw Error("https://github.com/elm/core/blob/1.0.0/hints/"+n+".md")}o(function(n,r){return n+r}),o(function(n,r){return n-r}),o(function(n,r){return n*r}),o(function(n,r){return n/r}),o(function(n,r){return n/r|0}),o(Math.pow),o(function(n,r){return r%n});var S=o(function(n,r){var t=r%n;return 0===n?D(11):0a)return u}var l=t.$;if(4===l){for(var d=t.k;4===d.$;)d=d.k;return n(r,d,e,u,i+1,a,r.elm_event_node_ref)}var h=t.e;var $=r.childNodes;for(var g=0;ga))return u;i=p}return u}(n,r,t,0,0,r.b,e)}function kr(n,r,t,e){return 0===t.length?n:(Ar(n,r,t,e),jr(n,t))}function jr(n,r){for(var t=0;t>n}),o(function(n,r){return r>>>n});function Dr(n){return h(Xr,b(function(n,r,t){return d(Wr,n,t)}),_,n)}function Sr(n){return d(ct,"\n ",d(vt,"\n",n))}function zr(n){return h(st,o(function(n,r){return r+1}),0,n)}function Jr(n){var r=$t(n);return 97<=r&&r<=122}function Mr(n){var r=$t(n);return r<=90&&65<=r}function Rr(n){return Jr(n)||Mr(n)}function qr(n){return Jr(n)||Mr(n)||function(n){var r=$t(n);return r<=57&&48<=r}(n)}function Br(n){return n}function Pr(n){return""===n}function Hr(n){return h(ie,ce(Wr),te(_),n)}var Gr=1,Ur=2,Yr=0,Wr=N,Xr=b(function(n,r,t){for(;;){if(-2===t.$)return r;var e=t.d,u=n,i=h(n,t.b,t.c,h(Xr,n,r,t.e));n=u,r=i,t=e}}),Zr=function(n){return h(Xr,b(function(n,r,t){return d(Wr,w(n,r),t)}),_,n)},Kr=x,Qr=(b(function(t,n,r){var e=r.c,u=r.d,i=o(function(n,r){return h(Kr,n.$?t:i,r,n.a)});return h(Kr,i,h(Kr,t,n,u),e)}),function(n){return{$:1,a:n}}),Vr=o(function(n,r){return{$:3,a:n,b:r}}),nt=o(function(n,r){return{$:0,a:n,b:r}}),rt=o(function(n,r){return{$:1,a:n,b:r}}),tt=function(n){return{$:0,a:n}},et=function(n){return{$:2,a:n}},ut=function(n){return{$:0,a:n}},it={$:1},at=H,ot=vn,ft=function(n){return n+""},ct=o(function(n,r){return d(B,n,L(r))}),vt=o(function(n,r){return T(d(q,n,r))}),st=b(function(n,r,t){for(;;){if(!t.b)return r;var e=t.b,u=n,i=d(n,t.a,r);n=u,r=i,t=e}}),bt=F,lt=b(function(n,r,t){for(;;){if(1<=p(n,r))return t;var e=n,u=r-1,i=d(Wr,r,t);n=e,r=u,t=i}}),dt=o(function(n,r){return h(lt,n,r,_)}),ht=o(function(n,r){return h(bt,n,d(dt,0,zr(r)-1),r)}),$t=function(n){var r=n.charCodeAt(0);return r<55296||56319>1,j(r,r),1&n?j(t,r):t):t}),Yu=o(function(n,r){return h(Uu,n,r,"")}),Wu=b(function(n,r,t){return j(d(Yu,n-Ut(t),function(n){return d(Gu,n,"")}(r)),t)}),Xu=Wn("pre"),Zu=Yn,Ku=s(function(n,r,t,e){var u,i=e.$?Zu(""):d(Hu,T([d(qu,"src",/^\s*(javascript:|data:text\/html)/i.test(u=e.a)?"":u)]),_),a=ft(r),o=Ut(a),f=d(Xu,T([Bu("bar")]),T([Zu("Frame: "+h(Wu,o,"0",ft(n))+" / "+a+" "),t]));return d(Pu,T([Bu("viewer")]),T([i,f]))}),Qu={$:4},Vu=Wn("button"),ni=sn,ri=o(function(n,r){return d(Kn,n,ni(r))})("disabled"),ti=Zn,ei=o(function(n,r){return d(ti,n,{$:0,a:r})}),ui=qu("title"),ii=o(function(n,r){return d(Pu,T([Bu("media-controls")]),T([d(Vu,T([$u(hu(-10)),ri(!n),ui("10 frames back")]),T([Zu("<<")])),d(Vu,T([$u(hu(-1)),ri(!n),ui("1 frame back")]),T([Zu("<")])),n?d(Vu,T([$u(Qu),ri(!n)]),T([Zu("Play")])):d(Vu,T([$u({$:3,a:r}),ri(n)]),T([Zu("Pause")])),d(Vu,T([$u(hu(1)),ri(!n),ui("1 frame forward")]),T([Zu(">")])),d(Vu,T([$u(hu(10)),ri(!n),ui("10 frames forward")]),T([Zu(">>")]))]))}),ai=b(function(n,r,t){var e=d(Ru,t,n),u=d(ii,!1,e);return l(Ku,e,n,u,d(ze,e,r))}),oi=b(function(n,r,t){var e=d(ii,!0,t);return l(Ku,t,n,e,d(ze,t,r))}),fi=o(function(e,n){return h(He,b(function(n,r,t){return d(e,n,r)?h(qe,n,r,t):t}),Ie,n)}),ci=Wn("label"),vi=qu("max"),si=Wn("progress"),bi=qu("value"),li=o(function(n,r){return d(ci,_,T([Zu("Loading frames "),d(si,T([bi(ft(n)),vi(ft(r))]),_)]))}),di=o(function(n,r){for(;;){if(-2===r.$)return n;var t=r.d;n=d(di,n+1,r.e),r=t}}),hi=b(function(n,r,t){var e=d(Ru,t,n),u=d(li,d(di,0,r),n),i=function(n){if(n.b){return ut(n.a)}return it}(gt(function(n){return h(Xr,b(function(n,r,t){return d(Wr,r,t)}),_,n)}(d(fi,o(function(n){return p(n,e)<1}),r))));return l(Ku,e,n,u,i)}),$i=Wn("h1"),gi=Wn("li"),mi=Wn("ul"),pi=ke({ay:function(){return w({A:Ne(0),a:je},Ce)},aF:function(r){return Fe(T([_u((t=$e,function(n){return t(d(ju,ku,n))})),function(){var n=r.a;n:for(;;)switch(n.$){case 4:case 3:return pu(ge);case 6:if(1!==n.a.$)break n;return d(eu,1e3,Le(Te));default:break n}return uu}()]));var t},aH:Mu,aI:function(r){return d(Pu,T([Bu("app")]),T([function(){var n=r.a;switch(n.$){case 0:return Zu("Disconnected");case 1:return Zu("Connected");case 2:return Zu("Compiling..");case 6:return function(n){switch(n.$){case 0:var r=n.a;return d(Pu,_,T([d($i,_,T([Zu("Compilation failed")])),d(Xu,_,T([Zu(r)]))]));case 1:return d(Pu,_,T([Zu("Failed to establish connection. Possible causes include: "),d(mi,_,T([d(gi,_,T([Zu("The reanimate script is not running")])),d(gi,_,T([Zu("At most one viewer window can connect at time. Maybe there's another browser window/tab already connected?")]))]))]));case 2:return Zu("Received 'done' message, but I was not receiving frames!");case 4:return Zu("Failed to decode Port message. The error was: "+wt(n.a));case 5:return Zu("Unexpected message: "+n.a);default:return Zu("Frame indices were not continuous block of number from 0 to "+ft(n.a-1))}}(n.a);case 3:return h(hi,n.a,n.b,r.A);case 4:return h(ai,n.a,n.b,r.A);default:return h(oi,n.a,n.b,n.c)}}()]))}});gu={Main:{init:pi(qt(0))(0)}},n.Elm?function n(r,t){for(var e in t)e in r?"init"==e?D(6):n(r[e],t[e]):r[e]=t[e]}(n.Elm,gu):n.Elm=gu}(this); \ No newline at end of file diff --git a/viewer-elm/dist/index.html b/viewer-elm/dist/index.html new file mode 100644 index 0000000..a8e4187 --- /dev/null +++ b/viewer-elm/dist/index.html @@ -0,0 +1,56 @@ + + + + Reanimate - viewer + + + + + +
+ + + + diff --git a/viewer-elm/dist/style.css b/viewer-elm/dist/style.css new file mode 100644 index 0000000..85582ef --- /dev/null +++ b/viewer-elm/dist/style.css @@ -0,0 +1,34 @@ +body { + padding: 0; + margin: 0; +} + +.app { + height: 100vh; + background-color: #282c34; + color: white; + font-family: monospace; + overflow: hidden; +} + +.viewer { + position: static; +} + +.viewer img { + max-width: 100vw; + max-height: 100vh; + margin-top: auto; + margin-bottom: auto; +} + +.bar { + position: fixed; + top: 0; + margin-top: 0; + width: 100%; +} + +.media-controls { + display: inline-block; +} \ No newline at end of file diff --git a/viewer-elm/elm.json b/viewer-elm/elm.json new file mode 100644 index 0000000..1bbe20e --- /dev/null +++ b/viewer-elm/elm.json @@ -0,0 +1,27 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "bburdette/websocket": "1.0.2", + "elm/browser": "1.0.2", + "elm/core": "1.0.4", + "elm/html": "1.0.0", + "elm/json": "1.1.3", + "elm/time": "1.0.0" + }, + "indirect": { + "NoRedInk/elm-json-decode-pipeline": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2", + "elm-community/list-extra": "8.2.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json new file mode 100644 index 0000000..a92cf4f --- /dev/null +++ b/viewer-elm/package-lock.json @@ -0,0 +1,1327 @@ +{ + "name": "viewer-elm", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "binwrap": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/binwrap/-/binwrap-0.2.2.tgz", + "integrity": "sha512-Y+Wvypk3JhH5GPZAvlwJAWOVH/OsOhQMSj37vySuWHwQivoALplPxfBA8b973rFJI7OS+O+1YmmYXIiEXVMAcw==", + "dev": true, + "requires": { + "mustache": "^3.0.1", + "request": "^2.88.0", + "request-promise": "^4.2.4", + "tar": "^4.4.10", + "unzip-stream": "^0.3.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true + }, + "chokidar": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", + "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", + "dev": true, + "requires": { + "anymatch": "^3.0.1", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", + "normalize-path": "^3.0.0", + "readdirp": "^3.1.1" + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crocks": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/crocks/-/crocks-0.12.1.tgz", + "integrity": "sha512-2qCRJwBmPlRQXzd50k9gt9PaItultOP8lj/cKSH2Eai9aeBuNqAnDuyolAm9TGn6Pw/4BgbxtPJLU1S+tQ4WMQ==", + "dev": true + }, + "cross-spawn": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.0.1.tgz", + "integrity": "sha1-o7uzAtsil8vqPATt82lB9GE6o5k=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "elm": { + "version": "0.19.1-3", + "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-3.tgz", + "integrity": "sha512-6y36ewCcVmTOx8lj7cKJs3bhI5qMfoVEigePZ9PhEUNKpwjjML/pU2u2YSpHVAznuCcojoF6KIsrS1Ci7GtVaQ==", + "requires": { + "request": "^2.88.0" + } + }, + "elm-format": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/elm-format/-/elm-format-0.8.2.tgz", + "integrity": "sha512-BRQaVQOGt9gxK1hqSJn1MISxDGdln22PSYzmHMjqpQY3S9OJY/3kPn5HoiH3bHQYQFwC+X0apsMZldK9VxySow==", + "dev": true, + "requires": { + "binwrap": "^0.2.2" + } + }, + "elm-hot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/elm-hot/-/elm-hot-1.1.1.tgz", + "integrity": "sha512-ZHjoHd2Ev6riNXNQirj3J+GKKXXwedAUikfFBYzlVL/+3CdGs96cpZ7nhAk4c5l//Qa9ymltrqX36mOlr0pPFA==", + "dev": true + }, + "elm-live": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/elm-live/-/elm-live-4.0.1.tgz", + "integrity": "sha512-IlonaC1pO/QoXlOrwwrJaxyvpJAT8QDSfzenkChbhU1PC1fJetkj2TwZfki+y1ZxpSMTnMSomMraOdWA6DO3VQ==", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "chokidar": "3.0.2", + "commander": "2.17.1", + "crocks": "0.12.1", + "cross-spawn": "5.0.1", + "elm-hot": "1.1.1", + "finalhandler": "1.1.2", + "http-proxy": "1.17.0", + "internal-ip": "4.3.0", + "mime": "2.4.3", + "open": "6.4.0", + "pem": "1.14.2", + "serve-static": "1.14.1", + "ws": "7.1.1" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + } + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es6-promisify": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.0.2.tgz", + "integrity": "sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "follow-redirects": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "dev": true, + "requires": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, + "mime": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", + "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==", + "dev": true + }, + "mime-db": { + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" + }, + "mime-types": { + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "requires": { + "mime-db": "1.42.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mustache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.1.0.tgz", + "integrity": "sha512-3Bxq1R5LBZp7fbFPZzFe5WN4s0q3+gxZaZuZVY+QctYJiCiVgXHOTIC0/HgZuOPFt/6BQcx5u0H2CUOxT/RoGQ==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "pem": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/pem/-/pem-1.14.2.tgz", + "integrity": "sha512-TOnPtq3ZFnCniOZ+rka4pk8UIze9xG1qI+wNE7EmkiR/cg+53uVvk5QbkWZ7M6RsuOxzz62FW1hlAobJr/lTOA==", + "dev": true, + "requires": { + "es6-promisify": "^6.0.0", + "md5": "^2.2.1", + "os-tmpdir": "^1.0.1", + "which": "^1.3.1" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", + "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", + "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uglify-js": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", + "dev": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unzip-stream": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.0.tgz", + "integrity": "sha512-NG1h/MdGIX3HzyqMjyj1laBCmlPYhcO4xEy7gEqqzGiSLw7XqDQCnY4nYSn5XSaH8mQ6TFkaujrO8d/PIZN85A==", + "dev": true, + "requires": { + "binary": "^0.3.0", + "mkdirp": "^0.5.1" + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.1.tgz", + "integrity": "sha512-o41D/WmDeca0BqYhsr3nJzQyg9NF5X8l/UdnFNux9cS3lwB+swm8qGWX5rn+aD6xfBU3rGmtHij7g7x6LxFU3A==", + "dev": true, + "requires": { + "async-limiter": "^1.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } +} diff --git a/viewer-elm/package.json b/viewer-elm/package.json new file mode 100644 index 0000000..feefab6 --- /dev/null +++ b/viewer-elm/package.json @@ -0,0 +1,22 @@ +{ + "name": "viewer-elm", + "version": "0.1.0", + "description": "Animation preview ui for reanimate", + "main": "", + "scripts": { + "build": "elm make src/Main.elm --optimize --output dist/elm.js", + "dev-server": "elm-live --open --dir=dist --start-page=index.html src/Main.elm -- --output dist/elm.js", + "format": "elm-format --yes .", + "minify": "uglifyjs dist/elm.js --compress \"pure_funcs='F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9',pure_getters,keep_fargs=false,unsafe_comps,unsafe\" | uglifyjs --mangle --output=dist/elm.js" + }, + "author": "", + "license": "Unlicense", + "dependencies": { + "elm": "^0.19.1-3" + }, + "devDependencies": { + "elm-format": "^0.8.2", + "elm-live": "^4.0.1", + "uglify-js": "^3.7.2" + } +} diff --git a/viewer-elm/src/Main.elm b/viewer-elm/src/Main.elm new file mode 100644 index 0000000..6cb95a7 --- /dev/null +++ b/viewer-elm/src/Main.elm @@ -0,0 +1,376 @@ +module Main exposing (main) + +import Browser +import Browser.Events +import Dict exposing (Dict) +import Html exposing (Html) +import Html.Attributes as Attr exposing (class, disabled, src, style, title, value) +import Html.Events exposing (onClick) +import Json.Decode +import Platform.Sub +import Ports +import Time exposing (Posix, millisToPosix, posixToMillis) +import WebSocket + + +main : Program () Model Msg +main = + Browser.element + { init = init + , update = update + , view = view + , subscriptions = subscriptions + } + + +subscriptions : Model -> Sub Msg +subscriptions model = + Platform.Sub.batch + [ Ports.receiveSocketMsg (WebSocket.receive MessageReceived) + , case model.status of + AnimationRunning _ _ -> + Browser.Events.onAnimationFrame TimestampReceived + + ReceivingFrames _ _ -> + Browser.Events.onAnimationFrame TimestampReceived + + SomethingWentWrong ConnectionFailed -> + Time.every 1000 (always AttemptReconnect) + + _ -> + Sub.none + ] + + +type Msg + = MessageReceived (Result Json.Decode.Error WebSocket.WebSocketMsg) + | TimestampReceived Posix + | AttemptReconnect + | PauseClicked Int + | PlayClicked + | SeekClicked Int + + +type Status + = Disconnected + | Connected + | Compiling + | ReceivingFrames Int Frames + | AnimationRunning Int Frames + | AnimationPaused Int Frames Int + | SomethingWentWrong Problem + + +type Problem + = CompilationError String + | ConnectionFailed + | DoneWithoutFrames + | FramesMissing Int + | PortMessageDecodeFailure Json.Decode.Error + | UnexpectedMessage String + + +type alias Model = + { status : Status + , clock : Posix + } + + +type alias Frames = + Dict Int String + + +init : () -> ( Model, Cmd Msg ) +init _ = + ( { status = Disconnected + , clock = millisToPosix 0 + } + , connectCommand + ) + + +connectCommand : Cmd msg +connectCommand = + WebSocket.send Ports.sendSocketCommand <| + WebSocket.Connect + { name = "TheSocket" + , address = "ws://localhost:9161" + , protocol = "" + } + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + AttemptReconnect -> + ( model, connectCommand ) + + TimestampReceived clock -> + ( { model | clock = clock }, Cmd.none ) + + MessageReceived result -> + ( processResult result model, Cmd.none ) + + PauseClicked frameIndex -> + ( case model.status of + AnimationRunning frameCount frames -> + { model | status = AnimationPaused frameCount frames frameIndex } + + _ -> + model + , Cmd.none + ) + + PlayClicked -> + ( case model.status of + AnimationPaused frameCount frames _ -> + { model | status = AnimationRunning frameCount frames } + + _ -> + model + , Cmd.none + ) + + SeekClicked delta -> + ( case model.status of + AnimationPaused frameCount frames frameIndex -> + { model | status = AnimationPaused frameCount frames (modBy frameCount (frameIndex + delta)) } + + _ -> + model + , Cmd.none + ) + + +processResult : Result Json.Decode.Error WebSocket.WebSocketMsg -> Model -> Model +processResult result model = + case result of + Err decodeError -> + { model | status = SomethingWentWrong (PortMessageDecodeFailure decodeError) } + + Ok wsMsg -> + case wsMsg of + WebSocket.Error { error } -> + { model | status = SomethingWentWrong (UnexpectedMessage error) } + + WebSocket.Data { data } -> + processMessage data model + + +processMessage : String -> Model -> Model +processMessage data model = + case String.lines data of + [ "connection established" ] -> + { model | status = Connected } + + [ "connection failed" ] -> + somethingWentWrong ConnectionFailed model + + [ "status", status ] -> + case status of + "Compiling" -> + { model | status = Compiling } + + "Done" -> + case model.status of + ReceivingFrames frameCount frames -> + if Dict.keys frames == List.range 0 (frameCount - 1) then + { model | status = AnimationRunning frameCount frames } + + else + somethingWentWrong (FramesMissing frameCount) model + + _ -> + somethingWentWrong DoneWithoutFrames model + + _ -> + somethingWentWrong (UnexpectedMessage ("Unknown status: '" ++ status ++ "'")) model + + "error" :: errorLines -> + somethingWentWrong (CompilationError (String.join "\n" errorLines)) model + + [ "frame_count", n ] -> + case String.toInt n of + Just frameCount -> + { model | status = ReceivingFrames frameCount Dict.empty } + + Nothing -> + somethingWentWrong (UnexpectedMessage ("frame_count wasn't number, but '" ++ n ++ "'")) model + + [ "frame", n, svgUrl ] -> + case String.toInt n of + Just frameIndex -> + case model.status of + ReceivingFrames frameCount frames -> + { model | status = ReceivingFrames frameCount (Dict.insert frameIndex svgUrl frames) } + + _ -> + somethingWentWrong (UnexpectedMessage "Got 'frame' message while not ReceivingFrames") model + + Nothing -> + somethingWentWrong (UnexpectedMessage ("Frame index wasn't number, but '" ++ n ++ "'")) model + + _ -> + somethingWentWrong (UnexpectedMessage data) model + + +somethingWentWrong : Problem -> Model -> Model +somethingWentWrong what model = + { model | status = SomethingWentWrong what } + + +view : Model -> Html Msg +view model = + Html.div [ class "app" ] + [ case model.status of + Disconnected -> + Html.text "Disconnected" + + Connected -> + Html.text "Connected" + + Compiling -> + Html.text "Compiling.." + + SomethingWentWrong problem -> + problemView problem + + ReceivingFrames frameCount frames -> + preliminaryAnimationView frameCount frames model.clock + + AnimationRunning frameCount frames -> + animationView frameCount frames model.clock + + AnimationPaused frameCount frames frameIndex -> + manualControlsView frameCount frames frameIndex + ] + + +frameIndexAt : Posix -> Int -> Int +frameIndexAt now frameCount = + (posixToMillis now * 60) // 1000 |> modBy frameCount + + +preliminaryAnimationView : Int -> Frames -> Posix -> Html Msg +preliminaryAnimationView frameCount frames clock = + let + frameIndex = + frameIndexAt clock frameCount + + bestFrame = + List.head (List.reverse (Dict.values (Dict.filter (\x _ -> x <= frameIndex) frames))) + + controls = + progressView (Dict.size frames) frameCount + in + frameView frameIndex frameCount controls bestFrame + + +animationView : Int -> Frames -> Posix -> Html Msg +animationView frameCount frames clock = + let + frameIndex = + frameIndexAt clock frameCount + + controls = + playControls False frameIndex + in + Dict.get frameIndex frames + |> frameView frameIndex frameCount controls + + +manualControlsView : Int -> Frames -> Int -> Html Msg +manualControlsView frameCount frames frameIndex = + let + controls = + playControls True frameIndex + in + Dict.get frameIndex frames + |> frameView frameIndex frameCount controls + + +playControls : Bool -> Int -> Html Msg +playControls paused frameIndex = + Html.div [ class "media-controls" ] + [ Html.button [ onClick (SeekClicked -10), disabled (not paused), title "10 frames back" ] [ Html.text "<<" ] + , Html.button [ onClick (SeekClicked -1), disabled (not paused), title "1 frame back" ] [ Html.text "<" ] + , if paused then + Html.button [ onClick PlayClicked, disabled (not paused) ] [ Html.text "Play" ] + + else + Html.button [ onClick (PauseClicked frameIndex), disabled paused ] [ Html.text "Pause" ] + , Html.button [ onClick (SeekClicked 1), disabled (not paused), title "1 frame forward" ] [ Html.text ">" ] + , Html.button [ onClick (SeekClicked 10), disabled (not paused), title "10 frames forward" ] [ Html.text ">>" ] + ] + + +frameView : Int -> Int -> Html Msg -> Maybe String -> Html Msg +frameView frameIndex frameCount controls maybeSvgUrl = + let + image = + case maybeSvgUrl of + Just svgUrl -> + Html.img [ src svgUrl ] [] + + Nothing -> + Html.text "" + + frameCountStr = + String.fromInt frameCount + + digitCount = + String.length frameCountStr + + bar = + Html.pre [ class "bar" ] + [ Html.text ("Frame: " ++ String.padLeft digitCount '0' (String.fromInt frameIndex) ++ " / " ++ frameCountStr ++ " ") + , controls + ] + in + Html.div [ class "viewer" ] + [ image + , bar + ] + + +progressView : Int -> Int -> Html msg +progressView receivedFrames frameCount = + Html.label [] + [ Html.text "Loading frames " + , Html.progress + [ value (String.fromInt receivedFrames) + , Attr.max (String.fromInt frameCount) + ] + [] + ] + + +problemView : Problem -> Html msg +problemView problem = + case problem of + CompilationError error -> + Html.div [] + [ Html.h1 [] [ Html.text "Compilation failed" ] + , Html.pre [] [ Html.text error ] + ] + + ConnectionFailed -> + Html.div [] + [ Html.text "Failed to establish connection. Possible causes include: " + , Html.ul [] + [ Html.li [] [ Html.text "The reanimate script is not running" ] + , Html.li [] [ Html.text "At most one viewer window can connect at time. Maybe there's another browser window/tab already connected?" ] + ] + ] + + DoneWithoutFrames -> + Html.text "Received 'done' message, but I was not receiving frames!" + + PortMessageDecodeFailure decodeError -> + Html.text ("Failed to decode Port message. The error was: " ++ Json.Decode.errorToString decodeError) + + UnexpectedMessage problemDescription -> + Html.text ("Unexpected message: " ++ problemDescription) + + FramesMissing frameCount -> + Html.text ("Frame indices were not continuous block of number from 0 to " ++ String.fromInt (frameCount - 1)) diff --git a/viewer-elm/src/Ports.elm b/viewer-elm/src/Ports.elm new file mode 100644 index 0000000..fddb112 --- /dev/null +++ b/viewer-elm/src/Ports.elm @@ -0,0 +1,9 @@ +port module Ports exposing (receiveSocketMsg, sendSocketCommand) + +import Json.Decode exposing (Value) + + +port receiveSocketMsg : (Value -> msg) -> Sub msg + + +port sendSocketCommand : Value -> Cmd msg