From 87e883931c98a7171d325758aa01b6eab9e3a760 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 8 Mar 2019 16:36:25 +0100 Subject: [PATCH] Better caching, bundle viewer. --- examples/latex_color.hs | 1 + reanimate.cabal | 13 +- src/Reanimate/Cache.hs | 81 +++++++ src/Reanimate/Driver.hs | 101 ++++---- src/Reanimate/LaTeX.hs | 74 ++---- src/Reanimate/Monad.hs | 9 +- src/Reanimate/Render.hs | 4 +- stack.yaml | 2 +- viewer/.gitignore | 23 ++ viewer/build/asset-manifest.json | 13 ++ viewer/build/favicon.ico | Bin 0 -> 3870 bytes viewer/build/index.html | 1 + viewer/build/manifest.json | 15 ++ ...nifest.15b8d497ab10704d87b84878b92d08cf.js | 22 ++ viewer/build/service-worker.js | 34 +++ .../build/static/css/main.6efe09fd.chunk.css | 2 + .../static/css/main.6efe09fd.chunk.css.map | 1 + viewer/build/static/js/2.772a56e7.chunk.js | 2 + .../build/static/js/2.772a56e7.chunk.js.map | 1 + viewer/build/static/js/main.db22f45d.chunk.js | 2 + .../static/js/main.db22f45d.chunk.js.map | 1 + .../build/static/js/runtime~main.9eb600ee.js | 2 + .../static/js/runtime~main.9eb600ee.js.map | 1 + viewer/package-lock.json | 27 --- viewer/package.json | 3 +- viewer/src/App.jsx | 28 +-- viewer/src/Presets.jsx | 217 ------------------ 27 files changed, 295 insertions(+), 385 deletions(-) create mode 100644 src/Reanimate/Cache.hs create mode 100755 viewer/.gitignore create mode 100644 viewer/build/asset-manifest.json create mode 100755 viewer/build/favicon.ico create mode 100644 viewer/build/index.html create mode 100755 viewer/build/manifest.json create mode 100644 viewer/build/precache-manifest.15b8d497ab10704d87b84878b92d08cf.js create mode 100644 viewer/build/service-worker.js create mode 100644 viewer/build/static/css/main.6efe09fd.chunk.css create mode 100644 viewer/build/static/css/main.6efe09fd.chunk.css.map create mode 100644 viewer/build/static/js/2.772a56e7.chunk.js create mode 100644 viewer/build/static/js/2.772a56e7.chunk.js.map create mode 100644 viewer/build/static/js/main.db22f45d.chunk.js create mode 100644 viewer/build/static/js/main.db22f45d.chunk.js.map create mode 100644 viewer/build/static/js/runtime~main.9eb600ee.js create mode 100644 viewer/build/static/js/runtime~main.9eb600ee.js.map delete mode 100644 viewer/src/Presets.jsx diff --git a/examples/latex_color.hs b/examples/latex_color.hs index c4309ad..605ef8f 100755 --- a/examples/latex_color.hs +++ b/examples/latex_color.hs @@ -1,5 +1,6 @@ #!/usr/bin/env stack -- stack --resolver lts-11.22 runghc --package reanimate +{-# LANGUAGE OverloadedStrings #-} module Main (main) where import Control.Lens diff --git a/reanimate.cabal b/reanimate.cabal index 6ff586c..16dc069 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -13,6 +13,14 @@ build-type: Simple extra-source-files: ChangeLog.md cabal-version: >=1.10 +data-files: viewer/build/*.js + viewer/build/*.html + viewer/build/static/js/2.772a56e7.chunk.js + viewer/build/static/js/main.db22f45d.chunk.js + viewer/build/static/js/runtime~main.9eb600ee.js + viewer/build/static/css/main.6efe09fd.chunk.css + + library hs-source-dirs: src default-language: Haskell2010 @@ -28,12 +36,15 @@ library Reanimate.Driver Reanimate.Misc other-modules: Reanimate.Svg.NamedColors + Reanimate.Cache + Paths_reanimate build-depends: base >=4.10 && <4.13, time, text, unix, filepath, process, directory, containers, reanimate-svg >= 0.7.0.0, xml, bytestring, lens, linear, mtl, matrix, JuicyPixels, attoparsec, parallel, diagrams, diagrams-svg, diagrams-core, diagrams-lib, diagrams-contrib, - svg-builder, matrices, cubicbezier, palette, hinotify, websockets + svg-builder, matrices, cubicbezier, palette, hinotify, websockets, + hashable Flag gtk-viewer Description: Enable gtk-based viewer diff --git a/src/Reanimate/Cache.hs b/src/Reanimate/Cache.hs new file mode 100644 index 0000000..69f5c81 --- /dev/null +++ b/src/Reanimate/Cache.hs @@ -0,0 +1,81 @@ +module Reanimate.Cache + ( cacheMem + , cacheDisk + , cacheDiskSvg + , cacheDiskLines + ) where + +import Control.Exception +import Data.Hashable +import Data.IORef +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.IO as T +import Graphics.SvgTree (Tree (..), parseSvgFile, unparse) +import Reanimate.Monad (renderTree) +import Reanimate.Svg (unbox) +import Text.XML.Light ( Content(..), parseXML ) +import System.Directory +import System.FilePath +import System.IO.Unsafe + +-- Memory cache and disk cache + +cacheDisk :: (T.Text -> Maybe a) -> (a -> T.Text) -> (Text -> IO a) -> (Text -> IO a) +cacheDisk parse render gen key = do + root <- getXdgDirectory XdgCache "reanimate" + createDirectoryIfMissing True root + let path = root show (hash key) + hit <- doesFileExist path + if hit + then do + inp <- T.readFile path + case parse inp of + Nothing -> do + let tmp = path <.> "tmp" + new <- gen key + T.writeFile tmp (render new) + renameFile tmp path + return new + Just val -> pure val + else do + let tmp = path <.> "tmp" + new <- gen key + T.writeFile tmp (render new) + renameFile tmp path + return new + +cacheDiskSvg :: (Text -> IO Tree) -> (Text -> IO Tree) +cacheDiskSvg = cacheDisk parse render + where + parse txt = case parseXML txt of + [Elem t] -> Just (unparse t) + _ -> Nothing + render = T.pack . renderTree + +cacheDiskLines :: (Text -> IO [Text]) -> (Text -> IO [Text]) +cacheDiskLines = cacheDisk parse render + where + parse = Just . T.lines + render = T.unlines + + +{-# NOINLINE cache #-} +cache :: IORef (Map Text Tree) +cache = unsafePerformIO (newIORef Map.empty) + +cacheMem :: (Text -> IO Tree) -> (Text -> IO Tree) +cacheMem gen key = do + store <- readIORef cache + case Map.lookup key store of + Just svg -> return svg + Nothing -> do + svg <- gen key + case svg of + -- None usually indicates that latex or another tool was misconfigured. In this case, + -- don't store the result. + None -> pure None + _ -> atomicModifyIORef cache (\store -> (Map.insert key svg store, svg)) diff --git a/src/Reanimate/Driver.hs b/src/Reanimate/Driver.hs index 7e29306..5a2464f 100644 --- a/src/Reanimate/Driver.hs +++ b/src/Reanimate/Driver.hs @@ -11,10 +11,12 @@ import System.INotify (EventVariety (..), addWatch, withINotify) import System.IO (BufferMode (..), hPutStrLn, hSetBuffering, stderr, stdin) -import Reanimate.Misc (runCmdLazy, runCmd_, withTempFile) +import Reanimate.Misc (runCmdLazy, runCmd, runCmd_, withTempDir, withTempFile) import Reanimate.Monad (Animation) import Reanimate.Render (renderSvgs) +import Paths_reanimate + opts = defaultConnectionOptions { connectionCompressionOptions = PermessageDeflateCompression defaultPermessageDeflate } @@ -24,50 +26,55 @@ reanimate animation = do hSetBuffering stdin NoBuffering case args of ["once"] -> renderSvgs animation - _ -> runServerWith "127.0.0.1" 9161 opts $ \pending -> do - putStrLn "Server pending." - prog <- getProgName - lst <- listDirectory "." - mbSelf <- findFile ("." : lst) prog - blocker <- newEmptyMVar :: IO (MVar ()) - case mbSelf of - Nothing -> do - hPutStrLn stderr "Failed to find own source code." - Just self -> withINotify $ \notify -> do - conn <- acceptRequest pending - slave <- newEmptyMVar - let handler = modifyMVar_ slave $ \tid -> do - sendTextData conn (T.pack "Compiling") - putStrLn "Kill and respawn." - killThread tid - tid <- forkIO $ withTempFile ".exe" $ \tmpExecutable -> do - ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions ++ [self, "-o", tmpExecutable] - case ret of - Left err -> - sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err)) - Right{} -> do - getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M200M", "-RTS"] - flip fix [] $ \loop acc -> do - frame <- getFrame - case frame of - Left "" -> do - sendTextData conn (T.pack "Done") - -- insertCache msg (reverse acc) - Left err -> do - -- _ <- getChanContents queue - sendTextData conn $ T.pack $ "Error" ++ err - Right frame -> do - sendTextData conn frame - loop (frame : acc) - return tid - putStrLn "Found self. Listening." - addWatch notify [Modify] self (const handler) - putMVar slave =<< forkIO (return ()) - let loop = do - fps <- receiveData conn :: IO T.Text - handler - loop - loop + _ -> withTempDir $ \tmpDir -> do + url <- getDataFileName "viewer/build/index.html" + runCmd "xdg-open" [url] + runServerWith "127.0.0.1" 9161 opts $ \pending -> do + putStrLn "Server pending." + prog <- getProgName + lst <- listDirectory "." + mbSelf <- findFile ("." : lst) prog + blocker <- newEmptyMVar :: IO (MVar ()) + case mbSelf of + Nothing -> do + hPutStrLn stderr "Failed to find own source code." + Just self -> withINotify $ \notify -> do + conn <- acceptRequest pending + slave <- newEmptyMVar + let handler = modifyMVar_ slave $ \tid -> do + sendTextData conn (T.pack "Compiling") + putStrLn "Kill and respawn." + killThread tid + tid <- forkIO $ withTempFile ".exe" $ \tmpExecutable -> do + ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions tmpDir ++ [self, "-o", tmpExecutable] + case ret of + Left err -> + sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err)) + Right{} -> do + getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M200M", "-RTS"] + flip fix [] $ \loop acc -> do + frame <- getFrame + case frame of + Left "" -> do + sendTextData conn (T.pack "Done") + -- insertCache msg (reverse acc) + Left err -> do + -- _ <- getChanContents queue + sendTextData conn $ T.pack $ "Error" ++ err + Right frame -> do + sendTextData conn frame + loop (frame : acc) + return tid + putStrLn "Found self. Listening." + addWatch notify [Modify] self (const handler) + putMVar slave =<< forkIO (return ()) + let loop = do + fps <- receiveData conn :: IO T.Text + handler + loop + loop -ghcOptions :: [String] -ghcOptions = ["-rtsopts", "--make", "-threaded", "-O2"] +ghcOptions :: FilePath -> [String] +ghcOptions tmpDir = + ["-rtsopts", "--make", "-threaded", "-O2"] ++ + ["-odir", tmpDir, "-hidir", tmpDir] diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index aed8c6c..b6c8219 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -7,74 +7,36 @@ import qualified Data.ByteString as B import Data.IORef import Data.Map (Map) import qualified Data.Map as Map +import Data.Monoid +import Reanimate.Cache import Reanimate.Misc import Reanimate.Svg import System.FilePath (replaceExtension, takeFileName, ()) import System.IO.Unsafe (unsafePerformIO) import Control.Lens (over, set, (%~), (&), (.~), (^.)) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as T import Graphics.SvgTree (Document (..), Tree (..), defaultSvg, elements, loadSvgFile, parseSvgFile, xmlOfDocument) import Text.XML.Light (elContent) import Text.XML.Light.Output (ppcContent, ppcElement, prettyConfigPP) --- instance ToHtml Document where --- toHtml = toHtmlRaw --- toHtmlRaw = toHtmlRaw . ppcElement prettyConfigPP . xmlOfDocument +latex :: T.Text -> Tree +latex tex = (unsafePerformIO . (cacheMem . cacheDiskSvg) latexToSVG) + ("% plain latex\n" <> tex) --- instance ToHtml Document where --- toHtml = toHtmlRaw --- toHtmlRaw doc = toHtmlRaw $ unlines $ map (ppcContent prettyConfigPP) (elContent elt) --- where --- elt = xmlOfDocument doc --- --- instance ToHtml Tree where --- toHtml = toHtmlRaw --- toHtmlRaw tree = toHtmlRaw doc --- where --- doc = Document --- { _viewBox = Nothing --- , _width = Nothing --- , _height = Nothing --- , _elements = [tree] --- , _definitions = Map.empty --- , _description = "" --- , _styleRules = [] --- , _documentLocation = "" --- } +xelatex :: Text -> Tree +xelatex tex = (unsafePerformIO . (cacheMem . cacheDiskSvg) latexToSVG) + ("% xelatex\n" <> tex) -{-# NOINLINE cache #-} -cache :: IORef (Map String Tree) -cache = unsafePerformIO (newIORef Map.empty) - -latex :: String -> Tree -latex tex = unsafePerformIO $ do - store <- readIORef cache - case Map.lookup tex store of - Just svg -> return svg - Nothing -> do - svg <- latexToSVG tex - case svg of - None -> pure None - _ -> atomicModifyIORef cache (\store -> (Map.insert tex svg store, svg)) - -xelatex :: String -> Tree -xelatex tex = unsafePerformIO $ do - store <- readIORef cache - case Map.lookup tex store of - Just svg -> return svg - Nothing -> do - svg <- xelatexToSVG tex - case svg of - None -> pure None - _ -> atomicModifyIORef cache (\store -> (Map.insert tex svg store, svg)) - -latexAlign :: String -> Tree -latexAlign tex = latex $ unlines ["\\begin{align*}", tex, "\\end{align*}"] +latexAlign :: Text -> Tree +latexAlign tex = latex $ T.unlines ["\\begin{align*}", tex, "\\end{align*}"] -latexToSVG :: String -> IO Tree +latexToSVG :: Text -> IO Tree latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do latex <- requireExecutable "latex" dvisvgm <- requireExecutable "dvisvgm" @@ -82,7 +44,7 @@ latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do let dvi_file = tmp_dir replaceExtension (takeFileName tex_file) "dvi" writeFile tex_file tex_document appendFile tex_file tex_prologue - appendFile tex_file tex + T.appendFile tex_file tex appendFile tex_file tex_epilogue runCmd latex ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file] runCmd dvisvgm [ dvi_file @@ -95,7 +57,7 @@ latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do Nothing -> error "Malformed svg" Just svg -> return $ unbox $ replaceUses svg -xelatexToSVG :: String -> IO Tree +xelatexToSVG :: Text -> IO Tree xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do latex <- requireExecutable "xelatex" dvisvgm <- requireExecutable "dvisvgm" @@ -104,7 +66,7 @@ xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do writeFile tex_file tex_document appendFile tex_file tex_xelatex appendFile tex_file tex_prologue - appendFile tex_file tex + T.appendFile tex_file tex appendFile tex_file tex_epilogue runCmd latex ["-no-pdf", "-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file] runCmd dvisvgm [ dvi_file @@ -117,7 +79,7 @@ xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do Nothing -> error "Malformed svg" Just svg -> return $ unbox $ replaceUses svg -failedSvg :: String -> Tree +failedSvg :: Text -> Tree failedSvg tex = defaultSvg -- text_ [ font_size_ "20" -- , fill_ "white"] (toHtml $ "bad latex: "++tex) diff --git a/src/Reanimate/Monad.hs b/src/Reanimate/Monad.hs index cb4cbff..54b1c39 100644 --- a/src/Reanimate/Monad.hs +++ b/src/Reanimate/Monad.hs @@ -10,8 +10,7 @@ import Data.Monoid ((<>)) import Data.Text (Text, pack) import Graphics.SvgTree (Document (..), Number (..), Text (..), TextSpan (..), TextSpanContent (..), - Tree, Tree (..), xmlOfDocument) -import Reanimate.LaTeX + Tree, Tree (..), xmlOfDocument, xmlOfTree) import Reanimate.Svg import Text.XML.Light (elContent) import Text.XML.Light.Output @@ -101,10 +100,10 @@ frameAt :: Double -> Animation -> Tree frameAt t (Animation d (Frame f)) = mkGroup $ execState (f d (min d t)) id [] renderTree :: Tree -> String -renderTree = renderSizedTree Nothing Nothing +renderTree t = maybe "" ppElement $ xmlOfTree t -renderSizedTree :: Maybe Number -> Maybe Number -> Tree -> String -renderSizedTree w h t = ppElement $ xmlOfDocument doc +renderSvg :: Maybe Number -> Maybe Number -> Tree -> String +renderSvg w h t = ppElement $ xmlOfDocument doc where width = 320 height = width / (16/9) diff --git a/src/Reanimate/Render.hs b/src/Reanimate/Render.hs index 42de400..cd913f5 100644 --- a/src/Reanimate/Render.hs +++ b/src/Reanimate/Render.hs @@ -25,7 +25,7 @@ renderSvgs ani = do where frames = [0..frameCount-1] rate = 60 - nthFrame nth = renderTree $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani + nthFrame nth = renderSvg Nothing Nothing $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani frameCount = round (duration ani * fromIntegral rate) :: Int nameTemplate :: String nameTemplate = "render-%05d.svg" @@ -88,7 +88,7 @@ renderFormat format ani target = do -- XXX: Use threads generateFrames ani width_ rate action = withTempDir $ \tmp -> do let frameName nth = tmp printf nameTemplate nth - rendered = [ renderSizedTree width height $ nthFrame n | n <- frames] + rendered = [ renderSvg width height $ nthFrame n | n <- frames] `using` parBuffer 16 rdeepseq forM_ (zip [0::Int ..] rendered) $ \(n, frame) -> do writeFile (frameName n) frame diff --git a/stack.yaml b/stack.yaml index 746b31f..475f9c1 100644 --- a/stack.yaml +++ b/stack.yaml @@ -3,7 +3,7 @@ resolver: lts-11.22 allow-newer: false extra-deps: -- reanimate-svg-0.8.1.0 +- reanimate-svg-0.8.2.0 - diagrams-1.4@sha256:3e36369e84115b900fd9dcb570672a188339a470eb19ca62170775cd835cf8ca - diagrams-contrib-1.4.3@sha256:bcfa6c85f8c33b8c48c3a61b7216afdebd51cd793c50da3a2dd358827d25fc76 - diagrams-core-1.4.1.1@sha256:6ef6b17785d77997c481eb085570e21b6a00cc91d086fbf49490504130ebc7d1 diff --git a/viewer/.gitignore b/viewer/.gitignore new file mode 100755 index 0000000..58b21fe --- /dev/null +++ b/viewer/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +# /build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/viewer/build/asset-manifest.json b/viewer/build/asset-manifest.json new file mode 100644 index 0000000..720fb8b --- /dev/null +++ b/viewer/build/asset-manifest.json @@ -0,0 +1,13 @@ +{ + "main.css": "./static/css/main.6efe09fd.chunk.css", + "main.js": "./static/js/main.db22f45d.chunk.js", + "main.js.map": "./static/js/main.db22f45d.chunk.js.map", + "runtime~main.js": "./static/js/runtime~main.9eb600ee.js", + "runtime~main.js.map": "./static/js/runtime~main.9eb600ee.js.map", + "static/js/2.772a56e7.chunk.js": "./static/js/2.772a56e7.chunk.js", + "static/js/2.772a56e7.chunk.js.map": "./static/js/2.772a56e7.chunk.js.map", + "index.html": "./index.html", + "precache-manifest.15b8d497ab10704d87b84878b92d08cf.js": "./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js", + "service-worker.js": "./service-worker.js", + "static/css/main.6efe09fd.chunk.css.map": "./static/css/main.6efe09fd.chunk.css.map" +} \ No newline at end of file diff --git a/viewer/build/favicon.ico b/viewer/build/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..a11777cc471a4344702741ab1c8a588998b1311a GIT binary patch literal 3870 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ literal 0 HcmV?d00001 diff --git a/viewer/build/index.html b/viewer/build/index.html new file mode 100644 index 0000000..602bc31 --- /dev/null +++ b/viewer/build/index.html @@ -0,0 +1 @@ +Reanimate Playground
\ No newline at end of file diff --git a/viewer/build/manifest.json b/viewer/build/manifest.json new file mode 100755 index 0000000..1f2f141 --- /dev/null +++ b/viewer/build/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/viewer/build/precache-manifest.15b8d497ab10704d87b84878b92d08cf.js b/viewer/build/precache-manifest.15b8d497ab10704d87b84878b92d08cf.js new file mode 100644 index 0000000..598c317 --- /dev/null +++ b/viewer/build/precache-manifest.15b8d497ab10704d87b84878b92d08cf.js @@ -0,0 +1,22 @@ +self.__precacheManifest = [ + { + "revision": "9eb600ee07a27cdad64f", + "url": "./static/js/runtime~main.9eb600ee.js" + }, + { + "revision": "db22f45d36ec0c1e28c1", + "url": "./static/js/main.db22f45d.chunk.js" + }, + { + "revision": "772a56e764e5091f7538", + "url": "./static/js/2.772a56e7.chunk.js" + }, + { + "revision": "db22f45d36ec0c1e28c1", + "url": "./static/css/main.6efe09fd.chunk.css" + }, + { + "revision": "8912fe90ce5c625516525c7cd80ee665", + "url": "./index.html" + } +]; \ No newline at end of file diff --git a/viewer/build/service-worker.js b/viewer/build/service-worker.js new file mode 100644 index 0000000..50254d2 --- /dev/null +++ b/viewer/build/service-worker.js @@ -0,0 +1,34 @@ +/** + * Welcome to your Workbox-powered service worker! + * + * You'll need to register this file in your web app and you should + * disable HTTP caching for this file too. + * See https://goo.gl/nhQhGp + * + * The rest of the code is auto-generated. Please don't update this file + * directly; instead, make changes to your Workbox build configuration + * and re-run your build process. + * See https://goo.gl/2aRDsh + */ + +importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); + +importScripts( + "./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js" +); + +workbox.clientsClaim(); + +/** + * The workboxSW.precacheAndRoute() method efficiently caches and responds to + * requests for URLs in the manifest. + * See https://goo.gl/S9QRab + */ +self.__precacheManifest = [].concat(self.__precacheManifest || []); +workbox.precaching.suppressWarnings(); +workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); + +workbox.routing.registerNavigationRoute("./index.html", { + + blacklist: [/^\/_/,/\/[^\/]+\.[^\/]+$/], +}); diff --git a/viewer/build/static/css/main.6efe09fd.chunk.css b/viewer/build/static/css/main.6efe09fd.chunk.css new file mode 100644 index 0000000..f72534c --- /dev/null +++ b/viewer/build/static/css/main.6efe09fd.chunk.css @@ -0,0 +1,2 @@ +body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.App{height:100vh;background-color:#282c34;color:#fff;display:grid;grid-template-columns:1fr;grid-template-rows:auto;grid-auto-flow:column;-webkit-align-items:center;align-items:center;overflow:hidden}.controls{text-align:center}.controls svg{padding-left:5px;padding-right:5px}.viewer{position:static}.viewer svg{max-width:100vw;max-height:100vh;margin-top:auto;margin-bottom:auto}div.messages{position:fixed;top:0;width:100%;background:#282c34}div.messages pre{margin:0}.home{color:#fff;text-align:center;float:right;margin-right:2em} +/*# sourceMappingURL=main.6efe09fd.chunk.css.map */ \ No newline at end of file diff --git a/viewer/build/static/css/main.6efe09fd.chunk.css.map b/viewer/build/static/css/main.6efe09fd.chunk.css.map new file mode 100644 index 0000000..cb65b85 --- /dev/null +++ b/viewer/build/static/css/main.6efe09fd.chunk.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["/home/lemmih/Coding/Haskell/reanimate/viewer/src/index.css","main.6efe09fd.chunk.css","/home/lemmih/Coding/Haskell/reanimate/viewer/src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAA,CACA,SAAA,CACA,mICEY,CDCZ,kCAAA,CACA,iCCCF,CDEA,KACE,uECEF,CCbA,KAGE,YAAA,CACA,wBAAA,CACA,UAAA,CACA,YAAA,CACA,yBAAA,CACA,uBAAA,CAEA,qBAAA,CACA,0BAAA,CAAA,kBAAA,CACA,eDiBF,CCZA,UACE,iBDiBF,CCfA,cACE,gBAAA,CACA,iBDiBF,CCfA,QACE,eDiBF,CCfA,YACE,eAAA,CACA,gBAAA,CACA,eAAA,CACA,kBDiBF,CCfA,aACE,cAAA,CACA,KAAA,CACA,UAAA,CACA,kBDiBF,CCfA,iBACE,QDiBF,CCfA,MACE,UAAA,CACA,iBAAA,CACA,WAAA,CACA,gBDiBF","file":"main.6efe09fd.chunk.css","sourcesContent":["body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n","body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\n.App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n -webkit-align-items: center;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n\n",".App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n"]} \ No newline at end of file diff --git a/viewer/build/static/js/2.772a56e7.chunk.js b/viewer/build/static/js/2.772a56e7.chunk.js new file mode 100644 index 0000000..b128397 --- /dev/null +++ b/viewer/build/static/js/2.772a56e7.chunk.js @@ -0,0 +1,2 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],[function(e,t,n){"use strict";e.exports=n(11)},function(e,t,n){"use strict";function r(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}n.d(t,"a",function(){return r})},function(e,t,n){"use strict";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e){for(var t=1;tR.length&&R.push(e)}function U(e,t,n){return null==e?0:function e(t,n,r,l){var a=typeof t;"undefined"!==a&&"boolean"!==a||(t=null);var u=!1;if(null===t)u=!0;else switch(a){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case i:case o:u=!0}}if(u)return r(l,t,""===n?"."+D(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var c=0;cthis.eventPool.length&&this.eventPool.push(e)}function fe(e){e.eventPool=[],e.getPooled=ce,e.release=se}l(ue.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!==typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=oe)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!==typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=oe)},persist:function(){this.isPersistent=oe},isPersistent:ae,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=ae,this._dispatchInstances=this._dispatchListeners=null}}),ue.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},ue.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var i=new t;return l(i,n.prototype),n.prototype=i,n.prototype.constructor=n,n.Interface=l({},r.Interface,e),n.extend=r.extend,fe(n),n},fe(ue);var de=ue.extend({data:null}),pe=ue.extend({data:null}),me=[9,13,27,32],he=$&&"CompositionEvent"in window,ye=null;$&&"documentMode"in document&&(ye=document.documentMode);var ve=$&&"TextEvent"in window&&!ye,ge=$&&(!he||ye&&8=ye),be=String.fromCharCode(32),ke={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},we=!1;function xe(e,t){switch(e){case"keyup":return-1!==me.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function Te(e){return"object"===typeof(e=e.detail)&&"data"in e?e.data:null}var Se=!1;var _e={eventTypes:ke,extractEvents:function(e,t,n,r){var l=void 0,i=void 0;if(he)e:{switch(e){case"compositionstart":l=ke.compositionStart;break e;case"compositionend":l=ke.compositionEnd;break e;case"compositionupdate":l=ke.compositionUpdate;break e}l=void 0}else Se?xe(e,n)&&(l=ke.compositionEnd):"keydown"===e&&229===n.keyCode&&(l=ke.compositionStart);return l?(ge&&"ko"!==n.locale&&(Se||l!==ke.compositionStart?l===ke.compositionEnd&&Se&&(i=ie()):(re="value"in(ne=r)?ne.value:ne.textContent,Se=!0)),l=de.getPooled(l,t,n,r),i?l.data=i:null!==(i=Te(n))&&(l.data=i),H(l),i=l):i=null,(e=ve?function(e,t){switch(e){case"compositionend":return Te(t);case"keypress":return 32!==t.which?null:(we=!0,be);case"textInput":return(e=t.data)===be&&we?null:e;default:return null}}(e,n):function(e,t){if(Se)return"compositionend"===e||!he&&xe(e,t)?(e=ie(),le=re=ne=null,Se=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1