Shpadoinkle-backend-snabbdom 0.3.0.1 → 0.3.0.2
raw patch · 5 files changed
+259/−143 lines, 5 filesdep +containers
Dependencies added: containers
Files
- CHANGELOG.md +0/−0
- README.md +20/−4
- Shpadoinkle-backend-snabbdom.cabal +36/−28
- Shpadoinkle/Backend/Snabbdom.hs +181/−78
- Shpadoinkle/Backend/Snabbdom/Setup.js +22/−33
− CHANGELOG.md
README.md view
@@ -1,6 +1,6 @@ # Shpadoinkle Backend Snabbdom -[](https://gitlab.com/fresheyeball/Shpadoinkle)+[](https://gitlab.com/platonic/shpadoinkle) [](https://shpadoinkle.org/backend-snabbdom) [](https://opensource.org/licenses/BSD-3-Clause) [](https://builtwithnix.org)@@ -12,7 +12,23 @@ > Snabbdom consists of an extremely simple, performant, and extensible core that is only ≈ 200 SLOC. It offers a modular architecture with rich functionality for extensions through custom modules. To keep the core simple, all non-essential functionality is delegated to modules. -These design decisions made Snabbdom a good fit for Shpadoinkle's first high-performance pure JavaScript backend. Right now Snabbdom is being provided using [CloudFlare](https://cdnjs.com/) content delivery network (CDN) and is not included in this repo. This is great for getting started fast and having a transparent developer experience where you can simply switch to the backend of your choosing. However, this is not a stable long term approach as the CDN artifact could be removed at any time. If you wish to use Snabbdom in production, I recommend either:+These design decisions made Snabbdom a good fit for Shpadoinkle's first high-performance pure JavaScript backend. Right now Snabbdom is being provided statically, and a [slightly modified build](https://github.com/fresheyeball/snabbdom) is included in this repo. Although this increases the size of the resulting executable, it's necessary for reproducible and stable builds. -- Proactively monitoring the CDN endpoints-- Wrap `SnabbdomT` in your own `newtype` and overriding the `setup` method in the `Backend` instance with a mechanism where you provide Snabbdom's JavaScript artifacts yourself.+# Building++In order to re-build `Shpadoinkle/Backend/Snabbdom/Setup.js`, it needs to be bundled with a tool like [parcel](https://parceljs.org/) - the following methodology is how it's currently done:++```bash+# clone outside the source directory of Shpadoinkl+git clone git@github.com:snabbdom/snabbdom.git+# compile its typescript so we can bundle the javascript+cd snabbdom && npm install && npm run compile+# Setup_src.js imports the snabbdom sources locally, so we need to manually move it+cp path-to-shpadoinkle/backends/snabbdom/Shpadoinkle/Backend/Snabbdom/Setup_src.js build/package/+# nix is most reliable for running parcel+nix-shell -p nodePackages.parcel-bundler --command "parcel build build/package/Setup_src.js"+# copy the bundled output as Setup.js+cp dist/Setup_src.js path-to-shpadoinkle/backends/snabbdom/Shpadoinkle/Backend/Snabbdom/Setup.js+```++Now when you build your shpadoinkle project, this new `Setup.js` will be statically allocated with your GHCJS output.
Shpadoinkle-backend-snabbdom.cabal view
@@ -1,41 +1,48 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.33.0.------ see: https://github.com/sol/hpack------ hash: 69cf96a52080c262156727e824b26eaebddc6ac0713edcc0f367f821161c934b--name: Shpadoinkle-backend-snabbdom-version: 0.3.0.1-synopsis: Use the high-performance Snabbdom virtual dom library written in JavaScript.-description: Snabbdom is a battle-tested virtual DOM library for JavaScript. It's extremely fast, lean, and modular. Snabbdom's design makes Snabbdom a natural choice for a Shpadoinkle rendering backend, as it has a similar core philosophy of "just don't do much" and is friendly to purely functional binding.-category: Web-author: Isaac Shapira-maintainer: fresheyeball@protonmail.com-license: BSD3-license-file: LICENSE-build-type: Simple+cabal-version: 2.2+name: Shpadoinkle-backend-snabbdom+version: 0.3.0.2+category: Web+author: Isaac Shapira+maintainer: isaac.shapira@platonic.systems+license: BSD-3-Clause+license-file: LICENSE+build-type: Simple extra-source-files:- README.md- CHANGELOG.md- Shpadoinkle/Backend/Snabbdom/Setup.js+ README.md+ Shpadoinkle/Backend/Snabbdom/Setup.js+synopsis:+ Use the high-performance Snabbdom virtual dom library written in JavaScript.+description:+ Snabbdom is a battle-tested virtual DOM library for JavaScript. It's extremely+ fast, lean, and modular. Snabbdom's design makes Snabbdom a natural choice for a+ Shpadoinkle rendering backend, as it has a similar core philosophy of+ "just don't do much" and is friendly to purely functional binding. + source-repository head type: git- location: https://gitlab.com/fresheyeball/Shpadoinkle.git+ location: https://gitlab.com/platonic/shpadoinkle.git + library exposed-modules:- Shpadoinkle.Backend.Snabbdom- other-modules:- Paths_Shpadoinkle_backend_snabbdom- hs-source-dirs:- ./.- ghc-options: -Wall -Wcompat -fwarn-redundant-constraints -fwarn-incomplete-uni-patterns -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-identities+ Shpadoinkle.Backend.Snabbdom++ hs-source-dirs: .++ ghc-options:+ -Wall+ -Wcompat+ -fwarn-redundant-constraints+ -fwarn-incomplete-uni-patterns+ -fwarn-tabs+ -fwarn-incomplete-record-updates+ -fwarn-identities+ build-depends: Shpadoinkle , base >=4.12.0 && <4.16+ , containers , exceptions , file-embed >=0.0.11 && <0.1 , ghcjs-dom >=0.9.4 && <0.20@@ -45,4 +52,5 @@ , text >=1.2.3 && <1.3 , transformers-base , unliftio >=0.2.12 && <0.3+ default-language: Haskell2010
Shpadoinkle/Backend/Snabbdom.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE FlexibleInstances #-}@@ -7,6 +8,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-}@@ -30,31 +32,51 @@ import Control.Category ((.))+#ifdef ghcjs_HOST_OS+import Control.Monad (join)+#endif import Control.Monad.Base (MonadBase (..), liftBaseDefault)-import Control.Monad.Catch (MonadCatch, MonadThrow)+import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)+import Control.Monad.Cont (MonadCont)+import Control.Monad.Except (MonadError) import Control.Monad.Reader (MonadIO, MonadReader (..), MonadTrans, ReaderT (..), forM_,- void, (>=>))+ void)+import Control.Monad.State (MonadState) import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..), MonadTransControl, defaultLiftBaseWith, defaultRestoreM)+import Control.Monad.Writer (MonadWriter) import Data.FileEmbed (embedStringFile)-import Data.Text (Text, split)-import Data.Traversable (for)+import Data.Map.Internal (Map (Bin, Tip))+import Data.Text (Text, isPrefixOf, words) import GHCJS.DOM (currentDocumentUnchecked) import GHCJS.DOM.Document (createElement, getBodyUnsafe)-import GHCJS.DOM.Element (setAttribute)+import GHCJS.DOM.Element (setAttribute, setInnerHTML) import GHCJS.DOM.Node (appendChild)-import Language.Javascript.JSaddle hiding (JSM, MonadJSM, liftJSM,- (#))-import Prelude hiding (id, (.))+#ifndef ghcjs_HOST_OS+import Language.Javascript.JSaddle (FromJSVal (..), JSVal, Object,+ ToJSVal (..), create, eval, fun,+ function, jsTrue, jsg1, jsg2,+ jsg3, toJSBool, toJSString,+ unsafeGetProp, unsafeSetProp,+ valMakeText, valToObject)+#else+import Language.Javascript.JSaddle (FromJSVal (..), JSVal, Object,+ ToJSVal (..), create, eval, fun,+ function, jsTrue, toJSBool,+ toJSString, unsafeGetProp,+ unsafeSetProp, valMakeText,+ valToObject)+#endif+import Prelude hiding (id, words, (.)) import UnliftIO (MonadUnliftIO (..), TVar, UnliftIO (UnliftIO, unliftIO), withUnliftIO) import UnliftIO.Concurrent (forkIO) -import Shpadoinkle hiding (children, name, props)+import Shpadoinkle default (Text)@@ -71,14 +93,22 @@ , Applicative , Monad , MonadIO- , MonadReader (TVar model) , MonadTrans , MonadTransControl , MonadThrow , MonadCatch+ , MonadMask+ , MonadWriter w+ , MonadState s+ , MonadError e+ , MonadCont ) +snabbAsk :: Monad m => SnabbdomT model m (TVar model)+snabbAsk = Snabbdom ask++ #ifndef ghcjs_HOST_OS deriving instance MonadJSM m => MonadJSM (SnabbdomT model m) #endif@@ -88,6 +118,11 @@ liftBase = liftBaseDefault +instance MonadReader r m => MonadReader r (SnabbdomT a m) where+ ask = Snabbdom . ReaderT $ const ask+ local f (Snabbdom rs) = Snabbdom $ ReaderT $ local f . runReaderT rs++ instance MonadBaseControl n m => MonadBaseControl n (SnabbdomT model m) where type StM (SnabbdomT model m) a = ComposeSt (SnabbdomT model) m a liftBaseWith = defaultLiftBaseWith@@ -111,54 +146,79 @@ runSnabbdom t (Snabbdom r) = runReaderT r t -props :: Monad m => (m ~> JSM) -> TVar a -> [(Text, Prop (SnabbdomT a m) a)] -> JSM Object-props toJSM i xs = do+traverseWithKey_ :: Applicative t => (k -> a -> t ()) -> Map k a -> t ()+traverseWithKey_ f = go+ where+ go Tip = pure ()+ go (Bin 1 k v _ _) = f k v+ go (Bin _ k v l r) = go l *> f k v *> go r+{-# INLINE traverseWithKey_ #-}+{-# SPECIALIZE traverseWithKey_ :: (k -> a -> JSM ()) -> Map k a -> JSM () #-}+++insertHook :: Text -> JSVal -> Object -> JSM ()+#ifndef ghcjs_HOST_OS+insertHook t f' hooksObj = void $ jsg3 "insertHook" t f' hooksObj+#else+insertHook t f' hooksObj = join $ insertHook' <$> toJSVal t <*> pure f' <*> toJSVal hooksObj+foreign import javascript unsafe "window['insertHook']($1,$2,$3)" insertHook' :: JSVal -> JSVal -> JSVal -> JSM ()+#endif+++{-# SPECIALIZE props :: NFData a => (JSM ~> JSM) -> TVar a -> Props (SnabbdomT a JSM) a -> JSM Object #-}+props :: Monad m => NFData a => (m ~> JSM) -> TVar a -> Props (SnabbdomT a m) a -> JSM Object+props toJSM i (Props xs) = do o <- create propsObj <- create listenersObj <- create classesObj <- create attrsObj <- create hooksObj <- create- void $ xs `for` \(k, p) -> case p of- PData d -> unsafeSetProp (toJSString k) d propsObj- PPotato pot -> do- f' <- toJSVal . fun $ \_ _ ->- let- g vnode = do- vnode' <- valToObject vnode- stm <- pot . RawNode =<< unsafeGetProp "elm" vnode'- let go = atomically stm >>= writeUpdate i . hoist (toJSM . runSnabbdom i)- void $ forkIO go- in \case- [vnode] -> g vnode- [_, vnode] -> g vnode- _ -> return ()- unsafeSetProp "insert" f' hooksObj- unsafeSetProp "update" f' hooksObj-- PText t -> do- t' <- toJSVal t- true <- toJSVal True- case k of- "className" | t /= "" -> forM_ (split (== ' ') t) $ \u ->- if u == mempty then pure () else unsafeSetProp (toJSString u) true classesObj- "style" | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj- "type" | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj- "autofocus" | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj- _ -> unsafeSetProp (toJSString k) t' propsObj+ flip traverseWithKey_ xs $ \k p ->+ let k' = toJSString k+ in case p of+ PData d -> unsafeSetProp k' d propsObj+ PPotato pot -> do+ f' <- toJSVal . fun $ \_ _ ->+ let+ g vnode'' = do+ vnode_ <- valToObject vnode''+ stm <- pot . RawNode =<< unsafeGetProp "elm" vnode_+ let go = atomically stm >>= writeUpdate i . hoist (toJSM . runSnabbdom i)+ void $ forkIO go+ in \case+ [vnode_] -> g vnode_+ [_, vnode_] -> g vnode_+ _ -> return ()+ insertHook "insert" f' hooksObj+ insertHook "update" f' hooksObj+ PText t+ | k == "className" -> forM_ (words t) $ \u ->+ unsafeSetProp (toJSString u) jsTrue classesObj+ | t /= "" -> do+ t' <- valMakeText t+ unsafeSetProp k' t' $ case k of+ "style" -> attrsObj+ "type" -> attrsObj+ "autofocus" -> attrsObj+ "checked" -> attrsObj+ d | "data-" `isPrefixOf` d -> attrsObj+ _ -> propsObj+ | otherwise -> do+ t' <- valMakeText t+ unsafeSetProp k' t' propsObj - PListener f -> do- f' <- toJSVal . fun $ \_ _ -> \case- [] -> return ()- ev:_ -> do- rn <- unsafeGetProp "target" =<< valToObject ev- x <- f (RawNode rn) (RawEvent ev)- writeUpdate i $ hoist (toJSM . runSnabbdom i) x- unsafeSetProp (toJSString k) f' listenersObj+ PListener f -> do+ f' <- toJSVal . fun $ \_ _ -> \case+ [] -> return ()+ ev:_ -> do+ rn <- unsafeGetProp "target" =<< valToObject ev+ x <- f (RawNode rn) (RawEvent ev)+ writeUpdate i $ hoist (toJSM . runSnabbdom i) x+ unsafeSetProp k' f' listenersObj - PFlag b -> do- f <- toJSVal b- unsafeSetProp (toJSString k) f propsObj+ PFlag b ->+ unsafeSetProp k' (toJSBool b) propsObj p <- toJSVal propsObj l <- toJSVal listenersObj@@ -173,49 +233,90 @@ return o -instance (MonadJSM m, Eq a) => Backend (SnabbdomT a) m a where- type VNode (SnabbdomT a) m = SnabVNode+potato :: JSVal -> RawNode -> JSM ()+#ifndef ghcjs_HOST_OS+potato n rn = void $ jsg2 "potato" n rn+#else+potato n (RawNode rn) = potato' n rn+foreign import javascript unsafe "window['potato']($1,$2)" potato' :: JSVal -> JSVal -> JSM ()+#endif - interpret :: (m ~> JSM) -> Html (SnabbdomT a m) a -> SnabbdomT a m SnabVNode- interpret toJSM = \case - TextNode t -> liftJSM $ fromJSValUnchecked =<< toJSVal t+vnode :: Text -> Object -> [SnabVNode] -> JSM SnabVNode+#ifndef ghcjs_HOST_OS+vnode name o cs = SnabVNode <$> jsg3 "vnode" name o cs+#else+vnode t o cs = join $ vnode' <$> pure t <*> pure o <*> toJSVal cs+foreign import javascript unsafe "window['vnode']($1,$2,$3)" vnode' :: Text -> Object -> JSVal -> JSM SnabVNode+#endif - Node name ps [TextNode t] -> do- i <- ask; liftJSM $ do- o <- props toJSM i ps- fromJSValUnchecked =<< jsg3 "vnode" name o t - Node name ps children -> do- i <- ask; liftJSM $ do- o <- props toJSM i ps- traverse ((toJSM . runSnabbdom i) . interpret toJSM >=> toJSVal) children- >>= jsg3 "vnode" name o >>= fromJSValUnchecked+#ifndef ghcjs_HOST_OS+vnodePotato :: Object -> JSM SnabVNode+vnodePotato o = SnabVNode <$> jsg2 "vnode" "div" o+#else+foreign import javascript unsafe "window['vnode']('div',$1)" vnodePotato :: Object -> JSM SnabVNode+#endif - Potato mrn -> liftJSM $ do- o <- create- hook <- create- rn <- mrn- ins <- toJSVal =<< function (\_ _ -> \case- [n] -> void $ jsg2 "potato" n rn- _ -> return ())- unsafeSetProp "insert" ins hook- hoo <- toJSVal hook- unsafeSetProp "hook" hoo o- fromJSValUnchecked =<< jsg2 "vnode" "div" o +patchh :: JSVal -> SnabVNode -> JSM ()+#ifndef ghcjs_HOST_OS+patchh previousNode newNode = void $ jsg2 "patchh" previousNode newNode+#else+patchh p (SnabVNode n) = patchh' p n+foreign import javascript unsafe "window['patchh']($1,$2)" patchh' :: JSVal -> JSVal -> JSM ()+#endif ++instance (MonadJSM m, NFData a) => Backend (SnabbdomT a) m a where+ type VNode (SnabbdomT a) m = SnabVNode++ interpret :: (m ~> JSM) -> Html (SnabbdomT a m) a -> SnabbdomT a m SnabVNode+ interpret toJSM (Html h') = h' mkNode mkPotato mkText+ where+ mkNode name ps children = do+ i <- snabbAsk; liftJSM $ do+ !o <- props toJSM i $ toProps ps+ !cs <- toJSM . runSnabbdom i $ sequence children+ vnode name o cs++ mkPotato mrn = snabbAsk >>= \i -> liftJSM $ do+ o <- create+ hook <- create+ (rn, stm) <- mrn+ ins <- toJSVal =<< function (\_ _ -> \case+ [n] -> potato n rn+ _ -> return ())+ unsafeSetProp "insert" ins hook+ hoo <- toJSVal hook+ unsafeSetProp "hook" hoo o+ let go = atomically stm >>= writeUpdate i . hoist (toJSM . runSnabbdom i) >> go+ void $ forkIO go+ vnodePotato o++ mkText = liftJSM . fmap SnabVNode . valMakeText++ patch :: RawNode -> Maybe SnabVNode -> SnabVNode -> SnabbdomT a m SnabVNode- patch (RawNode r) f t = t <$ (liftJSM . void $ jsg2 "patchh" f' t)- where f' = maybe r unVNode f+ patch (RawNode container) mPreviousNode newNode = liftJSM $ newNode <$ patchh previousNode newNode+ where previousNode = maybe container unVNode mPreviousNode setup :: JSM () -> JSM () setup cb = do void $ eval @Text $(embedStringFile "Shpadoinkle/Backend/Snabbdom/Setup.js")- void . jsg1 "startApp" . fun $ \_ _ _ -> cb+ startApp cb +startApp :: JSM () -> JSM ()+#ifndef ghcjs_HOST_OS+startApp cb = void . jsg1 "startApp" . fun $ \_ _ _ -> cb+#else+startApp cb = startApp' =<< toJSVal =<< function (fun $ \_ _ _ -> cb)+foreign import javascript unsafe "window['startApp']($1)" startApp' :: JSVal -> JSM ()+#endif++ -- | Get the @window.container@ DOM node produced by 'setup' (@Setup.js@). stage :: MonadJSM m => SnabbdomT a m RawNode stage = liftJSM $ do@@ -223,6 +324,8 @@ elm <- createElement doc ("div" :: Text) setAttribute elm ("id" :: Text) ("stage" :: Text) b <- getBodyUnsafe doc+ setInnerHTML b "" _ <- appendChild b elm RawNode <$> toJSVal elm+{-# SPECIALIZE stage :: SnabbdomT a JSM RawNode #-}
Shpadoinkle/Backend/Snabbdom/Setup.js view
@@ -1,33 +1,22 @@-(() => {--const head = document.getElementsByTagName('head')[0];-const addScript = x => {- const s = document.createElement('script');- s.type = 'text/javascript';- s.src = x;- head.appendChild(s);-}--const cdnjs = x => "https://cdnjs.cloudflare.com/ajax/libs/snabbdom/0.7.4/" + x;--addScript(cdnjs("snabbdom.min.js"));-addScript(cdnjs("snabbdom-class.min.js"));-addScript(cdnjs("snabbdom-props.min.js"));-addScript(cdnjs("snabbdom-attributes.min.js"));-addScript(cdnjs("snabbdom-eventlisteners.min.js"));-addScript(cdnjs("h.min.js"));--window.startApp = cb => setTimeout(() => {- const patch = snabbdom.init([- snabbdom_props.default,- snabbdom_class.default,- snabbdom_attributes.default,- snabbdom_eventlisteners.default- ]);- window.patchh = (a,b) => patch(a,b);- window.vnode = h.default;- window.potato = (n, e) => n.elm.appendChild(e)- cb();-}, 1000);--})();+parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c<t.length;c++)try{f(t[c])}catch(e){i||(i=e)}if(t.length){var l=f(t[t.length-1]);"object"==typeof exports&&"undefined"!=typeof module?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):n&&(this[n]=l)}if(parcelRequire=f,i)throw i;return f}({"RM4J":[function(require,module,exports) {+"use strict";function e(e,t,o,r,d){return{sel:e,data:t,children:o,text:r,elm:d,key:void 0===t?void 0:t.key}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.vnode=e;+},{}],"BfzD":[function(require,module,exports) {+"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.primitive=e,exports.array=void 0;var r=Array.isArray;function e(r){return"string"==typeof r||"number"==typeof r}exports.array=r;+},{}],"VeuO":[function(require,module,exports) {+"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.h=o;var e=require("./vnode.js"),r=i(require("./is.js"));function t(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return t=function(){return e},e}function i(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=t();if(r&&r.has(e))return r.get(e);var i={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var u=n?Object.getOwnPropertyDescriptor(e,o):null;u&&(u.get||u.set)?Object.defineProperty(i,o,u):i[o]=e[o]}return i.default=e,r&&r.set(e,i),i}function n(e,r,t){if(e.ns="http://www.w3.org/2000/svg","foreignObject"!==t&&void 0!==r)for(var i=0;i<r.length;++i){var o=r[i].data;void 0!==o&&n(o,r[i].children,r[i].sel)}}function o(t,i,o){var u,v,f,a={};if(void 0!==o?(null!==i&&(a=i),r.array(o)?u=o:r.primitive(o)?v=o:o&&o.sel&&(u=[o])):null!=i&&(r.array(i)?u=i:r.primitive(i)?v=i:i&&i.sel?u=[i]:a=i),void 0!==u)for(f=0;f<u.length;++f)r.primitive(u[f])&&(u[f]=(0,e.vnode)(void 0,void 0,void 0,u[f],void 0));return"s"!==t[0]||"v"!==t[1]||"g"!==t[2]||3!==t.length&&"."!==t[3]&&"#"!==t[3]||n(a,u,t),(0,e.vnode)(t,a,u,v,void 0)}+},{"./vnode.js":"RM4J","./is.js":"BfzD"}],"B5vY":[function(require,module,exports) {+"use strict";function e(e,t){return document.createElement(e,t)}function t(e,t,n){return document.createElementNS(e,t,n)}function n(e){return document.createTextNode(e)}function o(e){return document.createComment(e)}function r(e,t,n){e.insertBefore(t,n)}function i(e,t){e.removeChild(t)}function u(e,t){e.appendChild(t)}function c(e){return e.parentNode}function m(e){return e.nextSibling}function d(e){return e.tagName}function a(e,t){e.textContent=t}function f(e){return e.textContent}function l(e){return 1===e.nodeType}function p(e){return 3===e.nodeType}function s(e){return 8===e.nodeType}Object.defineProperty(exports,"__esModule",{value:!0}),exports.htmlDomApi=void 0;var x={createElement:e,createElementNS:t,createTextNode:n,createComment:o,insertBefore:r,removeChild:i,appendChild:u,parentNode:c,nextSibling:m,tagName:d,setTextContent:a,getTextContent:f,isElement:l,isText:p,isComment:s};exports.htmlDomApi=x;+},{}],"FyzG":[function(require,module,exports) {+"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.init=s;var e=require("./vnode.js"),t=l(require("./is.js")),r=require("./htmldomapi.js");function n(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return n=function(){return e},e}function l(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=n();if(t&&t.has(e))return t.get(e);var r={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=l?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}return r.default=e,t&&t.set(e,r),r}function o(e){return void 0===e}function i(e){return void 0!==e}var a=(0,e.vnode)("",{},[],void 0,void 0);function d(e,t){var r,n,l=e.key===t.key,o=(null===(r=e.data)||void 0===r?void 0:r.is)===(null===(n=t.data)||void 0===n?void 0:n.is);return e.sel===t.sel&&l&&o}function v(e){return void 0!==e.sel}function u(e,t,r){for(var n,l={},o=t;o<=r;++o){var i=null===(n=e[o])||void 0===n?void 0:n.key;void 0!==i&&(l[i]=o)}return l}var f=["create","update","remove","destroy","pre","post"];function s(n,l){var s,c,p={create:[],update:[],remove:[],destroy:[],pre:[],post:[]},h=void 0!==l?l:r.htmlDomApi;for(s=0;s<f.length;++s)for(p[f[s]]=[],c=0;c<n.length;++c){var m=n[c][f[s]];void 0!==m&&p[f[s]].push(m)}function g(e,t){return function(){if(0==--t){var r=h.parentNode(e);h.removeChild(r,e)}}}function x(e,r){var n,l,d,v=e.data;if(void 0!==v){var u=null===(n=v.hook)||void 0===n?void 0:n.init;i(u)&&(u(e),v=e.data)}var f=e.children,s=e.sel;if("!"===s)o(e.text)&&(e.text=""),e.elm=h.createComment(e.text);else if(void 0!==s){var c=s.indexOf("#"),m=s.indexOf(".",c),g=c>0?c:s.length,y=m>0?m:s.length,k=-1!==c||-1!==m?s.slice(0,Math.min(g,y)):s,b=e.elm=i(v)&&i(d=v.ns)?h.createElementNS(d,k,v):h.createElement(k,v);for(g<y&&b.setAttribute("id",s.slice(g+1,y)),m>0&&b.setAttribute("class",s.slice(y+1).replace(/\./g," ")),d=0;d<p.create.length;++d)p.create[d](a,e);if(t.array(f))for(d=0;d<f.length;++d){var j=f[d];null!=j&&h.appendChild(b,x(j,r))}else t.primitive(e.text)&&h.appendChild(b,h.createTextNode(e.text));var O=e.data.hook;i(O)&&(null===(l=O.create)||void 0===l||l.call(O,a,e),O.insert&&r.push(e))}else e.elm=h.createTextNode(e.text);return e.elm}function y(e,t,r,n,l,o){for(;n<=l;++n){var i=r[n];null!=i&&h.insertBefore(e,x(i,o),t)}}function k(e){var t,r,n=e.data;if(void 0!==n){null===(r=null===(t=null==n?void 0:n.hook)||void 0===t?void 0:t.destroy)||void 0===r||r.call(t,e);for(var l=0;l<p.destroy.length;++l)p.destroy[l](e);if(void 0!==e.children)for(var o=0;o<e.children.length;++o){var i=e.children[o];null!=i&&"string"!=typeof i&&k(i)}}}function b(e,t,r,n){for(var l,o;r<=n;++r){var a=void 0,d=void 0,v=t[r];if(null!=v)if(i(v.sel)){k(v),a=p.remove.length+1,d=g(v.elm,a);for(var u=0;u<p.remove.length;++u)p.remove[u](v,d);var f=null===(o=null===(l=null==v?void 0:v.data)||void 0===l?void 0:l.hook)||void 0===o?void 0:o.remove;i(f)?f(v,d):d()}else h.removeChild(e,v.elm)}}function j(e,t,r){var n,l,a,v,f,s=null===(n=t.data)||void 0===n?void 0:n.hook;null===(l=null==s?void 0:s.prepatch)||void 0===l||l.call(s,e,t);var c=t.elm=e.elm,m=e.children,g=t.children;if(e!==t){if(void 0!==t.data){for(var k=0;k<p.update.length;++k)p.update[k](e,t);null===(v=null===(a=t.data.hook)||void 0===a?void 0:a.update)||void 0===v||v.call(a,e,t)}o(t.text)?i(m)&&i(g)?m!==g&&function(e,t,r,n){for(var l,i,a,v=0,f=0,s=t.length-1,c=t[0],p=t[s],m=r.length-1,g=r[0],k=r[m];v<=s&&f<=m;)null==c?c=t[++v]:null==p?p=t[--s]:null==g?g=r[++f]:null==k?k=r[--m]:d(c,g)?(j(c,g,n),c=t[++v],g=r[++f]):d(p,k)?(j(p,k,n),p=t[--s],k=r[--m]):d(c,k)?(j(c,k,n),h.insertBefore(e,c.elm,h.nextSibling(p.elm)),c=t[++v],k=r[--m]):d(p,g)?(j(p,g,n),h.insertBefore(e,p.elm,c.elm),p=t[--s],g=r[++f]):(void 0===l&&(l=u(t,v,s)),o(i=l[g.key])?h.insertBefore(e,x(g,n),c.elm):(a=t[i]).sel!==g.sel?h.insertBefore(e,x(g,n),c.elm):(j(a,g,n),t[i]=void 0,h.insertBefore(e,a.elm,c.elm)),g=r[++f]);(v<=s||f<=m)&&(v>s?y(e,null==r[m+1]?null:r[m+1].elm,r,f,m,n):b(e,t,v,s))}(c,m,g,r):i(g)?(i(e.text)&&h.setTextContent(c,""),y(c,null,g,0,g.length-1,r)):i(m)?b(c,m,0,m.length-1):i(e.text)&&h.setTextContent(c,""):e.text!==t.text&&(i(m)&&b(c,m,0,m.length-1),h.setTextContent(c,t.text)),null===(f=null==s?void 0:s.postpatch)||void 0===f||f.call(s,e,t)}}return function(t,r){var n,l,o,i=[];for(n=0;n<p.pre.length;++n)p.pre[n]();for(v(t)||(t=function(t){var r=t.id?"#"+t.id:"",n=t.className?"."+t.className.split(" ").join("."):"";return(0,e.vnode)(h.tagName(t).toLowerCase()+r+n,{},[],void 0,t)}(t)),d(t,r)?j(t,r,i):(l=t.elm,o=h.parentNode(l),x(r,i),null!==o&&(h.insertBefore(o,r.elm,h.nextSibling(l)),b(o,[t],0,0))),n=0;n<i.length;++n)i[n].data.hook.insert(i[n]);for(n=0;n<p.post.length;++n)p.post[n]();return r}}+},{"./vnode.js":"RM4J","./is.js":"BfzD","./htmldomapi.js":"B5vY"}],"C4g2":[function(require,module,exports) {+"use strict";function e(e,s){var a,t,o=s.elm,r=e.data.class,l=s.data.class;if((r||l)&&r!==l){for(t in l=l||{},r=r||{})r[t]&&!Object.prototype.hasOwnProperty.call(l,t)&&o.classList.remove(t);for(t in l)(a=l[t])!==r[t]&&o.classList[a?"add":"remove"](t)}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.classModule=void 0;var s={create:e,update:e};exports.classModule=s;+},{}],"FnDi":[function(require,module,exports) {+"use strict";function e(e,o){var r,p,t=o.elm,a=e.data.props,s=o.data.props;if((a||s)&&a!==s)for(r in a=a||{},s=s||{})p=s[r],(a[r]!==p&&("value"!==r||t[r]!==p)||"checked"==r&&t[r]!==p)&&(t[r]=p)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.propsModule=void 0;var o={create:e,update:e};exports.propsModule=o;+},{}],"QBBp":[function(require,module,exports) {+"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.attributesModule=void 0;var t="http://www.w3.org/1999/xlink",e="http://www.w3.org/XML/1998/namespace",r=58,a=120;function i(i,o){var s,u=o.elm,d=i.data.attrs,b=o.data.attrs;if((d||b)&&d!==b){for(s in d=d||{},b=b||{}){var A=b[s];d[s]!==A&&(!0===A?u.setAttribute(s,""):!1===A?u.removeAttribute(s):s.charCodeAt(0)!==a?u.setAttribute(s,A):s.charCodeAt(3)===r?u.setAttributeNS(e,s,A):s.charCodeAt(5)===r?u.setAttributeNS(t,s,A):u.setAttribute(s,A))}for(s in d)s in b||u.removeAttribute(s)}}var o={create:i,update:i};exports.attributesModule=o;+},{}],"HAvm":[function(require,module,exports) {+"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(n,o,r){if("function"==typeof n)n.call(o,r,o);else if("object"===e(n))for(var i=0;i<n.length;i++)t(n[i],o,r)}function n(e,n){var o=e.type,r=n.data.on;r&&r[o]&&t(r[o],n,e)}function o(){return function e(t){n(t,e.vnode)}}function r(e,t){var n,r=e.data.on,i=e.listener,f=e.elm,s=t&&t.data.on,l=t&&t.elm;if(r!==s){if(r&&i)if(s)for(n in r)s[n]||f.removeEventListener(n,i,!1);else for(n in r)f.removeEventListener(n,i,!1);if(s){var u=t.listener=e.listener||o();if(u.vnode=t,r)for(n in s)r[n]||l.addEventListener(n,u,!1);else for(n in s)l.addEventListener(n,u,!1)}}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.eventListenersModule=void 0;var i={create:r,update:r,destroy:r};exports.eventListenersModule=i;+},{}],"gtJM":[function(require,module,exports) {+"use strict";var e=require("./h.js"),r=require("./init.js"),i=require("./modules/class.js"),t=require("./modules/props.js"),n=require("./modules/attributes.js"),s=require("./modules/eventlisteners.js");window.startApp=function(o){var u=(0,r.init)([t.propsModule,i.classModule,n.attributesModule,s.eventListenersModule]);window.patchh=function(e,r){return u(e,r)},window.vnode=e.h,window.potato=function(e,r){return e.elm.appendChild(r)},window.insertHook=function(e,r,i){var t=i[e];i[e]=function(e){t&&t(e),r(e)}},o()};+},{"./h.js":"VeuO","./init.js":"FyzG","./modules/class.js":"C4g2","./modules/props.js":"FnDi","./modules/attributes.js":"QBBp","./modules/eventlisteners.js":"HAvm"}]},{},["gtJM"], null)+//# sourceMappingURL=/Setup_src.js.map