[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non: push\njobs:\n  test:\n    env: \n      NODE_ENV: development\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [14.x]\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v1\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - name: Test\n      run: |\n        npm install -g codecov\n        npm install\n        npm test\n        codecov\n"
  },
  {
    "path": ".gitignore",
    "content": "*.html\n*.map\n*.br\n*.gz\n\npackage-lock.json\nnode_modules\ncoverage\nprivate\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright © Jorge Bucaran <<https://jorgebucaran.com>>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Hyperapp\n\n> The tiny framework for building hypertext applications.\n\n- **Do more with less**—We have minimized the concepts you need to learn to get stuff done. Views, actions, effects, and subscriptions are all pretty easy to get to grips with and work together seamlessly.\n- **Write what, not how**—With a declarative API that's easy to read and fun to write, Hyperapp is the best way to build purely functional, feature-rich, browser-based apps using idiomatic JavaScript.\n- **Smaller than a favicon**—1 kB, give or take. Hyperapp is an ultra-lightweight Virtual DOM, [highly-optimized diff algorithm](https://javascript.plainenglish.io/javascript-frameworks-performance-comparison-2020-cd881ac21fce), and state management library obsessed with minimalism.\n\nHere's the first example to get you started. [Try it here](https://codepen.io/jorgebucaran/pen/zNxZLP?editors=1000)—no build step required!\n\n<!-- prettier-ignore -->\n```html\n<script type=\"module\">\n  import { h, text, app } from \"https://unpkg.com/hyperapp\"\n\n  const AddTodo = (state) => ({\n    ...state,\n    value: \"\",\n    todos: state.todos.concat(state.value),\n  })\n\n  const NewValue = (state, event) => ({\n    ...state,\n    value: event.target.value,\n  })\n\n  app({\n    init: { todos: [], value: \"\" },\n    view: ({ todos, value }) =>\n      h(\"main\", {}, [\n        h(\"h1\", {}, text(\"To do list\")),\n        h(\"input\", { type: \"text\", oninput: NewValue, value }),\n        h(\"ul\", {},\n          todos.map((todo) => h(\"li\", {}, text(todo)))\n        ),\n        h(\"button\", { onclick: AddTodo }, text(\"New!\")),\n      ]),\n    node: document.getElementById(\"app\"),\n  })\n</script>\n\n<main id=\"app\"></main>\n```\n\n[Check out more examples](https://codepen.io/collection/nLLvrz?grid_type=grid)\n\nThe app starts by setting the initial state and rendering the view on the page. User input flows into actions, whose function is to update the state, causing Hyperapp to re-render the view.\n\nWhen describing how a page looks in Hyperapp, we don't write markup. Instead, we use `h()` and `text()` to create a lightweight representation of the DOM (or virtual DOM for short), and Hyperapp takes care of updating the real DOM efficiently.\n\n## Installation\n\n```console\nnpm install hyperapp\n```\n\n## Documentation\n\nLearn the basics in the [Tutorial](docs/tutorial.md), check out the [Examples](https://codepen.io/collection/nLLvrz?grid_type=grid), or visit the [Reference](docs/reference.md).\n\n## Packages\n\nOfficial packages provide access to [Web Platform](https://platform.html5.org) APIs in a way that makes sense for Hyperapp. For third-party packages and real-world examples, browse the [Hyperawesome](https://github.com/jorgebucaran/hyperawesome) collection.\n\n| Package                                        | Status                                                                                                                                              | About                                                                                                     |\n| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |\n| [`@hyperapp/dom`](/packages/dom)               | [![npm](https://img.shields.io/npm/v/@hyperapp/dom.svg?style=for-the-badge&color=0366d6&label=)](https://www.npmjs.com/package/@hyperapp/dom)       | Inspect the DOM, focus and blur.                                                                          |\n| [`@hyperapp/svg`](/packages/svg)               | [![npm](https://img.shields.io/npm/v/@hyperapp/svg.svg?style=for-the-badge&color=0366d6&label=)](https://www.npmjs.com/package/@hyperapp/svg)       | Draw SVG with plain functions.                                                                            |\n| [`@hyperapp/html`](/packages/html)             | [![npm](https://img.shields.io/npm/v/@hyperapp/html.svg?style=for-the-badge&color=0366d6&label=)](https://www.npmjs.com/package/@hyperapp/html)     | Write HTML with plain functions.                                                                          |\n| [`@hyperapp/time`](/packages/time)             | [![npm](https://img.shields.io/npm/v/@hyperapp/time.svg?style=for-the-badge&color=0366d6&label=)](https://www.npmjs.com/package/@hyperapp/time)     | Subscribe to intervals, get the time now.                                                                 |\n| [`@hyperapp/events`](/packages/events)         | [![npm](https://img.shields.io/npm/v/@hyperapp/events.svg?style=for-the-badge&color=0366d6&label=)](https://www.npmjs.com/package/@hyperapp/events) | Subscribe to mouse, keyboard, window, and frame events.                                                   |\n| [`@hyperapp/http`](/packages/http)             | [![npm](https://img.shields.io/badge/-planned-6a737d?style=for-the-badge&label=)](https://www.npmjs.com/package/@hyperapp/http)                     | Talk to servers, make HTTP requests ([#1027](https://github.com/jorgebucaran/hyperapp/discussions/1027)). |\n| [`@hyperapp/random`](/packages/random)         | [![npm](https://img.shields.io/badge/-planned-6a737d?style=for-the-badge&label=)](https://www.npmjs.com/package/@hyperapp/random)                   | Declarative random numbers and values.                                                                    |\n| [`@hyperapp/navigation`](/packages/navigation) | [![npm](https://img.shields.io/badge/-planned-6a737d?style=for-the-badge&label=)](https://www.npmjs.com/package/@hyperapp/navigation)               | Subscribe and manage the browser URL history.                                                             |\n\n> Need to create your own effects and subscriptions? [You can do that too](docs/reference.md).\n\n## Help, I'm stuck!\n\nIf you've hit a stumbling block, hop on our [Discord](https://discord.gg/eFvZXzXF9U) server to get help, and if you remain stuck, [please file an issue](https://github.com/jorgebucaran/hyperapp/issues/new), and we'll help you figure it out.\n\n## Contributing\n\nHyperapp is free and open-source software. If you want to support Hyperapp, becoming a contributor or [sponsoring](https://github.com/sponsors/jorgebucaran) is the best way to give back. Thank you to everyone who already contributed to Hyperapp! <3\n\n[![](https://opencollective.com/hyperapp/contributors.svg?width=1024&button=false)](https://github.com/jorgebucaran/hyperapp/graphs/contributors)\n\n## License\n\n[MIT](LICENSE.md)\n"
  },
  {
    "path": "docs/api/app.md",
    "content": "# `app()`\n\nInitializes and mounts a Hyperapp application.\n\n```elm\napp : ({ Init, View, Node, Subscriptions?, Dispatch? }) -> DispatchFn\n```\n\n| Prop                             | Type                                                                        | Required?                        |\n| -------------------------------- | --------------------------------------------------------------------------- | -------------------------------- |\n| [init:](#init)                   | <ul><li>[State](../architecture/state.md)</li><li>[[State](../architecture/state.md), ...[Effect](../architecture/effects.md)[]]</li><li>[Action](../architecture/actions.md)</li><li>[[Action](../architecture/actions.md), any]</li></ul> | No                               |\n| [view:](#view)                   | [View](../architecture/views.md)                                            | No                               |\n| [node:](#node)                   | DOM element                                                                 | **Yes when `view:` is present.** |\n| [subscriptions:](#subscriptions) | Function                                                                    | No                               |\n| [dispatch:](#dispatch)           | [Dispatch Initializer](../architecture/dispatch.md#dispatch-initializer)    | No                               |\n\n| Return Value                            | Type     |\n| --------------------------------------- | -------- |\n| [dispatch](../architecture/dispatch.md) | Function |\n\n```js\nimport { app, h, text } from \"hyperapp\"\n\napp({\n  init: { message: \"Hello World!\" },\n  view: (state) => h(\"p\", {}, text(state.message)),\n  node: document.getElementById(\"app\"),\n})\n```\n\n## `init:`\n\n_(default value: `{}`)_\n\nInitializes the app by either setting the initial value of the [state](../architecture/state.md) or taking an [action](../architecture/actions.md). It takes place before the first view render and subscriptions registration.\n\n### Forms of `init:`\n\n- `init: state`\n\n  Sets the initial state directly.\n\n  ```js\n  app({\n    init: { counter: 0 },\n    // ...\n  })\n  ```\n\n- `init: [state, ...effects]`\n\n  Sets the initial state and then runs the given list of [effects](../architecture/effects.md).\n\n  ```js\n  app({\n    init: [\n      { loading: true },\n      log(\"Loading...\"),\n      load(\"myUrl?init\", DoneAction),\n    ],\n    // ...\n  })\n  ```\n\n- `init: Action`\n\n  Runs the given [Action](../architecture/actions.md).\n\n  This form is useful when the action can be reused later. The state passed to the action in this case is `undefined`.\n\n  ```js\n  const Reset = (_state) => ({ counter: 0 })\n\n  app({\n    init: Reset,\n    // ...\n  })\n  ```\n\n- `init: [Action, payload]`\n\n  Runs the given [Action](../architecture/actions.md) with a payload.\n\n  ```js\n  const SetCounter = (_state, n) => ({ counter: n })\n\n  app({\n    init: [SetCounter, 10],\n    // ...\n  })\n  ```\n\n## `view:`\n\nThe [top-level view](../architecture/views.md#top-level-view) that represents the app as a whole. There can only be one top-level view in your app. Hyperapp uses this to map your state to your UI for rendering the app. Every time the [state](../architecture/state.md) of the application changes, this function will be called to render the UI based on the new state, using the logic you've defined inside of it.\n\n```js\napp({\n  // ...\n  view: (state) => h(\"main\", {}, [\n    outworld(state),\n    netherrealm(state),\n  ]),\n})\n```\n\n<!-- \"Outworld\" and \"Netherrealm\" are two of several realms in the \"Mortal Kombat\" videogame series. -->\n\n## `node:`\n\nThe DOM element to render the virtual DOM over (the **mount node**). The given element is replaced by a Hyperapp application. This process is called **mounting**. It's common to define an intentionally empty element in your HTML which has an ID that your app can use for mounting. If the mount node had content within it then Hyperapp will attempt to [recycle](../architecture/views.md#recycling) that content.\n\n```html\n<main id=\"app\"></main>\n```\n\n```js\napp({\n  // ...\n  node: document.getElementById(\"app\"),\n})\n```\n\n## `subscriptions:`\n\nA function that returns an array of [subscriptions](../architecture/subscriptions.md) for a given state. Every time the [state](../architecture/state.md) of the application changes, this function will be called to determine the current subscriptions.\n\nIf a subscription entry is falsy then the subscription that was at that spot, if any, will be considered unsubscribed from and will be cleaned up.\n\nIf `subscriptions:` is omitted the app has no subscriptions. It behaves the same as if you were using: `subscriptions: (state) => []`\n\n```js\nimport { onKey } from \"./subs\"\n\napp({\n  // ...\n  subscriptions: (state) => [\n    onKey(\"w\", MoveForward),\n    onKey(\"a\", MoveBackward),\n    onKey(\"s\", StrafeLeft),\n    onKey(\"d\", StrafeRight),\n    state.playingDOOM1993 || onKey(\" \", Jump),\n  ],\n})\n```\n\n<!-- The 1993 videogame DOOM did not have jumping as a movement option. -->\n\n## `dispatch:`\n\nA [dispatch initializer](../architecture/dispatch.md#dispatch-initializer) that can create a [custom dispatch function](../architecture/dispatch.md#custom-dispatching) to use instead of the default dispatch. Allows tapping into dispatches for debugging, testing, telemetry etc.\n\n## Return Value\n\n`app()` returns the [dispatch](../architecture/dispatch.md) function your app uses. This can be handy if you want to control your app externally, ie where only a subsection of your app is implemented with Hyperapp.\n\nCalling the dispatch function with no arguments frees the app's resources and runs every active subscription's cleanup function.\n\n## Other Considerations\n\n- You can embed your Hyperapp application within another already existing Hyperapp application or an app that was built with some other framework.\n\n- Multiple Hyperapp applications can coexist on the page simultaneously. They each have their own state and behave independently relative to each other. They can communicate with each other using subscriptions and effects (i.e. using events).\n"
  },
  {
    "path": "docs/api/h.md",
    "content": "<h1 title=\"The name of the `h()` function is short for **hyperscript** which is named after the original hyperscript function from [HyperScript](https://github.com/hyperhype/hyperscript).\"><code>h()</code></h1>\n\n**_Definition:_**\n\n> A function that creates [virtual DOM nodes (VNodes)](../architecture/views.md#virtual-dom) which are used for defining [views](../architecture/views.md).\n\n**_Import & Usage:_**\n\n```js\nimport { h } from \"hyperapp\"\n\n// ...\n\nh(tag, props, children)\n```\n\n**_Signature & Parameters:_**\n\n```elm\nh : (String, Object, VNode? | [...VNodes]?) -> VNode\n```\n\n| Parameters            | Type                     | Required? |\n| --------------------- | ------------------------ | --------- |\n| [tag](#tag)           | String                   | yes :100: |\n| [props](#props)       | Object                   | yes :100: |\n| [children](#children) | VNode or array of VNodes | no        |\n\n| Return Value                                         | Type  |\n| ---------------------------------------------------- | ----- |\n| [virtual node](../architecture/views.md#virtual-dom) | VNode |\n\n`h()` effectively represents the page elements used in your app. Because it's just JavaScript we can easily render whichever elements we see fit in a dynamical manner.\n\n```js\nconst hobbit = (wearingElvenCloak) =>\n  h(\"div\", {}, [\n    !wearingElvenCloak && h(\"p\", {}, text(\"Frodo\")),\n  ])\n```\n\n<!-- In \"The Lord of the Rings\" book/movie series, Frodo is a main character who eventually obtains a special cloak that makes him invisible when worn. -->\n\n---\n\n## Parameters\n\n### `tag`\n\nName of the node. For example, `div`, `h1`, `button`, etc. Essentially any [HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) or [SVG element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element) or [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements).\n\n### `props`\n\nHTML or SVG properties (\"props\") for the DOM element are defined using an object where the keys are the property names and the values are the corresponding property values.\n\n```js\nh(\"input\", {\n  type: \"checkbox\",\n  id: \"picard\",\n  checked: state.engaging,\n})\n```\n\n<!-- In the television series \"Star Trek: The Next Generation\", one of captain Picard's catchphrases is \"Engage!\". -->\n\nHyphenated props will need to be quoted in order to use them. The quotes are necessary to abide by JavaScript syntax restrictions.\n\n```js\nh(\"q\", { \"data-zoq-fot-pik\": \"Frungy\" }, text(\"The Sport of Kings!\"))\n```\n\n<!-- In the videogame \"Star Control II: The Ur-Quan Masters\" the alien races known as the Zoq-Fot-Pik have a favorite mysterious sport called Frungy which they regard as \"The Sport of Kings\". -->\n\nCertain properties are treated in a special way by Hyperapp.\n\n#### `class:`\n\nThe [classes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) to use with the VNode. The `class` prop can be given in various formats:\n\n- As a string representing a class name. Because of the way Hyperapp internally processes class strings they're allowed to have a space-separated list of different class names.\n\n  ```js\n  h(\"div\", { class: \"muggle-studies\" })\n  ```\n\n  <!-- In the \"Harry Potter\" book/movie series, \"Muggle Studies\" is a class that can be taken at the Hogwarts School of Witchcraft and Wizardry. -->\n\n- As an object where the keys are the names of the classes while the values are booleans for toggling the classes.\n\n  ```js\n  h(\"div\", { class: { arithmancy: true, \"study-of-ancient-runes\": true } })\n  ```\n\n  <!-- In the \"Harry Potter\" series, \"Arithmancy\" and \"The Study of Ancient Runes\" are classes that can be taken at Hogwarts. -->\n\n- As an array that contains any combination of the various formats including this one.\n\n  ```js\n  h(\"div\", { class: [\"magical theory\", \"xylomancy\"] })\n  ```\n\n  <!-- In the \"Harry Potter\" series, \"Magical Theory\" and \"Xylomancy\" are classes that can be taken at Hogwarts. -->\n\n  This means the array format is recursive.\n\n  ```js\n  h(\"input\", {\n    type: \"range\",\n    class: [\n      { dragonzord: state.green && !state.white },\n      \"mastodon\",\n      state.pink && \"pterodactyl\",\n      [\n        { triceratops: state.blue },\n        \"sabretooth-tiger\",\n        state.red && \"tyrannosaurus\",\n      ],\n    ],\n  })\n  ```\n\n  <!--\n  In the television show \"Mighty Morphin Power Rangers\", Tommy Oliver was initially the Green Ranger and eventually became the White Ranger.\n  The Green Ranger's Zord was called the Dragonzord.\n  The Black Ranger had the Mastodon Dinozord.\n  The Pink Ranger had the Pterodactyl Dinozord.\n  The Blue Ranger had the Triceratops Dinozord.\n  The Yellow Ranger had the Sabretooth Tiger Dinozord.\n  The Red Ranger had the Tyrannosaurus Dinozord.\n  -->\n\n#### `style:`\n\nThe [inline CSS styles](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/style) to use with the VNode. The `style` prop can be an object of [CSS properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference) where the keys are the CSS property names and the values are the corresponding CSS property values. Hyphenated CSS property names can either be in camelCase or quoted to abide by JavaScript syntax restrictions.\n\n```js\nh(\n  \"span\",\n  {\n    style: {\n      backgroundColor: \"white\",\n      color: \"blue\",\n      display: \"inline-block\",\n      \"font-weight\": \"bold\",\n    },\n  },\n  text(\"+\\\\\")\n)\n```\n\n<!-- The combination of the plus and backslash characters along with the blue and white colors are reminiscent of Hyperapp's logo. -->\n\n#### `key:`\n\nA unique string per VNode that helps Hyperapp track if VNodes are changed, added, or removed in situations where it's unable to do so, such as in arrays.\n\n```js\nconst pokedex = (pokemon) =>\n  h(\n    \"ul\",\n    {},\n    pokemon.map((p) => h(\"li\", { key: p.id }, text(p.name)))\n  )\n```\n\n<!-- The Pokédex is a digital encyclopedia used by Trainers in the world of Pokémon. -->\n\n#### Event Listeners\n\nProps that represent event listeners, such as [`onclick`](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event), [`onchange`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event), [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event), etc. are where you would assign [actions](../architecture/actions.md) to VNodes.\n\nSynthetic events can be added in the same way as long as their name starts with \"on\", so an event created with \n```js\nconst buildEvent = new Event(\"build\")\n``` \ncan be used like this: \n```js\nh(\"button\", { onbuild: BuildAction }, text(\"Click Me\"))\n```\n\n### `children`\n\nThe children of the VNode are other VNodes which are directly nested within it.\n\n`children` can either be given as a single child VNode:\n\n```js\nh(\"q\", {}, text(\"There is no spoon.\"))\n```\n\n<!-- In the movie \"The Matrix\", a young boy says \"There is no spoon.\" to the protagonist Neo. -->\n\nor as an array of child VNodes:\n\n```js\nh(\"q\", {}, [\n  text(\"I know Kung Fu.\"),\n  h(\"em\", {}, text(\"Show me.\")),\n])\n```\n\n<!-- In the movie \"The Matrix\", Neo says \"I know Kung Fu.\" after having downloaded martial arts knowledge into his head. His mentor Morpheus replies with \"Show me.\" before they spar with each other. -->\n\n---\n\n## Other Considerations\n\n### JSX Support\n\nHyperapp doesn't support [JSX](https://reactjs.org/docs/introducing-jsx.html) out-of-the-box. That said you can use this custom JSX function to be able to use it.\n\n```js\nimport { h, text } from \"hyperapp\"\n\nconst jsxify = (h) => (type, props, ...children) =>\n  typeof type === \"function\"\n    ? type(props, children)\n    : h(\n        type,\n        props || {},\n        [].concat(...children).map((x) =>\n          typeof x === \"string\" || typeof x === \"number\" ? text(x) : x\n        )\n      )\n\nconst jsx = jsxify(h) /** @jsx jsx */\n```\n"
  },
  {
    "path": "docs/api/memo.md",
    "content": "# `memo()`\n\n**_Definition:_**\n\n> A wrapper function to cache your [views](../architecture/views.md) based on properties you pass into them.\n\n**_Import & Usage:_**\n\n```js\nimport { memo } from \"hyperapp\"\n\n// ...\n\nmemo(view, props)\n```\n\n**_Signature & Parameters:_**\n\n```elm\nmemo : (View, IndexableData) -> VNode\n```\n\n| Parameters    | Type                                            | Required? |\n| ------------- | ----------------------------------------------- | --------- |\n| [view](#view) | [View](../architecture/views.md)                | yes :100: |\n| [data](#data) | anything indexable (i.e. Array, Object, String) | no        |\n\n| Return Value                                         | Type  |\n| ---------------------------------------------------- | ----- |\n| [virtual node](../architecture/views.md#virtual-dom) | VNode |\n\n`memo()` lets you take advantage of a performance optimization technique known as [memoization](../architecture/views.md#memoization).\n\n---\n\n## Parameters\n\n### `view`\n\nA [view](../architecture/views.md) you want [memoized](../architecture/views.md#memoization).\n\n### `data`\n\nThe data to pass along to the wrapped view function instead of the [state](../architecture/state.md). The wrapped view is recomputed when the data for it changes.\n\n---\n\n## Example\n\nHere we have a list of numbers displayed in a regular view as well as a memoized version of the same view. One button changes the list which affects both views. Another button updates a counter which affects the counter's view and also the regular view of the list but not the memoized view of the list.\n\n```js\nimport { h, text, app, memo } from \"hyperapp\"\n\nconst randomHex = () => \"0123456789ABCDEF\"[Math.floor(Math.random() * 16)]\nconst randomColor = () => \"#\" + Array.from({ length: 6 }, randomHex).join(\"\")\n\nconst listView = (list) =>\n  h(\"p\", {\n    style: {\n      backgroundColor: randomColor(),\n      color: randomColor(),\n    },\n  }, text(list))\n\nconst MoreItems = (state) => ({ ...state, list: [...state.list, randomHex()] })\nconst Increment = (state) => ({ ...state, counter: state.counter + 1 })\n\napp({\n  init: {\n    list: [\"a\", \"b\", \"c\"],\n    counter: 0,\n  },\n  view: (state) =>\n    h(\"main\", {}, [\n      h(\"button\", { onclick: MoreItems }, text(\"Grow list\")),\n      h(\"button\", { onclick: Increment }, text(\"+1 to counter\")),\n      h(\"p\", {}, text(`Counter: ${state.counter}`)),\n      h(\"p\", {}, text(\"Regular view showing list:\")),\n      listView(state.list),\n      h(\"p\", {}, text(\"Memoized view showing list:\")),\n      memo(listView, state.list),\n    ]),\n  node: document.querySelector(\"main\"),\n})\n```\n\n---\n\n## Other Considerations\n\n### Performance\n\nUsing `memo()` too often will lead to [degraded performance](../architecture/views.md#performance). Only use `memo()` when you know it will improve rendering. When in doubt, benchmark!\n\n### Memo Data Gotcha\n\nWhen Hyperapp checks memo data for changes it will do index-for-index comparisons between what the data currently is with how it was in the previous state. So, any indexable type like strings and arrays can be compared with one another and in certain edge cases be considered \"equal\" when it comes to determining if a re-render should happen.\n\nWe can modify parts of the example from earlier to illustrate this:\n\n```js\n// ...\n\nconst MoreItems = (state) => ({\n  ...state,\n  list: Array.isArray(state.list)\n    ? [...state.list, randomHex()]\n    : state.list + \"\" + randomHex(),\n})\n\nconst Increment = (state) => ({\n  ...state,\n  counter: state.counter + 1,\n\n  // The following should cause the memoized view to rerender but it doesn't.\n  list: Array.isArray(state.list)\n    ? state.list.join(\"\")\n    : state.list.split(\"\"),\n})\n\n// ...\n```\n"
  },
  {
    "path": "docs/api/text.md",
    "content": "# `text()`\n\n**_Definition:_**\n\n> A function that creates a [virtual DOM node (VNode)](../architecture/views.md#virtual-dom) out of a given value.\n\n**_Import & Usage:_**\n\nYou'll normally use it with [`h()`](./h.md).\n\n```js\nimport { text } from \"hyperapp\"\n\n// ...\n\nh(\"p\", {}, text(content))\n```\n\n**_Signature & Parameters:_**\n\n```elm\ntext : (String | Number) -> VNode\n```\n\n| Parameter           | Type                                                  | Required?      | Notes                                   |\n| ------------------- | ----------------------------------------------------- | -------------- | --------------------------------------- |\n| [content](#content) | any (sort of), but meaningfully only String or Number | yes :100:      |                                         |\n| node                | DOM element                                           | prohibited :x: | This is for internal Hyperapp use only! |\n\n| Return Value                                              | Type  |\n| --------------------------------------------------------- | ----- |\n| [virtual text node](../architecture/views.md#virtual-dom) | VNode |\n\nYou would use `text()` to insert regular text content into your views.\n\n```js\nh(\"p\", {}, text(\"You must construct additional pylons.\"))\n```\n\n<!-- In the videogame \"StarCraft\", the alien race known as the Protoss use special structures called pylons to power their buildings. -->\n\nOf course, this may include anything relevant from the [current state](../architecture/state.md).\n\n```js\nh(\"p\", {}, text(state.message))\n```\n\n`text()` exists as the way of defining text nodes such that Hyperapp's implementation is kept simpler than it otherwise would have been.\n\n---\n\n## Parameters\n\n### `content`\n\nWhile `content` can technically be anything, what will actually be used for the content of the VDOM element will be the stringified version of `content`. So, using actual strings and numbers makes a lot of sense but using arrays will probably be formatted in a way you don't want and objects won't work well at all.\n"
  },
  {
    "path": "docs/architecture/actions.md",
    "content": "# Actions\n\n**_Definition:_**\n\n> An **action** is a message used within your app that signals the valid way to change [state](state.md).\n\nAn action is implemented by a deterministic function that produces no side-effects which describes a transition between the current state and the next state and in so doing may optionally list out [effects](effects.md) to be run as well.\n\nActions are dispatched by either DOM events in your app, [effecters](effects.md#effecters), or [subscribers](subscriptions.md#subscribers). When dispatched, actions always implicitly receive the current state as their first argument.\n\n**_Signature:_**\n\n```elm\nAction : (State, Payload?) -> NextState\n                              | [NextState, ...Effects]\n                              | OtherAction\n                              | [OtherAction, Payload?]\n```\n\n**_Naming Recommendation:_**\n\nActions are recommended to be named in `PascalCase` to signal to the developer that they should be thought of as messages intended for use by Hyperapp itself. It is also recommended to use a verb (for instance `Add`) or a verb-noun phrase (`AddArticle`) for the name. The verb can be either in its imperative form, like `IncrementBy`, `ToggleVisibility`, `GetPizzas` or `SaveAddress`, or in the past tense form, for instance `GotData`, `StoppedCounting` – especially when the action is used for a \"final\" state transition at the end of an action-effect-chain.\n\n---\n\n## Simple State Transitions\n\nThe simplest possible action merely returns the current state:\n\n```js\n// Action : (State) -> SameState\nconst Identity = (state) => state\n```\n\nIt seems useless at first but can be helpful as a placeholder for other actions while prototyping a new app or [component](views.md#components).\n\nProbably the most common way to use an action is to assign it as an event handler for one of the nodes in your view.\n\n```js\nh(\"button\", { onclick: Identity }, text(\"Do Nothing\"))\n```\n\nThe next simplest type of action merely sets the state.\n\n```js\n// Action : () -> ForcedState\nconst FeedFace = () => 0xfeedface\n```\n\n<!-- \"FEEDFACE\" is an example of \"hexspeak\", a variant of English spelling using hexadecimal digits. -->\n\n<a name=\"actual-state-transition\"></a>\nBut you'll most likely want to do actual state transitions.\n\n```js\n// Action : (State) -> NewState\nconst Increment = (state) => ({ ...state, value: state.value + 1 })\n\n// ...\n\nh(\"button\", { onclick: Increment }, text(\"+\"))\n```\n\n---\n\n## Payloads\n\nActions can also accept an optional **payload** along with the current state.\n\n```js\n// Action : (State, Payload?) -> NewState\nconst AddBy = (state, amount) => ({ ...state, value: state.value + amount })\n```\n\nTo give a payload to an action we'll want to use an **action descriptor**.\n\n```js\nh(\"button\", { onclick: [AddBy, 5] }, text(\"+5\"))\n```\n\n### Event Payloads\n\nActions used as event handlers receive the event object as the default payload.\n\nIf we were to use our `AddBy` action without specifying its payload:\n\n```js\nh(\"button\", { onclick: AddBy }, text(\"+5\"))\n```\n\nthen it will receive the event object when the user clicks it and will attempt to directly \"add\" that to our state which would obviously be a bug.\n\nHowever, if we wanted to make proper use of the event object we have a couple options:\n\n- Rewrite `AddBy` to account for the possibility of receiving an event payload.\n- Or preprocess the event object to make it work with `AddBy` as it is.\n\nThe latter option is preferred because it lets our action remain unconcerned with how its payload is sourced thereby maintaining its reusability.\n\nWhich brings us to...\n\n---\n\n## Wrapped Actions\n\nActions can return other actions. The simplest form of these basically acts like an alias.\n\n```js\n// Action : () -> OtherAction\nconst PlusOne = () => Increment\n```\n\nA more useful form preprocesses payloads to use with other actions. We can make an event adaptor so our primary action can use event data without coupling to the event source.\n\n```js\n// Action : (State, EventPayload) -> [OtherAction, Payload]\nconst AddByValue = (state, event) => [AddBy, +event.target.value]\n```\n\nWe'll make use of `AddByValue` with an `input` node instead of the `button` from earlier because we want the event that gets preprocessed to have a `value` property we can extract:\n\n```js\nh(\"input\", { value: state, oninput: AddByValue })\n```\n\nYou can keep wrapping actions for as long as your sanity permits. The benefit is the ability to chain together payload adjustments.\n\n```js\nconst AddBy = (state, amount) => ({ ...state, value: state.value + amount })\nconst AddByMore = (_, amount) => [AddBy, amount + 5]\nconst AddByEvenMore = (_, amount) => [AddByMore, amount + 10]\n\n// ...\n\nh(\n  \"button\",\n  { onclick: [AddByEvenMore, 1] },\n  text(\"+16\")\n)\n```\n\n---\n\n## Transforms\n\nYou may consider refactoring very large and/or complicated actions it into simpler, more manageable functions. If so, remember that actions are just messages and, conceptually speaking, are not composable like the functions that implement them. That being said, it can at times be advantageous to delegate some state processing to other functions. Each of these constituent functions is a **transform** and is intended for use by actions or other transforms.\n\n```js\nconst Liokaiser = (state) => ({\n  ...state,\n  combined: true,\n  leftArm: hellbat(state),\n  rightArm: guyhawk(state),\n  upperTorso: leozack(state),\n  lowerTorso: jallguar(state),\n  leftLeg: drillhorn(state),\n  rightLeg: killbison(state),\n})\n```\n\n<!-- In the '80s Japanese animated series \"Transformers: Victory\", Liokaiser is a Decepticon combiner made from the combination of the team of Leozack, Drillhorn, Guyhawk, Hellbat, Jallguar, and Killbison. -->\n\n---\n\n## Stopping Your App\n\nYou can cease all Hyperapp processes by transitioning to an `undefined` state. This can be useful if you need to do specific cleanup work for your app.\n\n```js\n// Action : () -> undefined\nconst Stop = () => undefined\n```\n\nOnce your app stops, several things happen:\n\n- All of the app's subscriptions stop.\n- The DOM is no longer touched.\n- Event handlers stop working.\n\nA stopped app cannot be restarted.\n\nIf you encounter a scenario where your app doesn't respond when you click stuff within it, then your app might have been stopped by mistake.\n\n---\n\n## Other Considerations\n\n### Transitioning Array State\n\nAn array returned from an action carries [special meaning as already mentioned earlier](effects.md#using-effects). For this reason an actual [array state](state.md#array-state) needs special consideration.\n\nThere are a couple of options available:\n\n- Wrap the return state within an [effectful state array](state.md#state-with-effects). Mention also that init: option of app() function must also be wrapped.\n\n  ```js\n  const ArrayAction = (state) => [[...state, \"one\"]]\n  ```\n\n- Or you can choose a different format for the state by setting it up as an object that contains the the array so actions can work with it like they would with any other object state.\n\n  ```js\n  const ObjectAction = (state) => ({ ...state, list: [...state.list, \"one\"] })\n  ```\n\n### Nonstandard Usage\n\n- Using an anonymous function for an action has the disadvantage that it has no name for debugging tools to make use of. That's significant because it's recommended that actions have names.\n\n- If you wanted to use curried functions to implement actions then you can use named function expressions.\n\n  ```js\n  const Meet = (name) =>\n    function AndGreet(state) {\n      return `${state.salutation}, my name is ${name}.`\n    }\n  ```\n\n- If you have some special requirements you can customize how actions are [dispatched](dispatch.md).\n\n- Because of the way Hyperapp works internally, anywhere actions can be used literal values can be used instead to directly set state and possibly run effects.\n\n  ```js\n  h(\"button\", { onclick: 55 }, text(\"55\"))\n  h(\"button\", { onclick: [55, log] }, text(\"55 and log\"))\n  ```\n\n  However, this conflicts with the notion that state transitions happen through the usage of actions. The valid way to achieve the same thing would be:\n\n  ```js\n  const FiftyFive = () => 55\n  const FiftyFiveAndLog = () => [55, log]\n  ```\n\n  ```js\n  h(\"button\", { onclick: FiftyFive }, text(\"55\"))\n  h(\"button\", { onclick: FiftyFiveAndLog }, text(\"55 and log\"))\n  ```\n\n  The [`init`](../api/app.md#init) property of [`app()`](../api/app.md) is the only place where it's valid to either directly set the state or use an action to do it.\n\n  That said, this type of usage is fascinating...\n\n  ```js\n  h(\"button\", { onclick: state.startingOver ? \"Begin\" : MyCoolAction }, text(\"cool\"))\n  ```\n"
  },
  {
    "path": "docs/architecture/dispatch.md",
    "content": "# Dispatch\n\n**_Definition:_**\n\n> The **dispatch** function controls Hyperapp's core dispatching process which executes [actions](actions.md), applies state transitions, runs [effects](effects.md), and starts/stops [subscriptions](subscriptions.md) that need it.\n\nYou can augment the dispatcher to tap into the dispatching process for debugging/instrumentation purposes. Such augmentation is loosely comparable to middleware used in other frameworks.\n\n**_Signature:_**\n\n```elm\nDispatchFn : (Action, Payload?) -> void\n```\n\n---\n\n## Dispatch Initializer\n\nThe dispatch initializer accepts the default dispatch as its sole argument and must give back a dispatch in return. Hyperapp's default dispatch initializer is equivalent to:\n\n```js\nconst boring = (dispatch) => dispatch\n```\n\nIn your own initializer you'll likely want to return a variant of the regular dispatch.\n\n---\n\n## Augmented Dispatching\n\nA dispatch function accepts as its first argument an [action](actions.md) or anything an action can return, and its second argument is the default [payload](actions.md#payloads) if there is one. The payload will be used if the first argument is an action function.\n\nThe action will then be carried out and its resulting state transition will be applied and then any effects it requested to be run will be run.\n\n```js\n// DispatchFn : (Action, Payload?) -> void\nconst dispatch = (action, payload) => {\n  // Do your custom work here.\n  // ...\n\n  // Hand dispatch over to built-in dispatch.\n  dispatch(action, payload)\n}\n```\n\n## Dispatch recursion\n\nDispatch is implemented in a recursive fashion, such that if the action dispatched does not represent the next state (or next state with effects), it will use the dispatched action and payload to resolve the next thing to dispatch. \n\nA call to `dispatch([ActionFn, payload])` will recurse `dispatch(ActionFn, payload)`, which will recurse to `dispatch(ActionFn(currentState, payload))`. \n\n---\n\n## Example 1 - Log actions\n\nLet's say you need to debug the order in which actions are dispatched. An augmented dispatch that logs each action could help with that, rather than having to add `console.log` to every action.\n\n```js\nconst logActionsMiddleware = dispatch => (action, payload) => {\n\n  if (typeof action === 'function') {\n    console.log('DISPATCH: ', action.name || action)\n  }\n\n  //pass on to original dispatch\n  dispatch(action, payload)\n}\n```\n\n---\n\n## Example 2 - Log state\n\nTo log each state transformation, we first create a general state middleware and then use it to create an augmented dispatch for state logging:\n\n```js\nconst stateMiddleware = fn => dispatch => (action, payload) => {\n  if (Array.isArray(action) && typeof action[0] !== 'function') {\n    action = [fn(action[0]), ...action.slice(1)]\n  } else if (!Array.isArray(action) && typeof action !== 'function') {\n    action = fn(action)\n  }\n  dispatch(action, payload)\n}\n\nconst logStateMiddleware = stateMiddleware(state => { \n  console.log('STATE:', state)\n  return state\n})\n```\n\n---\n\n## Example 3 - Immutable state\n\nWhen learning Hyperapp and during developemt it can sometimes be useful to guarantee states are not mutated by mistake, let's use `stateMiddleware` above to create an augmented dispatch for state immutability:\n\n```js\n// a proxy prohibiting mutation\nconst immutableProxy = o => {\n  if (o===null || typeof o !== 'object') return o\n  return new Proxy(o, {\n    get(obj, prop) {\n      return immutableProxy(obj[prop])\n    },\n    set(obj, prop) {\n      throw new Error(`Can not set prop ${prop} on immutable object`)\n    }\n  })\n}\n\nexport const immutableMiddleware = stateMiddleware(state => immutableProxy(state))\n```\n\n\n## Usage\n\nThe [`app()`](../api/app.md) function will check to see if you have a dispatch initializer assigned to the [`dispatch:`](../api/app.md#dispatch) property while instantiating your application. If so, your app will use it instead of the default one.\n\nThe only time the dispatch initializer gets used is once during the instantiation of your app.\n\nOnly one dispatch initializer can be defined per app. Consequently, only one dispatch can be defined per app.\n\nExtending the example from above, the dispatch initializer would be used like this:\n\n```js\nimport { mwLogState } from \"./middleware.js\"\n\napp({\n  // ...\n  dispatch: logActionsMiddleware\n})\n```\n\nAnd if you wanted to use all custom dispatches together, you can chain them like this:\n\n```js\nimport { logActionsMiddleware, logStateMiddleware, immutableMiddleware } from \"./middleware.js\"\n\napp({\n  // ...\n  dispatch: dispatch => logStateMiddleware(logActionsMiddleware(immutableMiddleware(dispatch)))\n})\n```\n\n\n---\n\n## Other Considerations\n\n- [`app()`](../api/app.md) returns the dispatch function to allow [dispatching externally](../api/app.md#instrumentation).\n\n- If you're feeling truly adventurous and/or know what you're doing you can choose to have your dispatch initializer return a completely custom dispatch from the ground up. For what purpose? You tell me! However, a completely custom dispatch won't have access to some important internal framework functions, so it's unlikely to be something useful without building off of the original dispatch.\n"
  },
  {
    "path": "docs/architecture/effects.md",
    "content": "# Effects\n\n_**Definition:**_\n\n> An **effect** is a representation used by actions to interact with some external process.\n\nAs with [subscriptions](subscriptions.md), effects are used to deal with impure asynchronous interactions with the outside world in a safe, pure, and immutable way. Creating an HTTP request, giving focus to a DOM element, saving data to local storage, sending data over a WebSocket, and so on, are all examples of effects at a conceptual level.\n\n**_Signature:_**\n\n```elm\nEffect : EffecterFn | [EffecterFn, Payload]\n```\n\n**_Naming Recommendation:_**\n\nEffects are recommended to be named in `camelCase` using a verb (for instance `log`) or verb-noun phrase (like `saveAsPDF`) in its imperative form for the name.\n\n## Using Effects\n\nAn action can associate its state transition with a list of one or more [effects](#effects) to run alongside the transition. It does this by returning an array containing the [state with effects](state.md#state-with-effects) where the first entry is the next state while the remaining entries are the effects to run.\n\n```js\nimport { log } from \"./fx\"\n\n// Action : (State) -> [NextState, ...Effects]\nconst SayHi = (state) => [\n  { ...state, value: state.value + 1 },\n  log(\"hi\"),\n  log(\"there\"),\n]\n\n// ...\n\nh(\"button\", { onclick: SayHi }, text(\"Say Hi\"))\n```\n\nActions can of course receive payloads and use effects simultaneously.\n\n```js\n// Action : (State, Payload) -> [NextState, ...Effects]\nconst SayBye = (state, amount) => [\n  { ...state, value: state.value + amount },\n  log(\"bye\"),\n]\n\n// ...\n\nh(\"button\", { onclick: [SayBye, 1] }, text(\"Bye\"))\n```\n\n## Excluding Effects\n\nIf you don't include any effects in the return array then only the state transition happens.\n\nHere, `OnlyIncrement` both behaves and is used similarly to `Increment` [shown here](actions.md#actual-state-transition):\n\n```js\n// Action : (State) -> [NextState]\nconst OnlyIncrement = (state) => [{ ...state, value: state.value + 1 }]\n\n// ...\n\nh(\"button\", { onclick: OnlyIncrement }, text(\"+\"))\n```\n\nSuch a single-element array may seem redundant at first but it can come into play if you have an action that conditionally runs effects.\n\nFor example, compare this:\n\n```js\nconst DoIt = (state) => {\n  let transition = { ...state, value: \"MacGuffin\" }\n  if (state.eating) {\n    transition = [transition, log(\"eating\")]\n  }\n  if (state.drinking) {\n    transition = Array.isArray(transition)\n      ? [...transition, log(\"drinking\")]\n      : [transition, log(\"drinking\")]\n  }\n  return transition\n}\n```\n\n<!-- In fiction, a MacGuffin is something that's necessary to the plot and the motivation of the characters but unimportant in itself. -->\n\nwith this:\n\n```js\nconst DoItBetter = (state) => {\n  let transition = [{ ...state, value: \"MacGuffin\" }]\n  if (state.eating) {\n    transition = [...transition, log(\"eating\")]\n  }\n  if (state.drinking) {\n    transition = [...transition, log(\"drinking\")]\n  }\n  return transition\n}\n```\n\nAdmittedly, these examples are a bit contrived but the latter is less complex.\n\nHowever, for these examples in particular we can do even better by taking advantage of the fact that any \"effects\" that are actually falsy values are ignored.\n\n```js\nconst DoItBest = (state) => [\n  { ...state, value: \"MacGuffin\" },\n  state.eating && log(\"eating\"),\n  state.drinking && log(\"drinking\"),\n]\n```\n\n## Defining Effects\n\nSyntactically speaking, an effect takes the form of a tuple containing its [effecter](#effecters) and any associated data.\n\nTechnically, an effect can be used directly but using a function that creates the effect is recommended because it offers flexibility with how the tuple is created while looking a little cleaner overall.\n\n```js\nconst massFx = (data) => [runNormandy, data]\n```\n\n<!-- `massFx` is a play on the title of the videogame series \"Mass Effect\". The SSV Normandy SR-1 is the spaceship the player travels in throughout the series. -->\n\n## Effecters\n\n**_Definition:_**\n\n> An **effecter** is the function that actually carries out an effect.\n\n**_Signature:_**\n\n```elm\nEffecterFn : (DispatchFn, Payload?) -> void\n```\n\nAs with [subscribers](subscriptions.md#subscribers), effecters are allowed to use side-effects and can also manually [`dispatch`](dispatch.md) actions in order to inform your app of any pertinent results from their execution.\n\nIt's important to know that effecters are more than just a way to wrap any arbitrary impure code. Their purpose is to be a generalized bridge between your app's business logic and the impure code that needs to exist. By keeping the effecters as generic as we can, we form a clean, manageable separation between what is requested to be done from how that request is done.\n\nTo demonstrate this approach take this ill-formed effecter for example:\n\n```js\n// This effecter is ill-formed.\nconst runHarvest = (dispatch, _payload) => {\n  const tiberium = document.getElementById(\"tiberium\")\n  dispatch((state) => ({ ...state, tiberium }))\n}\n```\n\n<!-- In the videogame series \"Command & Conquer\", Tiberium is a toxic alien crystalline substance that can be harvested for its energy. -->\n\nSure it runs, but it's also coupled to our app's state and the element ID being referenced is also hard-coded.\n\nLet's address this by first decoupling our callback action from the effecter by leveraging our ability to give the effecter a payload:\n\n```js\nconst runHarvest = (dispatch, payload) => \n  dispatch(payload.action, document.getElementById(\"tiberium\"))\n```\n\nLet's further utilize our payload by using it to pass in data our effecter needs to work:\n\n```js\nconst runHarvest = (dispatch, payload) => \n  dispatch(payload.action, document.getElementById(payload.id))\n```\n\nFinally, we should rename the effecter to reflect its generic nature:\n\n```js\nconst runGetElement = (dispatch, payload) => \n  dispatch(payload.action, document.getElementById(payload.id))\n```\n\nA well-formed effecter is as generic as it can be.\n\n### Synchronization\n\nEffecters which run some asynchronous operation and wish to report the results of it back to your app will need to ensure that the timing of their communication dispatch happens in alignment with Hyperapp's repaint cycle. This is important to ensure the state is set correctly.\n\nHyperapp's repaint cycle stays synchronized with the browser's natural repaint cycle, so asynchronous effecters must do the same. The preferred way to do this is with [`requestAnimationFrame()`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). If for some reason that method is unavailable, the fallback is [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout).\n\nLet's see an example of an ill-formed asynchronous effecter:\n\n```js\n// This effecter is ill-formed.\nconst runBrotherhood = async (dispatch, payload) => {\n  const response = await fetch(payload.lookForKaneHere)\n  const kaneLives = response.json()\n  requestAnimationFrame(() => {\n    dispatch((state) => ({\n      ...state,\n      message: kaneLives ? \"One vision! One purpose!\" : \"\",\n    }))\n  })\n}\n```\n\n<!-- In the videogame series \"Command & Conquer\", Kane is the leader of the Brotherhood of Nod and has cheated death at least once. One of his catchphrases is \"One vision! One purpose!\" -->\n\nNow let's see a more well-formed asynchronous effecter:\n\n```js\nconst runSimpleFetch = async (dispatch, payload) => {\n  const response = await fetch(payload.url)\n  requestAnimationFrame(() => dispatch(payload.action, response.json()))\n}\n```\n\n### Custom Events\n\nThe ideal scenario to use custom effects is when your Hyperapp application needs to communicate with a legacy app via custom events.\n\nWe can have our Hyperapp application use a custom effect for triggering custom events.\n\n```js\n// ./fx.js\n\nconst runEmit = (_dispatch, payload) => \n  dispatchEvent(new CustomEvent(payload.type, { detail: payload.detail }))\n\nexport const emit = (type, detail) => [runEmit, { type, detail }]\n```\n\n```js\nimport { h, text, app } from \"hyperapp\"\nimport { emit } from \"./fx\"\n\napp({\n  view: () =>\n    h(\"main\", {}, [\n      h(\n        \"button\",\n        {\n          onclick: (state) => [\n            state, \n            emit(\"outgoing\", { message: \"hello\" })\n          ],\n        },\n        text(\"Send greetings\")\n      ),\n    ]),\n  node: document.querySelector(\"main\"),\n})\n```\n"
  },
  {
    "path": "docs/architecture/flowchart.md",
    "content": "```mermaid\ngraph TD\n    init(\"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\")\n    init --- |\"init:{state}<br/>init:[state, effect(s)]<br/>\"|j0[ ] --- j1[ ] -->nextState\n    init --> |\"init:Action<br/>init:[Action, payload?]\"|Action\n\n    domevent(\"DOM/synthetic&nbsp;<br/>events<br/>&nbsp;(click/myevent)&nbsp;\") --> viewEvent\n    viewEvent((\"&nbsp;&nbsp;&nbsp;&nbsp;view&nbsp;&nbsp;&nbsp;&nbsp;<br/>event\")) --> Action\n    externalEvents(\"global/external<br/>processes<br/>&nbsp;(window resize)&nbsp;\") --> subscription\n    subscription((\"subscription\")) -->Action\n\n    Action[\"&nbsp;Action&nbsp;<br/>(state change)\"] -->|\"OtherAction<br/>&nbsp;[OtherAction, payload?]<br/>\"|Action\n    Action --- |\"NextState<br/>[NextState, ...Effects]\"|j2[ ] ---> nextState\n    \n    nextState((\"&nbsp;&nbsp;next&nbsp;&nbsp;<br/>state\")) --- j3[ ]\n    j3 --> |\"view(state)\"|newDom(\"&nbsp;&nbsp;&nbsp;(re)render&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;DOM&nbsp;&nbsp;&nbsp;\")\n    j3 --> |\"subscriptions(state)\"|recalcSubs(recalc<br/>subscriptions)\n    j3 --> |\"(dispatch, Payload?) -> void\"|effect\n    effect(\"Effects<br>(impure code)\") -.-> |\"dispatch\"|dispatchAction(\"Action\")\n    \n    style j0 height:1px;\n    style j0 width:1px;\n    style j1 height:1px;\n    style j1 width:1px;\n    style j2 height:1px;\n    style j2 width:1px;\n    style j3 height:1px;\n    style j3 width:1px;\n```\n"
  },
  {
    "path": "docs/architecture/state.md",
    "content": "# State\n\n**_Definition:_**\n\n> The **state** of your Hyperapp application is the unified set of data that your [views](views.md), [actions](actions.md), and [subscriptions](subscriptions.md) all have access to.\n\nHyperapp by design offers no strong opinion about how your state should be structured aside from it being unified. This means [components](views.md#components) don't technically possess their own local state but that also means they have direct access to any part of the entire state they need. The user is entrusted with shaping things beyond that.\n\n---\n\n## Assignment\n\nWhen you initially create your app instance with [`app()`](../api/app.md) you get to setup your state with the [`init:`](../api/app.md#init) property. Since it's possible to have several different app instances [active simultaneously](../api/app.md#multiple-apps) it's important to know that each app retains its own separate state.\n\n### State Transitions\n\nAside from the aforementioned [`init:`](../api/app.md#init) property the only way to affect state is by changing it through the use of [actions](actions.md).\n\n## State With Effects\n\nIf you use an array to set the state Hyperapp will interpret this as a special array where the first entry is the state and if there are more entries they will be [effects](effects.md) that need to be run.\n\nSo, Hyperapp will apply the state first and then will run the effects in the order they appear.\n\n```js\n[state, log(state), log(\"MOAR\")]\n```\n\n### Array State\n\nIf you actually do want to use an array as your state you'll have to wrap it within an effectful state array to make it work.\n\n```js\n[[\"a\", \"b\", \"c\"]]\n```\n\nThe actions page also [talks about it](actions.md#transitioning-array-state).\n\n---\n\n## Visualization\n\nThe primary [view](views.md) of your app, as set by the [`view:`](../api/app.md#view) property of [`app()`](../api/app.md), will receive the current state for it to use to determine what gets rendered. Any changes to the state are automatically reflected there as well.\n\n---\n\n## Other Considerations\n\n### Serializability\n\nWhile you can put anything you want in the state we recommend avoiding things that are unserializable such as symbols, functions, and recursive references. This helps to ensure compatibility with things like saving to persistent local storage, or using other tools especially ones that are potentially Hyperapp-specific.\n\n### State Type\n\nYou can of course choose to make your state some basic type such as a string or number. However, it's recommended to use an object because of the expressivity it gives you in defining your state shape.\n\n### Direct Mutation\n\nSince we are ultimately using JavaScript you can technically edit parts of the state mutably. However, state changes should be thought of in terms of snapshots: New versions of the state get created to reflect the changes made at a certain moment in time. This perspective naturally calls for immutability.\n\nFresh new state should be returned from an [action](actions.md). If an action returns nothing your app will [stop](actions.md#stopping-your-app). If you mutate the current state and return it you are returning the same object reference as the state was earlier. Hyperapp cannot tell from this that any changes have occurred. Hence the action will do nothing.\n"
  },
  {
    "path": "docs/architecture/subscriptions.md",
    "content": "# Subscriptions\n\n**_Definition:_**\n\n> A **subscription** function represents a dependency your app has on some external process.\n\nAs with [effects](effects.md), subscriptions deal with impure, asynchronous interactions with the outside world in a safe, pure, and immutable way. They are a streamlined way of responding to events happening outside our application such as time or location changes. They handle resource management for us that we would otherwise need to worry about like adding and removing event listeners, closing connections, etc.\n\n**_Signature:_**\n\n```elm\nSubscription : [SubscriberFn, Payload?]\n```\n\n**_Naming Recommendation:_**\n\nSubscriptions are recommended to be named in `camelCase` prefixed by `on`, for instance `onEvery` or `onMouseEnter` in order to reflect their event handling character.\n\n---\n\n## Using Subscriptions\n\nSubscriptions are setup and managed through the [`subscriptions:`](../api/app.md#subscriptions) property used with [`app()`](../api/app.md) when instantiating your app.\n\n```js\nimport { onEvery } from \"./time\"\n\n// ...\n\napp({\n  init: { delayInMilliseconds: 1000 },\n  subscriptions: (state) => [\n    // Dispatch `RequestResource` every `delayInMilliseconds`.\n    onEvery(state.delayInMilliseconds, RequestResource),\n  ],\n})\n```\n\nYou can control if subscriptions are active or not by using boolean values.\n\n```js\napp({\n  subscriptions: (state) => [\n    state.toBe && onEvery(state.delay, ThatIsTheQuestion),\n    state.notToBe || onEvery(state.delay, ThatIsTheQuestion),\n  ],\n})\n```\n\n<!-- In William Shakespeare's play \"Hamlet\", Prince Hamlet gives a soliloquy in Act 3, Scene 1 where he begins with \"To be, or not to be\", basically questioning life. -->\n\n### Subscriptions Array Format\n\nHyperapp expects the subscriptions array to be of a fixed size with each entry being either a boolean value or a particular subscription function that stays in the same array position. Using dynamic arrays won't work. Inlining subscription functions also won't work because they would just reset on every state change.\n\n### Subscription Lifecycle\n\nOn every state change, Hyperapp will check each subscriptions array entry to see if they're active and compare that with how they were in the previous state. This comparison determines how subscriptions are handled.\n\n| Previously Active | Currently Active | What Happens                                 |\n| ----------------- | ---------------- | -------------------------------------------- |\n| no                | no               | Nothing.                                     |\n| no                | yes :100:        | Subscription starts up.                      |\n| yes :100:         | no               | Subscription shuts down and gets cleaned up. |\n| yes :100:         | yes :100:        | Subscription remains active.                 |\n\nTo restart a subscription you must first deactivate it and then, during the next state change, reactivate it.\n\n---\n\n## Custom Subscriptions\n\nThere may be times when an official Hyperapp subscription package is unavailable for our needs. For those scenarios we'll need to make our own custom subscriptions.\n\n### Subscribers\n\n**_Definition:_**\n\n> A **subscriber** is a function which implements an active subscription.\n\n**_Signature:_**\n\n```elm\nSubscriberFn : (DispatchFn, Payload?) -> CleanupFn\n```\n\nAs with [effecters](effects.md#effecters), subscribers are allowed to use side-effects and can also manually [`dispatch`](dispatch.md) actions in order to inform your app of any pertinent results from their execution.\n\nSubscribers can be given a data `payload` for their use.\n\nWell-formed subscribers, as it is with effecters, should be as generic as possible. However, unlike with effecters, they should return a function that handles cleaning up the subscription if it gets cancelled.\n\n### Example\n\nLet's say we're embedding our Hyperapp application within a legacy vanilla JavaScript project.\n\nSomewhere within the legacy portion of our project a custom event gets emitted:\n\n```js\n// Somewhere in our legacy app...\n\nconst triggerSpecialEvent = () => {\n  dispatchEvent(new CustomEvent(\"secret\", { detail: 42 }))\n}\n\n// ...\n\ntriggerSpecialEvent()\n```\n\n<!-- In \"The Hitchhiker's Guide to the Galaxy\" the number 42 is given as The Answer to the Ultimate Question of Life, The Universe, and Everything by the computer Deep Thought. -->\n\nOur embedded Hyperapp application will need a custom subscription to be able to deal with custom events:\n\n```js\n// ./subs.js\n\nconst listenToEvent = (dispatch, props) => {\n  const listener = (event) =>\n    requestAnimationFrame(() => dispatch(props.action, event.detail))\n\n  addEventListener(props.type, listener)\n  return () => removeEventListener(props.type, listener)\n}\n\nexport const listen = (type, action) => [listenToEvent, { type, action }]\n```\n\nIn case you're wondering why `listenToEvent()`'s listener is using `requestAnimationFrame`, it has to do with [synchronization](actions.md#synchronization).\n\nNow we can use our custom subscription in our Hyperapp application. Since it will be embedded we'll wrap our call to [`app()`](../api/app.md) within an exported function our legacy app can make use of:\n\n```js\nimport { h, text, app } from \"hyperapp\"\nimport { listen } from \"./subs\"\n\nconst Response = (state, payload) => ({ ...state, payload })\n\nexport const myApp = (node) =>\n  app({\n    init: () => ({ payload: null }),\n    view: ({ payload }) =>\n      h(\"main\", {}, [\n        payload && h(\"p\", {}, text(`Payload received: ${JSON.stringify(payload)}`)),\n      ]),\n    subscriptions: () => [listen(\"secret\", Response)],\n    node: document.querySelector(\"main\"),\n  })\n```\n\n---\n\n## Other Considerations\n\n### Destructuring Gotcha\n\nSince a well-formed subscriber returns a cleanup function, it's possible that the cleanup function would want to communicate back to your app that the cleanup took place.\n\n```js\nconst listenToEvent = (dispatch, props) => {\n  const listener = (event) =>\n    requestAnimationFrame(() => dispatch(props.action, event.detail))\n\n  addEventListener(props.type, listener)\n  return () => {\n    removeEventListener(props.type, listener)\n    dispatch(props.action, \"<done>\")\n  }\n}\n```\n\nSo, using `props` directly works well. However, if instead you tried to use destructuring then the cleanup function won't be able to communicate back to your app in all scenarios:\n\n```js\nconst listenToEvent = (dispatch, { action, type }) => {\n  const listener = (event) =>\n    requestAnimationFrame(() => dispatch(action, event.detail))\n\n  addEventListener(type, listener)\n  return () => {\n    removeEventListener(type, listener)\n    dispatch(action, \"cleaned-up\")    // <-- uh, oh!\n  }\n}\n```\n\nThe reason is because destructuring the `props` parameter will create local copies of the props listed. This means the cleanup function's closure will be referring to the `action` function that existed at the moment the cleanup function was created and returned, not the moment the cleanup function gets invoked. This is a subtle yet significant difference depending on how you use your actions with this type of subscriber.\n\nThe scenario in which this comes into play is if you use an anonymous function for the `action`. An example of where you may consider doing this is if you wanted a way to selectively prevent default event behavior when a subscriber responds to an event.\n\n```js\n// ./fx.js\n\nconst runPreventDefault = (dispatch, payload) => {\n  payload.event.preventDefault()\n  dispatch(payload.action)\n}\n\nexport const preventDefault = (action, event) =>\n  [runPreventDefault, { action, event }]\n```\n\n```js\n// ./actions.js\n\nimport { preventDefault } from \"./fx\"\n\nexport const skipDefault = (action) => (state, event) => \n  [state, preventDefault(action, event)]\n\nexport const MyAction = (state) => ({ ...state })\n```\n\n```js\n// ./subs.js\n\nconst subOnThatThing = (dispatch, props) => {\n  // Do stuff...\n}\n\nexport const onThatThing = (action, props) => [subOnThatThing, { ...props, action }]\n```\n\n```js\n// ./main.js\n\nimport { onThatThing } from \"./subs\"\nimport { skipDefault } from \"./actions\"\n\napp({\n  subscriptions: (state) => [\n    state.isActive &&\n      onThatThing(skipDefault(MyAction), {\n        foo: 42 + state.index,\n      }),\n  ],\n})\n```\n\nNow when the subscription function runs per state update, the wrapped action is generated anew which results in a new function reference for the subscription's `action`. So, `subOnThatThing` must use `props` instead of destructuring to ensure the right function reference is available.\n"
  },
  {
    "path": "docs/architecture/views.md",
    "content": "# Views\n\n**_Definition:_**\n\n> A **view** is a declarative description of what should get rendered and is usually influenced by the current [state](state.md).\n\nA view is implemented as a pure function that accepts the current state and returns a [virtual DOM node (VNode)](#virtual-dom). When [state transitions](state.md#state-transitions) happen your views are automatically updated accordingly.\n\n**_Signature:_**\n\n```elm\nView : (State) -> VNode\n```\n\n---\n\n## Describing Views\n\nThe [`h()`](../api/h.md), [`text()`](../api/text.md), and [`memo()`](../api/memo.md) functions are the building blocks of your views.\n\n[`h()`](../api/h.md) not only describes what HTML elements are being used but also what [actions](actions.md) are wired up if any.\n\n```js\nconst view = (state) =>\n  h(\n    \"button\",\n    {\n      class: { \"calling-acid-burn\": state.beingFramed },\n      onclick: FindThatDisk,\n    },\n    text(\"It's in that place where I put that thing that time.\")\n  )\n```\n\n<!-- In the 1995 movie \"Hackers\", the hacker \"The Phantom Freak\" calls his friend \"Acid Burn\" from jail as he's being framed for a crime he didn't commit. -->\n\n[`text()`](../api/text.md) just creates text nodes so the views it can create on its own are necessarily simplistic.\n\n```js\nconst view = () => text(\"Go home and be a family man!\")\n```\n\n<!-- In the videogame \"Street Fighter II: The World Warrior\", the fighter known as Guile says this taunt to his opponent after defeating them. -->\n\n[`memo()`](../api/memo.md) is designed to be used with other functions that produce VNodes, so it doesn't really describe a view by itself.\n\n```js\nconst view = (state) => memo(scenicView, state.vacationSpot)\n```\n\n<!-- Just a play-on-words between how \"view\" is used in Hyperapp and everyday language. -->\n\n---\n\n## Components\n\nViews are naturally composable so they can be as simple or complicated as you need. Simpler apps probably just need a single view but in more complicated apps there could be plenty of subviews.\n\n**_Definition:_**\n\n> A **component** in Hyperapp can either be a subview or some other function that generates VNodes.\n\n**_Signature:_**\n\n```elm\nComponent : (GlobalState | PartialState) -> VNode | [...VNodes]\n```\n\n\n\nYou would typically make components for widgets that provide the building block elements of your app's UI. Components for larger UI segments such as dashboards or pages would make use of these widgets.\n\nIn the following example, `coinsDisplay` is a component in the form of a subview while `questionBlock` is a component in the form of some function that returns a VNode. Notice the former cares directly about the state while the latter doesn't:\n\n```js\n// Component : (GlobalState) -> VNode\nconst coinsDisplay = (state) =>\n  h(\"div\", { class: \"coins-display\" }, text(state.coins))\n\n// Component : (PartialState) -> VNode\nconst questionBlock = (opened) =>\n  opened\n    ? h(\"button\", { class: \"question-block opened\" }, text(\"?\"))\n    : h(\n        \"button\",\n        {\n          class: \"question-block\",\n          onclick: [\n            HitBlockFromBottom,\n            { revealItem: \"beanstalk\" },\n          ],\n        },\n        text(\"?\")\n      )\n\n// Component : (GlobalState) -> VNode\nconst level = (state) =>\n  h(\"div\", { class: \"level\" }, [\n    coinsDisplay(state),\n    questionBlock(state.onlyQuestionBlockOpened),\n  ])\n```\n\n<!-- In the videogame \"Super Mario Bros.\" coins are important for earning extra lives and the question blocks often contain useful contents. -->\n\n**_Naming Recommendation:_**\n\nComponents are recommended to be named in `camelCase` using a noun that concisely describes the (purpose of the) composed group of contained elements best, for instance `articleHeader` or `questionBlock`.\n\n### Components Returning Multiple VNodes\n\nComponents are allowed to return an array of VNodes. However, to make use of such components in a list of other siblings, you'll need to spread their result.\n\n```js\n// Component : () -> [...VNodes]\nconst finishingMoveOptions = () => [\n  h(\"button\", { onclick: FinishHim }, text(\"Fatality\")),\n  h(\"button\", { onclick: FinishHimAsAnAnimal }, text(\"Animality\")),\n  h(\"button\", { onclick: TurnHimIntoABaby }, text(\"Babality\")),\n  h(\"button\", { onclick: BefriendHim }, text(\"Friendship\")),\n]\n\nconst view = () => h(\"div\", {}, [\n  h(\"em\", {}, text(\"Finish them:\")),\n  ...finishingMoveOptions(),\n])\n```\n\n<!-- In the \"Mortal Kombat\" videogame series there are multiple ways to finish off your opponent. The opportunity to do so occurs at the end of a match once the match announcer exclaims \"Finish Him!\" -->\n\n---\n\n## Using Views\n\n### Top-Level View\n\nEvery Hyperapp application has a base view that encompasses all others. This is the **top-level view** that's defined by the [`view:`](../api/app.md#view) property when using [`app()`](../api/app.md). Hyperapp automatically calls this view and gives it the current state when the state is initially set or anytime it's updated.\n\n```js\napp({\n  // ...\n  view: (state) =>\n    h(\"main\", {}, [\n      earthrealm(state),\n      edenia(state),\n    ]),\n})\n```\n\n<!-- \"Earthrealm\" and \"Edenia\" are two of several realms in the \"Mortal Kombat\" videogame series. -->\n\n### Conditional Rendering\n\nElements of a view can be shown or hidden conditionally.\n\n```js\nconst view = (state) =>\n  h(\"div\", {}, [\n    state.flying && h(\"div\", {}, text(\"Flying\")),\n    state.notSwimming || h(\"div\", {}, text(\"Swimming\")),\n  ])\n```\n\n### Recycling\n\nHyperapp supports hydration of views out of the box. This means that if the mount node you specify is already populated with DOM elements, Hyperapp will recycle and use these existing elements instead of throwing them away and creating them again. You can use this for doing SSR or pre-rendering of your applications, which will give you SEO and performance benefits.\n\n---\n\n## Virtual DOM\n\n**_Definition:_** \n\n> The **virtual DOM**, or **VDOM** for short, is an in-memory representation of the [DOM](https://dom.spec.whatwg.org/) elements that exist on the current page.\n\nHyperapp uses it to determine how to efficiently update the actual DOM. The virtual DOM is a tree data structure where each of its nodes represent a particular VDOM element that may or may not get rendered.\n\nWe've already seen how [`h()`](../api/h.md), [`text()`](../api/text.md), and [`memo()`](../api/memo.md) all return different types of VNodes.\n\n### Patching the DOM\n\nWhen Hyperapp is ready to update the DOM it will do so starting at the element that corresponds to the root VNode of the [top-level view](#top-level-view). Hyperapp checks if there were changes made to that VNode representing that element. If so, the element gets rerendered the process repeats recursively for every child of that VNode.\n\n### Keys\n\nSometimes Hyperapp needs help determining how certain elements have changed. This is generally the case for VNodes that are rendered based on arrays in the state. This is because array items may have shifted around a lot during a state change, so when they get rendered the VNodes that currently represent them might be completely different than before.\n\nSince Hyperapp can't know for sure it must assume everything had changed requiring a full render every time.\n\nFor an example, look at the [`key:`](../api/h.md#key) documentation for [`h()`](../api/h.md).\n\n### Memoization\n\nThe optimization technique known as **memoization**, is where the result of a calculation is stored somewhere to be used again in the future without incurring the cost of calculating again.\n\nMemoization in Hyperapp concerns how VNodes are rendered and is implemented using [`memo()`](../api/memo.md). When memoized views are rerendered the \"state\" they receive is actually the props defined for the view when the memoization was setup.\n\nImmutability in Hyperapp guarantees that if two things are referentially equal, they must be identical. This makes it safe for Hyperapp to only re-compute your memoized components when values passed through their props change.\n\nFor an example, look at the documentation for [`memo()`](../api/memo.md#example).\n\n#### Performance\n\nMemoization exists to help improve rendering performance but it's not a panacea. If it was used with nodes that need to update on every state change, the cost of checking if the memoization's props had changed before carrying out the rendering would be a net loss of performance over time.\n\nMemoization was designed for nodes that don't need to update at all or just occasionally.\n\nAs always when it comes to optimizations, be sure to measure the performance of your app to make sure you're getting true benefits and adjust if necessary.\n"
  },
  {
    "path": "docs/reference.md",
    "content": "# Reference\n\n## API\n\n- [`h()`](api/h.md) creates a virtual DOM node (VNode) that gets rendered.\n- [`text()`](api/text.md) turns a string into a VNode.\n- [`app()`](api/app.md) initializes a Hyperapp app and mounts it.\n- [`memo()`](api/memo.md) creates a special VNode that is lazily rendered.\n\n## Architecture\n\n- [State](architecture/state.md) represents your application's data.\n- [Views](architecture/views.md) represent your state visually.\n- [Actions](architecture/actions.md) cause state transitions and trigger effects.\n- [Effects](architecture/effects.md) are triggered by actions to interact with external processes.\n- [Subscriptions](architecture/subscriptions.md) dispatch actions in response to external events.\n- [Dispatch](architecture/dispatch.md) controls action dispatching.\n\n&nbsp;&nbsp;&nbsp;&nbsp;[Flowchart](architecture/flowchart.md) showing the general flow of a hyperapp app.\n\n<h2 title=\"“I’d like to think of browsing the glossary as flipping pages in a book. I can go anywhere instantly and learn whatever suits my fancy.” ―@icylace\">Glossary</h2>\n\n- [Action](architecture/actions.md): An app behavior that transitions state and invokes effects.\n- [Action Descriptor](architecture/actions.md#payloads): A tuple representing an action with its payload.\n- [Component](architecture/views.md#components): A view with a specific purpose.\n- [Dispatch Function](architecture/dispatch.md#dispatch): The process that executes actions, applies state, and calls effects.\n- [Dispatch Initializer](architecture/dispatch.md#dispatch-initializer): A function that controls dispatch.\n- [Effect](architecture/effects.md): A generalized encapsulation of an external process.\n- [Effecter](architecture/effects.md#effecters): A function that carries out an effect.\n- [Event Payload](architecture/actions.md#event-payloads): A payload specific to an event.\n- [Memoization](architecture/views.md#memoization): In Hyperapp, the delayed rendering of VNodes.\n- [Mount Node](api/app.md#node): The DOM element that holds the app.\n- [Payload](architecture/actions.md#payloads): Data given to an action.\n- [State](architecture/state.md): The unified set of data your Hyperapp application uses and maintains.\n- [State Transition](architecture/state.md#state-transitions): An evolutionary step for the state.\n- [Subscriber](architecture/subscriptions.md#subscribers): A function that carries out a subscription.\n- [Subscription](architecture/subscriptions.md): A binding between the app and external events.\n- [Top-Level View](architecture/views.md#top-level-view): The main view which is given the state.\n- [VDOM](architecture/views.md#virtual-dom): The virtual DOM, an in-memory representation for the DOM of the current page.\n- [View](architecture/views.md): A function describing the desired DOM, represented by a VNode, as a function of the current state.\n- [Wrapped Action](architecture/actions.md#wrapped-actions): An action that is returned by another action.\n"
  },
  {
    "path": "docs/tutorial.md",
    "content": "# Tutorial #\n\nIf you're new to Hyperapp, this is a great place to start. We'll cover all the essentials and then some, as we incrementally build up a simplistic example. To begin, open up an editor and type in this html:\n\n```html\n<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"stylesheet\" href=\"./hyperapp-tutorial.css\" />\n    <script type=\"module\">\n\n/* Your code goes here */      \n\n    </script>\n  </head>\n  <body>\n    <main id=\"app\"/>\n  </body>\n</html>\n```\n\nSave it as `hyperapp-tutorial.html` on your local drive, and in the same folder create the `hyperapp-tutorial.css` with the following css:\n\n<details>\n  <summary>(expand tutorial css)</summary>\n  \n```css\n@import url('https://cdn.jsdelivr.net/npm/water.css@2/out/light.css');\n\n:root {\n  --box-width: 200px;\n}\n\nmain { position: relative;}\n\n.person {\n  box-sizing: border-box;\n  width: var(--box-width);\n  padding: 10px 10px 10px 40px;\n  position: relative;\n  border: 1px #ddd solid;\n  border-radius: 5px;  \n  margin-bottom: 10px;\n  cursor: pointer;\n}\n\n.person.highlight {\n  background-color: #fd9;\n}\n.person.selected {\n  border-width: 3px;\n  border-color: #55c;\n  padding-top: 8px;\n  padding-bottom: 8px;\n}\n\n.person input[type=checkbox] {\n  position: absolute;\n  cursor: default;\n  top: 10px;\n  left: 7px;\n}\n.person.selected input[type=checkbox] {\n  left: 5px;\n  top: 8px;\n}\n\n.person p {\n  margin: 0;\n  margin-left: 2px;\n}\n.person.selected p {\n  margin-left: 0;\n} \n\n.bio {\n  position: absolute;\n  left: calc(var(--box-width) + 2rem);\n  top: 60px;\n  color: #55c;\n  font-style: italic;\n  font-size: 2rem;\n  text-indent: -1rem;\n}\n.bio:before {content: '\"';}\n.bio:after {content: '\"';}\n\n```\n  \n</details>\n\nKeep the html file open in a browser as you follow along the tutorial, to watch your progress. At each step there will be a link to a live-demo sandbox yo may refer to in case something isn't working right. (You could also use the sandbox to follow the tutorial if you prefer)\n\n## Hello world ##\n\nEnter the following code:\n\n```js\nimport {h, text, app} from \"https://cdn.skypack.dev/hyperapp\"\n\napp({\n  view: () => h(\"main\", {}, [\n    h(\"div\", {class: \"person\"}, [\n      h(\"p\", {}, text(\"Hello world\")),\n    ]),\n  ]),\n  node: document.getElementById(\"app\"),\n})\n```\n\nSave the file and reload the browser. You'll be greeted by the words \"Hello world\" framed in a box.\n\n<img width=\"582\" src=\"https://user-images.githubusercontent.com/2061445/116821112-d9986300-ab78-11eb-82c5-25c35667eb18.png\">\n\n[Live Demo][1-hello-world]\n\nLet's walk through what happened:\n\nYou start by importing the three functions `h`, `text` and `app`.\n\nYou call `app` with an object that holds app's definition.\n\nThe `view` function returns a _virtual DOM_ – a blueprint of how we want the actual DOM to look, made up of _virtual nodes_. `h` creates virtual nodes representing HTML tags, while `text` creates representations of text nodes. The equivalent description in plain HTML would be:\n\n```html\n<main>\n  <div class=\"person\">\n    <p>Hello world</p>\n  </div>\n</main>\n```\n\n`node` declares _where_ on the page we want Hyperapp to render our app. Hyperapp replaces this node with the DOM-nodes it generates from the description in the view.\n\n## State, View, Action ##\n\n### Initializing State ###\n\nAdd an `init` property to the app:\n\n```js\napp({\n  init: { name: \"Leanne Graham\", highlight: true },\n  ...\n})\n```\n\nEach app has an internal value called _state_. The `init` property sets the state's initial value. The view is always called with the current state, allowing us to display values from the state in the view.\n\nChange the view to:\n\n```js\nstate => h(\"main\", {}, [\n  h(\"div\", {class: \"person\"}, [\n    h(\"p\", {}, text(state.name)),\n    h(\"input\", {type: \"checkbox\", checked: state.highlight}),\n  ]),\n])\n```\n\nSave and reload. Rather than the statically declared \"Hello world\" from before, we are now using the name \"Leanne Graham\" from the state. We also added a checkbox, whose checked state depends on `highlight`. \n\n<img width=\"584\" src=\"https://user-images.githubusercontent.com/2061445/116821122-e5842500-ab78-11eb-8ab6-09a4fe590557.png\">\n\n[Live Demo][2-render-with-state]\n\n\n### Class properties ###\n\nChange the definition of the div:\n\n```js\nh(\"div\", {class: {person: true, highlight: state.highlight}}, [ ... ])\n```\n\nThe class property can be a string of space-separated class-names just like in regular HTML, _or_ it can be an object where the keys are class-names. When the corresponding value is truthy, the class will be assigned to the element.\n\nThe `highlight` property of the state now controls both wether the div has the class \"highlight\" and wether the checkbox is checked.\n\n<img width=\"584\" src=\"https://user-images.githubusercontent.com/2061445/116821134-f03eba00-ab78-11eb-9054-fcfab957dee6.png\">\n\n[Live Demo][3-class-objects]\n\nHowever, clicking the checkbox to toggle the highlightedness of the box doesn't work. In the next step we will connect user interactions with transforming the state.\n\n### Actions ###\n\nDefine the function:\n\n```js\nconst ToggleHighlight = state => ({ ...state, highlight: !state.highlight })\n```\n\nIt describes a _transformation_ of the state. It expects a value in the shape of the app's state as argument, and will return something of the same shape. Such functions are known as _actions_. This particular action keeps all of the state the same, except for `highlight`, which should be flipped to its opposite.\n\nNext, assign the function to the `onclick` property of the checkbox: \n\n```js\nh(\"input\", {\n  type: \"checkbox\",\n  checked: state.highlight,\n  onclick: ToggleHighlight,\n})\n```\n\nSave and reload. Now, clicking the checkbox toggles not only checked-ness but the higlighting of the box.\n\n<img width=\"583\" src=\"https://user-images.githubusercontent.com/2061445/116821148-fcc31280-ab78-11eb-9eaa-48ea590f3804.png\">\n\n[Live Demo][4-toggle-highlight]\n\n\n### Dispatching ###\n\nBy assigning `ToggleHighlight` to `onclick` of the checkbox, we tell Hyperapp to _dispatch_ `ToggleHighlight` when the click-event occurs on the checkbox. Dispatching an action means Hyperapp will use the action to transform the state. With the new state, Hyperapp will calculate a new view and update the DOM to match.\n\n\n### View components ###\n\nSince the view is made up of nested function-calls, it is easy to break out a portion of it as a separate function for reuse & repetition.  \n\nDefine the function:\n\n```js\nconst person = props =>\n  h(\"div\", {\n    class: {\n      person: true,\n      highlight: props.highlight\n    }\n  }, [\n    h(\"p\", {}, text(props.name)),\n    h(\"input\", {\n      type: \"checkbox\",\n      checked: props.highlight,\n      onclick: props.ontoggle,\n    }),\n  ])\n```\n\nNow the view can be simplified to:\n\n```js\nstate => h(\"main\", {}, [\n  person({\n    name: state.name,\n    highlight: state.highlight,\n    ontoggle: ToggleHighlight,\n  }),\n])\n```\n\nHere, `person` is known as a _view component_. Defining and combining view components is a common practice for managing large views. Note, however, that it does not rely on any special Hyperapp-features – just plain function composition.\n\n[Live Demo][5-view-component]\n\n### Action payloads ###\n\nThis makes it easier to have multiple boxes in the view. First add more names and highlight values to the initial state, by changing `init`:\n\n```js\n{\n  names: [\n    \"Leanne Graham\",\n    \"Ervin Howell\",\n    \"Clementine Bauch\",\n    \"Patricia Lebsack\",\n    \"Chelsey Dietrich\",\n  ],\n  highlight: [\n    false,\n    true,\n    false,\n    false,\n    false,\n  ],\n}\n```\n\nnext, update the view to map over the names and render a `person` for each one:\n\n```js\nstate => h(\"main\", {}, [\n  ...state.names.map((name, index) => person({\n    name,\n    highlight: state.highlight[index],\n    ontoggle: [ToggleHighlight, index],\n  })),\n])\n```\n\nNotice how instead of assigning just `ToggleHighlight` to `ontoggle`, we assign `[ToggleHighlight, index]`. This makes Hyperapp dispatch `ToggleHighlight` with `index` as the _payload_. The payload becomes the second argument to the action. \n\nUpdate `ToggleHighlight` to handle the new shape of the state, and use the index payload:\n\n```js\nconst ToggleHighlight = (state, index) => {\n  // make shallow clone of original highlight array\n  let highlight = [...state.highlight]\n\n  // flip the highlight value of index in the copy\n  highlight[index] = !highlight[index]\n  \n  // return shallow copy of our state, replacing \n  // the highlight array with our new one\n  return { ...state, highlight}\n}\n```\n\nSave & reload. You now have five persons. Each can be individually highlighted by toggling its checkbox.\n\n<img width=\"584\" src=\"https://user-images.githubusercontent.com/2061445/116821165-0d738880-ab79-11eb-9144-ae07771d798e.png\">\n\n[Live Demo][6-action-payloads]\n\nNext, let's add the ability to \"select\" one person at a time by clicking on it. We only need what we've learned so far to achieve this.\n\nFirst, add a `selected` property to `init`, where we will keep track of the selected person by its index. Since no box is selected at first, `selected` starts out as `null`:\n\n```js\n{\n  ...\n  selected: null, \n}\n```\n\nNext, define an action for selecting a person: \n\n```js\nconst Select = (state, selected) => ({...state, selected})\n```\n\nNext, pass the `selected` property, and `Select` action to the `person` component:\n\n```js\nperson({\n  name,\n  highlight: state.highlight[index],\n  ontoggle: [ToggleHighlight, index],\n  selected: state.selected === index, // <----\n  onselect: [Select, index],          // <----\n})\n```\n\nFinally, we give the selected person the \"selected\" class to visualize wether it is selected. We also pass the given `onselect` property on to the `onclick` event handler of the div.\n\n```js\nconst person = props =>\n  h(\"div\", {\n    class: {\n      person: true,\n      highlight: props.highlight,\n      selected: props.selected,    // <---\n    },\n    onclick: props.onselect,       // <---\n  }, [\n    h(\"p\", {}, text(props.name)),\n    h(\"input\", {\n      type: \"checkbox\",\n      checked: props.highlight,\n      onclick: props.ontoggle,\n    }),\n  ])\n```\n\nSave, reload & try it out by clicking on the different persons.\n\n<img width=\"578\" src=\"https://user-images.githubusercontent.com/2061445/116821180-1e23fe80-ab79-11eb-9467-82880ce7a750.png\">\n\n[Live Demo][7-with-selection]\n\n### DOM-event objects ###\n\nBut now, when we toggle a checkbox, the person also selected. This happens because the `onclick` event bubbles up from the checkbox to the surrounding div. That is just how the DOM works. If we had access to the event object we could call the `stopPropagation` method on it, to prevent it from bubbling. That would allow toggling checkboxes without selecting persons.\n\nAs it happens, we _do_ have access to the event object! Bare actions (_not_ given as `[action, payload]`) have a default payload which is the event object. That means we can define the `onclick` action of the checkbox as:\n\n```js\nonclick: (state, event) => {\n  event.stopPropagation()\n  //...\n}\n```\n\nBut what do we do with the `props.ontoggle` that used to be there? – We return it!\n\n```js\nh(\"input\", {\n  type: \"checkbox\",\n  checked: props.highlight,\n  onclick: (_, event) => {\n    event.stopPropagation()\n    return props.ontoggle\n  },\n})\n```\n\nWhen an action returns another action, or an `[action, payload]` tuple instead of a new state, Hyperapp will dispatch that instead. You could say we defined an \"intermediate action\" just to stop the event propagation, before continuing to dispatch the action originally intended.\n\nSave, reload and try it! You should now be able to highlight and select persons independently. \n\n<img width=\"571\" src=\"https://user-images.githubusercontent.com/2061445/116821193-2b40ed80-ab79-11eb-9d1e-1ae1fc0da62b.png\">\n\n[Live Demo][8-separate-highlight-selection]\n\n\n### Conditional rendering ###\n\nFurther down we will be fetching the \"bio\" of selected persons from a server. For now, let's prepare the app to receive and display the bio.\n\nBegin by adding an initially empty `bio` property to the state, in `init`:\n\n```js\n{\n  ...,\n  selected: null,\n  bio: \"\",       // <---\n}\n```\n\nNext, define an action that saves the bio in the state, given some server data:\n\n```js\nconst GotBio = (state, data) => ({...state, bio: data.company.bs})\n```\n\nAnd then add a div for displaying the bio in the view:\n\n```js\nstate => h(\"main\", {}, [\n  ...state.names.map((name, index) => person({\n    name,\n    highlight: state.highlight[index],\n    ontoggle: [ToggleHighlight, index],\n    selected: state.selected === index,\n    onselect: [Select, index],\n  })),\n  state.bio &&                                  // <---\n  h(\"div\", { class: \"bio\" }, text(state.bio)),  // <---\n])\n```\n\nThe bio-div will only be shown if `state.bio` is truthy. You may try it for yourself by setting `bio` to some nonempty string in `init`.\n\n[Live Demo][9-conditional-rendering]\n\nThis technique of switching parts of the view on or off using `&&` (or switching between different parts using ternary operators `A ? B : C`) is known as _conditional rendering_\n\n## Effects ##\n\n### Effecters ###\n\nIn order to fetch the bio, we will need the id associated with each person. Add the ids to the initial state for now:\n\n```js\n{\n  ...\n  selected: null,\n  bio: \"\",\n  ids: [1, 2, 3, 4, 5], // <---\n}\n```\n\nWe want to perform the fetch when a person is selected, so update the `Select` action:\n\n```js\nconst Select = (state, selected) => {\n\n  fetch(\"https://jsonplaceholder.typicode.com/users/\" + state.ids[selected])\n  .then(response => response.json())\n  .then(data => {\n    console.log(\"Got data: \", data)\n  \n    /* now what ? */\n  })\n\n  return {...state, selected}\n}\n```\n\n> We will be using the JSONPlaceholder service in this tutorial. It is a free & open source REST API for testing & demoing client-side api integrations. Be aware that some endpoints could be down or misbehaving on occasion.\n\nIf you try that, you'll see it \"works\" in the sense that data gets fetched and logged – but we can't get it from there in to the state!\n\nHyperapp actions are not designed to be used this way. Actions are not general purpose event-handlers for running arbitrary code. Actions are meant to simply calculate a value and return it. \n\nThe way to run arbitrary code with some action, is to wrap that code in a function and return it alongside the new state:\n\n```js\nconst Select = (state, selected) => [\n  {...state, selected},\n  () => \n    fetch(\"https://jsonplaceholder.typicode.com/users/\" + state.ids[selected])\n    .then(response => response.json())\n    .then(data => {\n      console.log(\"Got data: \", data)\n      /* now what ? */\n    })\n]\n```\n\nWhen an action returns something like `[newState, [function]]`, the function is known as an _effecter_ (a k a \"effect runner\"). Hyperapp will call that function for you, as a part of the dispatch process. What's more, Hyperapp provides a `dispatch` function as the first argument to effecters, allowing them to \"call back\" with response data:\n\n\n```js\nconst Select = (state, selected) => [\n  {...state, selected},\n  dispatch => {                           // <---\n    fetch(\"https://jsonplaceholder.typicode.com/users/\" + state.ids[selected])\n    .then(response => response.json())\n    .then(data => dispatch(GotBio, data)) // <---\n  }\n]\n```\n\nNow when a person is clicked, besides showing it as selected, a request for the persons's data will go out. When the response comes back, the `GotBio` action will be dispatched, with the response data as payload. This will set the bio in the state and the view will be updated to display it.\n\n<img width=\"567\" src=\"https://user-images.githubusercontent.com/2061445/116821205-3ac03680-ab79-11eb-8814-74362f93de25.png\">\n\n[Live Demo][10-effecter-with-dispatch]\n\n### Effects ###\n\nThere will be other things we want to fetch in a similar way. The only difference will be the url and action. So let's define a reusable version of the effecter where url and action are given as an argument:\n\n```js\nconst fetchJson = (dispatch, options) => {\n  fetch(options.url)\n  .then(response => response.json())\n  .then(data => dispatch(options.action, data))\n}\n```\n\nNow change `Select` again:\n\n```js\nconst Select = (state, selected) => [\n  {...state, selected},\n  [ \n    fetchJson,\n    {\n      url: \"https://jsonplaceholder.typicode.com/posts/\" + state.ids[selected],\n      action: GotBio,\n    }\n  ]\n]\n```\n\nA tuple such as `[effecter, options]` is known as an _effect_. The options in the effect will be provided to the effecter as the second argument. Everything works the same as before, but now we can reuse `fetchJson` for other fetching we may need later.\n\n[Live Demo][11-effect]\n\n### Effect creators ###\n\nDefine another function:\n\n```js\nconst jsonFetcher = (url, action) => [fetchJson, {url, action}]\n```\n\nIt allows us to simplify `Select` even more:\n\n```js\nconst Select = (state, selected) => [\n  {...state, selected},\n  jsonFetcher(\"https://jsonplaceholder.typicode.com/users/\" + state.ids[selected], GotBio),\n]\n\n```\n\nHere, `jsonFetcher` is what is known as an _effect creator_. It doesn't rely any special Hyperapp features. It is just a common way to make using effects more convenient and readable.\n\n[Live Demo][12-effect-creator]\n\n### Effects on Init ###\n\nThe `init` property works as if it was the return value of an initially dispatched action. That means you may set it as `[initialState, someEffect]` to have the an effect run immediately on start. \n\nChange `init` to:\n\n```js\n[\n  {names: [], highlight: [], selected: null, bio: \"\", ids: []},\n  jsonFetcher(\"https://jsonplaceholder.typicode.com/users\", GotNames)\n]\n```\n\nThis means we will not have any names or ids for the persons at first, but will fetch this information from a server. The `GotNames` action will be dispatched with the response, so implement it:\n\n```js\nconst GotNames = (state, data) => ({\n  ...state,\n  names: data.slice(0, 5).map(x => x.name),\n  ids: data.slice(0, 5).map(x => x.id),\n  highlight: [false, false, false, false, false],\n})\n```\n\nWith that, you'll notice the app will now get the names from the API instead of having them hardcoded.\n\n[Live Demo][13-init-effect]\n\n## Subscriptions ##\n\nOur final feature will be to make it possible to move the selection up or down using arrow-keys. First, define the actions we will use to move the selection:\n\n\n```js\nconst SelectUp = state => {\n  if (state.selected === null) return state\n  return [Select, state.selected - 1]\n}\n\nconst SelectDown = state => {\n  if (state.selected === null) return state\n  return [Select, state.selected + 1]\n}\n```\n\nWhen we have no selection it makes no sense to \"move\" it, so in those cases both actions simply return `state` which is effectively a no-op.\n\nYou may recall from earlier, that when an action returns `[otherAction, somePayload]` then that other action will be dispatched with the given payload. We use that here in order to piggy-back on the fetch effect already defined in `Select`.\n\nNow that we have those actions – how do we get them dispatched in response to keydown events? \n\nIf effects are how an app affects the outside world, then _subscriptions_ are how an app _reacts_ to the outside world. In order to subscribe to keydown events, we need to define a _subscriber_. A subscriber is  a lot like an effecter, but wheras an effecter contains what we want to _do_, a subscriber says how to start listening to an event. Also, subscribers must return a function that lets Hyperapp know how to _stop_ listening:\n\n```js\nconst mySubscriber = (dispatch, options) => {\n  /* how to start listening to something */\n  return () => {\n    /* how to stop listening to the same thing */\n  }\n}\n```\n\nDefine this subscriber that listens to keydown events. If the event key matches `options.key` we will dispatch `options.action`.\n\n```js\nconst keydownSubscriber = (dispatch, options) => {\n  const handler = ev => {\n    if (ev.key !== options.key) return\n    dispatch(options.action)\n  }\n  addEventListener(\"keydown\", handler)\n  return () => removeEventListener(\"keydown\", handler)\n}\n```\n\nNow, just like effects, let's define a subscription creator for convenient usage:\n\n```js\nconst onKeyDown = (key, action) => [keydownSubscriber, {key, action}]\n```\n\nA pair of `[subscriber, options]` is known as a _subscription_. We tell Hyperapp what subscriptions we would like active through the `subscriptions` property of the app definition. Add it to the app call:\n\n```js\napp({\n  ...,\n  subscriptions: state => [\n    onKeyDown(\"ArrowUp\", SelectUp),\n    onKeyDown(\"ArrowDown\", SelectDown),\n  ]\n})\n```\n\nThis will start the subscriptions and keep them alive for as long as the app is running. \n\nBut we don't actually want these subscriptions running all the time. We don't want the arrow-down subscription active when the bottom person is selected. Likewise we don't want the arrow-up subscription action when the topmost person is selected.  And when there is no selection, neither subscription should be active. We can tell Hyperapp this using logic operators – just as how we do conditional rendering:\n\n```js\napp({\n  ...,\n  subscriptions: state => [\n\n    state.selected !== null &&\n    state.selected > 0 &&\n    onKeyDown(\"ArrowUp\", SelectUp),\n\n    state.selected !== null &&\n    state.selected < (state.ids.length - 1) &&\n    onKeyDown(\"ArrowDown\", SelectDown),\n  ],\n})\n```\n\nEach time the state changes, Hyperapp will use the subscriptions function to see which subscriptions should be active, and start/stop them accordingly.\n\n\n<img width=\"570\" src=\"https://user-images.githubusercontent.com/2061445/116821228-4f9cca00-ab79-11eb-9528-7f6d37641ea2.png\">\n\n\n[Live Demo][14-subscriptions]\n\n## Conclusion ##\n\nThat marks the completion of this tutorial. Well done! We've covered state, actions, views, effects and subscriptions – and really there isn't much more to it. You are ready to strike out on your own and build something amazing!\n\n\n[1-hello-world]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgUEQhMawfACehFp8WgDmpPDwbjzFkYHWKbHWCZ7Wzq7uPOYgBM4IbXJcwgDsSABMOCAAvni8AkIiAFZcMnIKSsIQYMbkpOJawKJ4WgoAHuKHJsYTWqwUYFqGEuLGhEhWVsRQPBiEANa5xnxiD8MFB4BorKJ-vBSBdDA4HBcABTAGoaCDwADuSC0iIAlFpdOYtKJEYYwHwIDxDIdgFMtDQat4SYZbNS9sQcoQXvcQMZoYQ5IY6QyvIEmaTeWzaYcTuIJQAJeBUchaDHbWBQQy43F4RlaJg6moG3WinjkUHYqDkYhxQTyDDFCoAUQQdvEACFcgBJKAS2EgQ08Ca4hxdECyTYcaHKABGfBjSrDPRcbn6ygAzEgAIx0SbTED8QTKDDELlh2TyRTiZQAAQ2Wx2WjipFgiIA5I9nq93p8MItQSkNKQMDwKlYeMYwFYMXwFMPS4QayMrOQ4uIrClihIS1y27iANzwnhICjkXYo0UAWkvMfIx0vGOg4lE2JGdDoxmOh6DR-JlL2WhbIQECpseWhlDkbgaPA+4TEeGB8qQApeBe3i3vewEAF6UsU2K3qQoKkDed7ft4j5QM+2IaHwpCIte6EPk+ogHjUAIwDh2I5p+WhcccPEfnxKACaRgHkMBoHYhBs6aDBNT4YRnHcQAxDAUBaAKKRQCJ8nQpeMLqHE3I4J++7eDU5KkMUlLEeI4jkGAnHCTUNpIds2JbJSc7fnBVJfIhyFiBAW6bhIexyYCPylKuPBQJesiwG5WhKawUBYN5DgIfycjfEqKbwGpqFaDpRHkZRWjpiZcnbIRcWUIlSk4DgxAiWx6hVJednGNiAAclWiq1OE2XZDlaL1X4OD5GX+XIOgTmuNDiFCujEKILg-OhTBhf1Ykge02Lxhpa6yaKLkCqQlrwKwfAJOIImdY5fXeAgrDiNigx9T5mWuV8yauPls3GPNi18stq1AhtW1PZdr1aMZ42ivdo0ffB01eMYkNaBZVlgXQIlY9Zz0wyMyN+VlP25X9ano4V+M8JehPYrjE33L5GAxu4GNAbtcj7TGh0KCJDNaMQfCwMQiLUbR9F3oxFHMVoADUWgjGUYAsQj5BdVoaBOSddXnUljXNTUrArJehCLQg2IgaLEDG6KpvyObECYfAr6q3d8CnJelKgvI2KXlmHsTRl7PhAmptlOyKxVtibaGG2sGh+4SB8C90LR5W-taPHICJz5SYU6BAwgHQSB0JeOBYOXkxMBMQA\n\n[2-render-with-state]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgUEQhMawfACehFp8WvyChTxQhVrEoi4A1gBG5AAekYHWKbHWCZ7Wzq7uPOYgBM4I-XJcwgDsSADMaCAAvni8AkIiAFZcMnIKSsIQYMbkpOJawKJ4WgpN4lcmxotarBRgWoYS4saESFZWxFAeBhCLVcsY+MRahgoPANFZRGD4KQHoYHA4HgAKYCtCA8CDiJDnYprQmGAAy8D4PB48C0AHFkaIBIYrqIIABzUQpTkE66kOK05atDQQeAAd0JhHEfAUWl05i0ogxhjAfFxLPOyy0NFa3iVhlsGuAxByhB+7xAxiRhDkhi1Oq8gT1ystRq1N3EGKlMvgGBK8AAlAG8LrAvqQLjjHFxEbxIjSSBqnVGi1hlUapD4FBJdKFGIOVyC+JFsHQ0xS47yyHHTxyDDCVByMQ4oJ5Bh2fBxABRBCt8QAIVyAEkoC6USAKyWHMNE+Qjhwkcp6nx6vBpEQ1y43BNlFhUABaFBIAAcSxWIH9ygwxDNM9k8kU4mUAAFDsdTlo4qRYBiAOSfb5fn+QEMC2GEUg0Ug-U7KweGMMArDFH0oJvQhnwAJischoysbkJGvM1fwDABuNEeCQChyDObFHX3fcU33MVoHEURCXQug6GMJpSJ4RYyNVXEiWOQh8QGQlSDXGVNHgYi+J4BwMCtUgbS8GjvAYkSAC9cXZQlGlIGFSHo5oeO8JioBYwkND4UgMTohjzJYkjWnBGAdMJABGTimi0LyuN87ytBQbzTK0YTRLkcTJLcDQZNafTDM8-yAGIYAqG0UigUKEqRfdkXUOJzRwLjiO8VpVVIdlcWM8RxDnTyQtaZtlJOQljlxBRSB4uSFKUlT805PDqPiiFanZCg4nKfdZFgVqtGS1goCwbreutORgU3Vws3OeKTkMxjmNYrRZhK3aDNyma5uSnAcGIULXPUHh2X3OrjEJY9TsdB6dJquqwHez6eqBPq5B0ODoxoOMrV0JNIRTJgdq+8gRO3cjCnqDLozix1mptUgG3gVg+AScRQtehrPu8BBWF5KZAdWlqgVGLdtsjCGofgGGMwaZoEbUrRqd5YruNacmtA+kXeLIxS1q8YxEe8CqqrRuhQqV6rBbY+ngdljaxgUCp5f59WeH3TWtFVhwnml+p3AVsLkYitGV0xhRQvN4g+FgYgMWs2z7OaA6LNEAMtAAai0dCJLAZzHTFtBGpxygrpuu7WlYXZ9ylXIEEJfEvYgNPHQz+Qs4gTT4DY6OyfgW591xGF5EJfcPOrq2FNt8JVwziTznvPZeV-Qxf1kjv3CQPgaaRPvdkfQkh5AEe5JnZnxh4SYQDoJA6H3HA9zoJYmEWIA\n\n[3-class-objects]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgUEQhMawfACehFp8WvyChTxQhVrEoi4A1gBG5AAekYHWKbHWCZ7Wzq7uPOYgBM4I-XJcwgDsSADMaCAAvni8AkIiAFZcMnIKSsIQYMbkpOJawKJ4WgpN4lcmxotarBRgWoYS4saESFZWxFAeBhCLVcsY+MRahgoPANFZRGD4KQHoYHA4HgAKYCtCA8CDiJDnYprQmGAAy8D4PB48C0AHFkaIBIYrqIIABzUQpTkE66kOK05atDQQeAAd0JhHEfAUWl05i0ogxhjAfFxLPOyy0NFa3iVhlsGuAxByhB+52MSMIckJ4n58FZHK5Tt5Upl8DETu5EkWWp1XkCeuVIDMw01Vxu4gxboUGBK8AAlAm8LrAvqQLjjHFxEbxIjSSBqnVGi0w0XIfAoJLpbG2ZzveJFsnU0xmwHWymAzxyDDCVByMQ4oJ5Bh2fBxABRBDD8QAIVyAEkoMGUSA202HMNC+Qjhwkcp6nx6vBpEQTy43BNlDhUABaG9oKZLFYgePKDDEM1b2TyRTiZQAAKHMcpxaHEpCwBiADknzfL8-yAhgWwwikGikHG45WDwxhgFYYruuhn6EABABMVjkNmVgNh+ZpQQmADcaI8EgFDkGc2IBret4lreYrQOIoiEiRdB0MYTSMTwixMaquJEschD4gMhKkCeMqaPA9FSTwDgYJapDWl4HHeDxCkAF64uyhKNKQMKkNxzQSd4fFQAJhIaHwpAYlxPHOQJDGtOCMAWYSACMolNFoYViZF4VaCg4WOVo8mKTaWgqTkbgaBprTWbZoXRQAxDAFTWikUCJblSK3si6hxOaOBifR3itKqpDsri9niOIO6hQlrSDvpJyEscuIKKQElaTpekGZ69YuucOUQrU7IUHE5S3rIsBDVoBWsFAWATVNVpyMC56uJWC0BpVdm+YJWizI1OUnLZG2UNtBU4DgxCJYF6g8Oyt7dcYhIAByPQGv0WZ13VgKD4OTUC01yDo2HZjQeaWro5YNM0TCXd4yWXsxhT1KV2bZQGA3WqQfbwKwfAJOIiVA714PeAgrC8lM8NHYNQKjBeF2ZmjGPwFjNSQiWeNGVoHO8g14mtCzWhg4rklMbpx1eMY+NaK17XE3QiX6x1ctCTziNa6dYwKBUOsyybPC3mbWhGw4Twa-U7i64TSkk2TCiJS7xB8LAxAYu5nnec0vH8aICZaAA1FoJEqWA-kBsraB9ZTb00ztn3fa0rC7LeUq5AghL4qHEBFwGJfyGXECmfAQlp8z8C3LeuIwvIhK3iF7fuzpXvhMeJcqecP57LyUGGFBmkj+4SB8JzSJT7sf6EnPIAL1pW4C+MPCTCAdBIHQ95YOfSxMIsQA\n\n[4-toggle-highlight]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQAq5ADmWQha4qLwWsSFxADWAEbkAB755HU5eQVFohBZoint4pGB1imx1gme1s6u7jzmIATOCGNyXMIA7EgAjABMIAC+eLwCQiIAVlwycgpKwhBgxuSk4lrAonj58NXiTybGm1qsFGBahhJxMZCEgrFZiFAeBhCGUAJ7GPjlDBQeAaKyieHwUgfQwOByyHiEO6ZRrwAASbQ6lLuui0RL4Ci0unMWgAFMAtBgufSFE9Wu1OhIkFoAIQ8+BiSmCu6bACUeP4pnZPQgPAg4mFHP4gmFhgAMvA+DweEUAOLY0QCQx8qXU4XiUhxIrbHoaCDwADuwvFTJZolZhjAfFV1vu2y0NB63n9hlsoeAxFgfEIIPuxixhDk9sd8BtArtdPEDIl-KpXU24cjXkC0YDIDMUzDTwUr1Z4ow2vgstleCjgRjIFVxji3UbwD7NfEmN1IBKLkqNWtE8Cc-K8Cg3qLCkl+a6verNe8ckTEHKwpJuXJtr3y7l+5rTB7PUf960PHIKOFUHIxDignkGBZPA4gAKIIP+4gAEKwgAklAdY4iAT48HKDhTLO5BXBwWLKBUfAVPA0hEIRLhuPMyjrEgADMVFbDsICdsoGDECm6EEmc4jKAAApc1y3FocSkLArIAOSAsCoLgpCGBHCiKQaKQHbAVYPDGGAVgesWiksYQXFrFY5AjlY0rMSmImygA3AqSAUOQdzjtWAC0jlVNUjketABTCmsdB0MY1RWShCpBqq9xaNchDquMwqkIRDKaPAFmbAqGDpqQmZeA53iuY5kUAF6qlkwpVKQKKkC5NSBd4HlQF5WgaHwpCss5OU1QUlk9AiMCFcKKx+bUfX+Vog21Cg-VVeF5CRWRPAxXFbgaIlPQlWVvVDQAxDAUB0pQ0ATStWKOdi6hxKmOD+RZ3g9EGpBZKqFXiOImG9eNPS-ulNzCtcqoKKQgXJTwDipRmcg7mWEj3MtiJlFkFBxDwUCObIsCfVo62sFAWD-UDaUZdCJGuOukPVgd5VtaIwpURdy03GVSOUKj604DgxATV16g8FkjlPcYwoABzU9W7OFQ9T1gPzgsAzjINeEOI40FO6a6KuC7VEwxPeBFUVZlo+GZrAI5LdW72ZqQX7wKwfAJOIE08y9gveAgrAaloiyS9LH1QjMpFE3L4gK5iyulKr6tZVoTsu+dAU9HbWgC9HQWA1CuNyOFGtaDdd2zVodATZn90R957vJzL+OzAo23GOn+c8I5hc5-9-xJxgFTuOnWszcKeuUIbE318QfCwMQrINU1LU1O5nmiLKWgANRaGssVgB11ax2gr3GwzZto8zrM9Kwpy5VOCDCuqg+nhNB-yLlEB5fA3lL7bLziI5qoovIwqOSsj8OADLfuEgAiB9Yr3HYooF2IlDAiSSkDVu4Q+DOyxKA044DhSQJANAgG6FvZzEJMoOgSA6CORwFgQhWwmCbCAA\n\n[5-view-component]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQAq5ADmWQha4qLwWsSFxADWAEbkAB755HU5eQVFohBZoint4pGB1imx1gme1s6u7jzmIATOCGNyXMIA7EgAjABMIAC+eLwCQiIAVlwycgpKwhBgxuSk4lrAonj58NXiTybGm1qsFGBahhJxMZCEgrFZiFAeBhCGUAJ7GPjlDBQeAaKyieHwUgfQwOBxgrQAWmJWgAggBhdIASQA8gA5ADKROJeJ4sh4hDumUa8AAEm0OgK7rotJy+AotLpzFoABTALQYRVihRPVrtToSJBaACEyvgYgFGrumwAlKyCcTCVoAGpUgCiAHUtOSaQBZAAK9LtdPSTMtrPZnK0xixhDkkuDFGBktiohlhlshiewB63mIsD4hBB91TgRDpDDPC14lIcXgeFz3jVgq6WuMUcIBvVQtzmx62y0NFzccMZim9w7CleMvr5GBGH4ghNJorXkCPZAEB4xji3X7KbngXymK1hhKLkqNSTleKpTK8CgdYbTZrElnW+8cnTEHKV7HjdO2Vy5dbM56TDNHh8SsZkrQAJQAVTpUDWQ+OUeiXCBxC1eVJ3gXcQAAGXgPgeB4IoAHFsVEAQky0asjWLUsim2HoNAgeAAHctT1GNyPjcA+CXMjgA7LtN2DUM5HggTvDQljxHFfU0PvB8KKFCSpJvI1ZK3T8eS1blv35ZsulUrRTVkgDZJ4cgUS1KByGIOJBHkDAsngcQ7QQWzxAAIVhKkoA4nEQD-HhTQcKYQFkK4OCxZQKj4Cp4GkIhYpcNx5mUNYAA5Vg2bZdkEZQMGILNgvZM5xGUAABS5rluLQ4lIWAZQAckBYFQXBSEMCOFEUg0UgJ0cqxlzAKxGKknr8sIUq1ischVysI08qzeqTQAblZJAKHIO4N28YkqmqQlGOgAotTWOg6GMaoVoC1kwC4rx5WuQgkPGLVSFi8VNHgJa2yAqF80LHM512wlHoALyXLItSqUgUVIQldsu7wDqgI6tA0PhSBlHaan2w7RGWnoERgcGtRWM7alJ86tAp2oUDJhHg3IR6kqLLRXozNwNE+nooZhknKYAYhgKBRUoaB6Z5rFCWxdQ4mzHBzqW7wehu0gsiXOGNvEcgwBJumemsgsbjrcglwUUhLu+hwMD+uRlKFAHvCi8osgoOIeCgQlZFgI2tH51goCwC2rZtqEZkSi8Ha0CXYaRlGAGYFe5m4Yc9ygff5nAcGIenCfUHgskJLXjC1VLE7nXPwY18QtZ1rRS4uhxLd+oSvCXFdxBocRMV0fdyl2phI4ep65C1aKw1gVcubnA2w1ICz4FYPgEnEemi91svvAQVhkK0RYy++62W+hBLXAjtvV077ve8PaoB62rQt53+WG7nNe6-31lD8NrxjEjlW1ZZnQem-91aP2Oh-Zu39j6zAUMLX+98QE8EJGArQQDG7-B+hgCo7hB6M2HizMelBJ70xQcQPgsBiAyjRhjLGe1Y54y0AAai0GsV6YB8avzHFqNAetp5pznr7TO2ceisFOMDLuCAtRIXIS+emoj5DAwgCDdCLC2GrxeOIQkS4UTyC1ISFYajG5W2weEGKojXr3CKooHe9VDD1S+sY9wSA+DbyxJY041itS2JAPY76wUw5zA5MoOgSA6CEhwFgUJWwmCbCAA\n\n\n[6-action-payloads]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1imx1gme1s6u7jzmIATOCJNyXMIA7Eg4dCAAvni8jcoYAFZcMnIKSsIQYMbkpNXAonh5leJPJsZbWqwUYFqGEuJjIQkFYrMQoDwMIRsgBPYx8YjZDBQeAaKyiOHwUjvQwOBygrQAWmJWgAgukACoASQA8gA5ADKROJeJ4sh4hGqFPIbTaCAAEu1OkLqrotAAKTl8BRPCA8FElACUWl05i0wH6BLAfGyTUIoj4VHIAHctMRYHImuRWFpbu05YaWkKuhI6qRsTD+ghqq0Oi7RVoaBhg1KFGJnSKmKzvATWCljHkCr7hd0tBpDXErTa5QqdF58k1ZMZPV4nX6RTQc5UmCqtABCZP+yvy6v9TVWLSkeDiOKkLz6w0W01FmG2m3kXtaUPwJ5d4ywBFytp-UsEgtllOuvjuvij429US2ycVU2W-pdnt99VaYNQ8TSmcb-1bBwvnj4jvEwlaABqVIAogA6lo6Q0gAsgACvS-50hSTJfqy7KcloxhYoQci1sYFBAiqsSiOKhi2IYTwaqW3jmnwhDAuq-SBChaFyEgeSkJmeC0YEjYikxWHkEC4blt07Fvt4OyBux+GGGYszqqJChVOKPF8fwgiKoqbFkS0BEgHKxhxH00mkXR3jiJiTGGMQWSIsUJTEex5GWbqUDcdhhD8Zurx2babIpIizm8a5Zw8nyM5CWp-RMIqrIEl+WgAEoAKp0syhKsu84qGXmvRMRl3jKfAwIAAU0J5hgADLwHwPAVFoADi2IGmAtkad4hj-qQGhylo-ImvAVBNUZfwgOkCCCPIcpNAAQnwcQWf1RmGBB0qkBAxAQPU5WFIQCLZHNdGGJkvXOKOQQQN2y2zbM7EsOJEbdExxXNV8hrOOpA3iCxIWPawz2fQN32wC9nn-YDGnXaWOz9B18DGkx064ZphjanKxEyU8D10be04YHlrnasY4rinlsotkq8OoaQ6E8OlnlE55nF3VO95hvTEjNgqYMDYFvIIPd3Lc-AgoCRIxPs69gRbKpYsRWLPDkCiTFQOQxBxKN4gYG03b-iNijiBNMJUlAWk4iAYU8BLDizCAsjXBwWLKIUfCFL1lvzC4bhLMoADMSCbDseyCAcxBUZb7LnOIygAAJXDcdxaL2sDigA5ACQIgmCEJHIQKIpBopDY92Vg8MYYBWMaD550HhARwATFYE7iFY-oYJXieKgA3KySAUOQ9z9MS1mEvuUD5Ex1d0HQxglB3ZuskjXjACh5CEL0UxMV2C5uBo8Bt2+DgYOTlM0aWA-LwAXkuTHFKQKKkIS1nT94Q8j2m27iv3pSD9A+Tt-08IwBfWgACME8yjAMnkAkBWgUAgIfovZe7seBr16tKTQ29+hXxvkxQB4CADEMAoBTkoNAWBGCsSEmxOoOI1EcCTzbi1Us2pSBtDlHfHu4hyBgCwTA-oysKa3G4uQOUChSDT13pCA+cg3L+iPt4B2iI2gUDiPKQksgLSkCYjg1gUAsCiL3hIyErtXDwAIRlUht8n6iCYp7Wh6Dbg3xUZQfhWgcE4BwMQWBf91A8DaISdhxgmIAA4bGlk8UuVh4h2GcK0EEqer5WT7wYl4HSekaAmVQroCyORrI1gyjceBq86ibUoHpNBpZeHoXUVoFE30EjiFgX4rhwTvAIFYOIJiKxglvgSXwgxvU3bGLzLpcQqTMQZIctkmRWgWltK0DQ2JpYGnRM6fE-RKFJmMOYYgrQdBYEbJYdM0eyzxGJKhH0oxBCEwZT2TwQkBztmiJXHvQo7hJl5JXoxQp6FYAlNgXc4ghpiDinTKQN+rCSif2HqIZUABqLQ1cuxgB-gs3iTE0DcLKY4ypLi3GwNYGcQknIYQ8x0PeHyuL8Vn3gKPBF9SXiEirPIJihJAE0riZCZ54QnZ4q7OqUOOsmKJ0MInHeTz3BID4K0rEvKzj8q0IKkAwq3wuzOQg5YIA6A+0JDgLAPtthMC2EAA\n\n[7-with-selection]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo17HCZ7Wzq7uPOYgBFsubnJcwgCMdEg4AEwgAL54XiNZQYABWXBkcgUSmEEDAxnIpGqwFEeDylXE6JMxn+WlYFDAWkMEnExkISCsVmIUB4GEI2QAnsY+NMMFB4BorKJmfBSDjDA4HFStABacVaACC6QAKgBJADyADkAMpi8VCniyHiEaoy8htNoIAAS7U6Zuqui0AApdXwFOiIDwOSUAJRaXTmLTAfoIaqtDpdCQerQ0DDhu0KMRmoPiJj9APm7o0J0upghgCEidjKedlXjZ1I8HEcVIXmAWnD9PE9vg6OzFv+DibPAc2t1WhV8G2lptkbrWieOyg7s9NuAVf76KHCig-1dmpF4tFWgAanKAKIAdQmCoAsgAFZUbpUytXLzXt6rGPmEWZW4wUcke2Kia2GWyGdE+s7eYiwPhCApb0jm8G9SDvHgkDyUg4jrUCWhjC1oMfchyWjQMLTwBCZ12FCn0Ielu2eXZ0UCEUVAvX8tEBI45H-CBpnwtDCNeYjXDI8YtAoqjvEBUMjjfQwzAeb1+IUKprVQ9D+EEV1XWw6ihJAJ1jDiPpRJ-Li8l5aDDGILJpmKEovwQgycjwrRpMIhtukU7T6KmbJmPQ6EDSNeDqPneytCYBdWx4JcJQAJQAVSVdVRU1HFrS0nQeF6aC4u8WT4ApAACmgEMMAAZeA+B4CotAAcX5UQBFM6jvEMDdSA0J0tGNcgAHdu1gSrtMMSZQkUNwioAIT4OIDI6rjDAPe1SEYiB6jywpCFZbJRvGLqslgZxGS0IIIGLKaRoeI4WEEpDumgrKqvxPh1s87TxFgm6uNYK7nB88Ynuu17Anel7Ds+3CoGgngElgdF+los56vgZroP7F8WnfcA+CdL8xPRc7xknGso1SwilmMa1rVSx08zdOHwMg2KEKJhDbIkGGsfgDCkwkXM00+7w3MNBAzv1Ln4FNTC7PitmcPY2d6drIie12D1dCtVNKnRHjeK4tiezOrse2JtntPGZWNS8+SfL8nyeHIDloKgchiDiQR5AwNpiw3BA7fEfrGTlKAEYFEAFObfyHhAWQEQ4PllEKPhCm7QOZ1uN4QHeABmJA6ABIEQFS0FiCAwPtRhcRlAAAXhRFkS0UtYGtAByUlyUpalaXBQgORSDRSAwCpxCsHhjDAKxmtrdvs8IQufisch1JOC0MGHqvXQAbk1JAKHIFF+nFYzRWa6B8mgn46DoYwSkXngWwcJYGorRFCF6W5oKLAC3A0eB57PulydmOLN5vgAvJ02mgsUUgHJSCimMifbw28oC7y0BoPgpBrQb1KFvHeogF79BZDAf+0FPhHy0LgsoBCtAoEPsfDB5Ab4vCgloB+9pNAv36EAkBOC8EAGIYBQEHJQaAECihIhAaKfk6g4jARwEfee1UzhLFIG0J0YDV7iHIGAHBpDeE2wgkiFC5AnQKFICfN+GAP50lpmvM4EdphtAoHEZ0opZCwE0VoVhrAoBYH0Q4Qxt45BSxIpwr+-C+QoOgaIaCidxGMP8aAuxDjWE4BwMQXhmD1A8DaKKRRxhoIAA4wlnESf-eR4hFHKK0Fkshp9NQeI0V4VS6kaDiF5LocyRlSjpjitfW+choKRzvLAdSDCzjqLvKQS28AnoJHELwtJKjsneAQKwcQ0EADs2SWwVMgt44c8U1LiFqfUxp2RjItN9CM+ZWgxGlO8JM4pyzylGKsiBKR8DZHULoLw6RTzRSzJOT8a579PF0n+ncuKby5GfOgi85sxIAoYEKO4e5YEKHtOoV0ygvTeGgq0MQK6xBrRwIQUgkogT8jugANRaB+EWMA6CziXLQKo-oUShmONifE-orBoSil1IybmOgaxTF4Wy+QHKIA-3gHvClEzMSigVvIaCop3jiubO4mF4Qo5sqLN6POvVoJV0MFXV+Sr3BID4HMvkGroRaq0DqkAeqWwxzFnHZQXw6CihwFgFOAImD-CAA\n\n\n[8-separate-highlight-selection]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBql+tYEp5rM5XO4eOYQAQ-nC5FxhABGADMSBwdBAAF88LxGsoMAArLgyOQKJTCCBgYzkUjVYCiPB5SriDkmYwErSsChgLSGCTiYyEJBWKzEKA8DCEbIAT2MfGmGCg8A0VlEKvgpF5hgcDmlWgAtBatABBdIAFQAkgB5AByAGVzRbjTxZDxCNVbeQ2m0EAAJdqdcPVXRaAAUfr4Cg5d01JQAlFpdOYtMB+ghqq0Ol0JBmtDQMOX4woxOGi+ImP0CxHujRk5UmCWAISN2stngp+tnUjwcRxUheYBacsK8QJ+Ac7uRgkOJc8Bw+v1aV3wbZR2OVudaFEKKDpzOx4BT-cco+7Ampr2mi1mrQANXtAFEAOoTR0AWQACi677Ora7pPl667VMY+qELM0bGBQEoZrEogxoYtiGByOZnN4xCwHwhCStmRzeNBpCwTwSB5KQcRziRLQ1pGVEIeQErVoWkZ4PRN5QMxiGEAq27-LsXE4VoRJHHIeE3NkfGsQJaJCa4oneESpZHKhhhmEi2ZqQoVQxixbHAvAqapipgSaSAdzGHEfQ6dhlx5HqVGGE8OSvJh9HudMuxyWxC7dBZ4xSVMsmxgA+hyWqKOIp5Zo5TlaDF8jTqx-6IXwbQJvCMb3mJ4xDiOY5aEZCnyIGwaHAV4nBeJ5n9Ew+UmlYHrPgASgAqs6bVeryMaJXcvRUYl3gmZKAAFND0YYAAy8B8DwFRaAA4gaogCF5NWGO+pAaHcWghuQADu26wFtTmGJMoSxXcTQAEJ8HETwXZchj-gmpA3BA9TzYUhBqtkr3jFdWSwM4SpaEEEDDl9L1IkcLAaYx3RUdNNWsHw4N0TV4g0TjTmY9jdXeETzgkwKWPk4jdU8VRPAJLAHL9BJZz7fAx1UfuyEtGh4B8HcmG6Ry6PjJeM5VuNGBLMYMYxiZSZ9pU8WlTBcgDfRCv0YFEhcxL8DsU2Ei9v2FM0pVCBowGQahijEiK6b3FKceeuzoJO67BmujRq2JRm76zto1uO4O22dV3g1ZxNRZPDkJqVHvMQcSCKlbTDu+CAp+I91KvaUB84aICR3eDhIiAsiMhw+rKIUfCFNuZdHvC6IgAATAAHEgrf4kSJKCGSxCEWXPq0uIygAAIMkyLJaKOsAxgA5GKEpSjKcoUoQmopBopAYBU4hWDwxhgFYx2zrvg+EOPrdWOQdknJGGCXwvqYANxekgFA-MRZwWq8ZrHWgPkKi3c6DGBKO-HgK4HBLAOhOJkhBejwiokOfCbgNDwFftA+UZEKI-28P-RBAAvO4bQqLFFIJqUgZpXiQO8IAqAwCtAaD4KQGMf9SgAKAaIN+-RVQwFIVRDEYCyjCPAVoMRZQUAiLoaVcgiC3ByBQduHKGDZEUKoUI8RABiGAUBDyUGgOo5kVCzQGnUHEIiOBwGv28P0JYpA2h3BoT8cQ5AwBCJkf0JO5FmTMXIHcBQpBIHYIwLguQhtaz4KKIDNoFA4h9jNLIWAfitDaNYFALAISHBhLVvKHi0SNH6i4Yw0QVEsQ2P6EU6hyTUnaJwDgYgsj+HqHuGaNxxgqLt0qWcFppCXHiDcR4rQ3SIHLi9Lk3xXgbJ2RoOIPUugfLZFeO2RKCCkFKLqP9SgdlMHeNHLBUgCd4CYwSOIWRHTPE9O8AgVg4gqIAHYekrkmRRd2wl9EzPEHMhZSyVnRNufcrQ1ixlnEuSM55EzwleGMNEhxTjKJaDoLI+FzjAUgMhTgvJ7ydj6NhYlVFPAzToqRSEkUq55SFHcNE9ZijEV11grAXZsiSXECxsQGMLC2EcJKCU-I6YADUWhW5DjALwsFrEqJoC8WcWpRy0kNKaf0VgNIzR+iVJbHQM4piyJVfINVEAiHwBAaKi5XIzStnkFRM0GJTXjMpe4JA9cVVDmzCPWKVEF6GAXlgnJVLwh8DufqN1NIPVaC9SAH1K5G7O2bsoOgSA6BmhwFgRNhImAEiAA\n\n[9-conditional-rendering]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBql+tYEp5rM5XO4eOYQAQ-nC5FxhABGADMSBwdBAAF88LxGsoMAArLgyOQKJTCCBgYzkUjVYCiPB5SriDkmYwErSsChgLSGCTiYyEJBWKzEKA8DCEbIAT2MfGmGCg8A0VlEKvgpF5hgcDmlWgAtBatABBdIAFQAkgB5AByAGVzRbjTxZDxCNVbeQ2m0EAAJdqdcPVXRaAAUfr4Cg5d01JQAlFpdOYtMB+ghqq0Ol0JBmtDQMOX4woxOGi+ImP0CxHujRk5UmCWAISN2stngp+tnUjwcRxUheYBacsK8QJ+Ac7uRgkOJc8Bw+v1aV3wbZR2OVudaFEKKDpzOx4BT-cco+7Ampr3r6oAcR+ACF3CW4zPE1ooAm+KeWYxheFbfgehTuEgv7-hgsiMnwPBKhghSEHeXqmhaZpaAAavaACiADqEyOgAsgACi6eHOra7qYQ+aLVMY+qELM0bGBQEoZrEogxoYtiGByOZnN4xCwHwhCStmRzeExpAsTwUHiKQcRztJLQ1pGUHseQErVoWkZ4GpN5QFpHGEAq27-LshnCVoRJHHIok3Nkpk6eZaKWa4NneESpZHDxhhmEi2a+QoVQxtpunAvAqapt5gQBSAdzGHEfTBUJlx5HqUGGE8OSvAJal5dMuyubpC7dPF4yOVMLmxgA+hyWqKOIgFSbZ4zNfI046WRHF8G0CbwjG94dYEQ4jmOWiRe58iBsGhxjfZtl3vFTCjSaVgelhABKACqzrbV6vLAf0dy9FBGWBNFkoAAU0GphgADLwAhFRaE+BqiAIhVjYYeGkBodxaCG5AAO7brAv2ZYYkyhC1dxNK+fBxE80OXIYZEJqQNwQPUL0oWq2To+MsNZLAzhKloQQQMOONo0iRwsP5GndFBD1jawfAU6pY1KSpVWBFzPOC94wvOKLArcxLTOC8ZUE8AksAckcEHhCKIACZlWimiodFnMt3hA-AYNQfuXEtLx4B8HcWvAL5HPjJeYEYDdGBLMYMYxtFSZ9pUbWyfJp1jT7akVRIZsu+H4i9v2ks0vNCDswGQahqzEi+3HRmecekezhZO67BmujRq2JTx76Ofs1uO6Z22gt3nFRz7shH4AGRt9rXfdz3uv6+MiX8elWiieJkmGGr+yhVyX752rsUcjrW1656ZzrfFPDkJqUHvMQcSCN1bTDnhCAH+Ir5KvaUBW4aIBNzwaE8EiIBwcYHD6sohR8IU27P0e8LohADgHASAMT4iJCSQQZJiASWfj6Wk4hlAAAEGRMhZFoUcsAYwAHIxQSilDKOUFJCCahSBoUgrthxWB4MYMAVgwazgoTAwgSCABMVhyCpROJGWCElsGpgANxeiQBQH47VvAWleGaMG0B8hQVYXQOgxgShCIfl6JYwMJxMkIL0eEUEhxiTcBoeAAiVwOAwIHWYV0pE6IAF53DaFBYopBNSkDNK8VR3gZFQDkVoDQfBSAxkkaUaRsjRCCP6KqGADioJgOUVoOJZRElaBQEolRkTyA6LcHIfR24hrGM8UUZkrjYnxIAMQwCgIeSg0BCnONcWaA06g4iSRwMogR3h+hLFIG0O47ifjiHIGAWJaTCl7zksyLS5A7gKFIKosx8pLHymjuIooRM2gUDiH2M0shYCTK0GU1gUAsDzPMUsguVkqnWOKfqUJPjRBQSxO0-o9Tbm7P2WU4BxBClRPUPcM0gzjBQQABzPLOL8hx-TxCDOGVoUF6S1GrkWcxWYyVUo0HEHqXQxVsivHbFdbRuicl1BQpQVKJj+jjJYqQHe8AuYJHEIUwFIywXeAQKwcQUEADsYKVwWJRfKYyOgaHosxUxbFzxcWlHxbmOlnKtBtIRd4ZlcLeVen5RMrwxhVndN6QpLQdBCm6r6ey+VrC1XIs1RcnYVTtVXWNTwM0pqoKGuXCKJFrdagEsyUS-V38WKwHJYU51I9ubEBjP4wJwSSh3PyOmAA1FoVhQ4wARLOCqtAozKWUA+V8wprAaRmj9EqJOOgZxTHzYWux8B5EpqZVyM0rZ5BQTNBiOty5zFqyQD-AtQ5szwJalBbBhhsGmM7ZBPgHL9T9ppIOrQw6QCjpXH-HOADlB0CQHQM0OAsCbsJEwAkQA\n\n[10-effecter-with-dispatch]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBqlQRdLgBleDbNz3ObApqseDiJ6fOo8KBadSEYywPgATy+gKK7i0rHIpHWfGqxngpEIclBJ3BZ2sCU81mcrncPHMIAIf15ci4wgAjAB2JBYEAAXzwvEaygwACsuDI5AolMIIGBjFTqsBRHg8pVxKaTMY5RSKGAtIYJOJjIQkFYrMQoDwMIRsoTjHxphgoPANFZRP6GVbDA4HO6tABaJNaACC6QAKgBJADyADkoYmk7GeLIeIRqunyG02ggABLtToN6q6LQACnLtPgpruIZKAEotLpzFpgP0ENVWh0uhJB1oaBgFx2FGIG9PxEx+pPG90aD3KkxZwBCLdr3dY-f9UiouKkLzALQLn3iTumk9NuUOD88Byl8taGFwrO7bPgoprCgoUADkOc79MAj5Ll2WjgbsCr9DQuIBmioiDsO96XPhBGEfGKhJgmRwolhraOuIzquu66pyPigbwKIlAhqQGDiP6NzkCGGCyGAVhxM4jJWPsADUSEgfAGDQIQNDIVATB9kcnFZDwrZXniopNNBWkGmWMkMRpfYqWc3hqYorZQLS9TQRhtJPK2ADiPwAELuKaNnPqZWjEaR-RyhuPDBT+orVK54gebULbAS+OK2VBw6tnBi7SaahTuEgCXPvx5D6nwPCEhghSEHKZlxlYhYJloABqmYAKIAOoTNmACyAAKeYNbm6YFgF34luFWj0oyswtsYFAujhm5USAtiGKao7mVoxAEoQrojkc3ijUyPDZeIpBxF220tKuTbZZN5AuiuU5Nngp2KZdU2ED6sL-LsD0rahK1yGtNzZM912vTpcJfd4CowStohzWYgojpDChVK2V03Uipng4EMOGHcxhxH08PLfhXH0tlhjoi8pSLadFMrFAQM3W+3SY+Mf1TIDbYAPqmqGijiElW0reMvPyE+10dVNfBtLSfKtmZhFXuIN5eKjIPyFWNaHELWg-eM5WY8pxbxqRWgAEoAKq5tVxZWil-R3L02VE4ESKugABTQp2GAAMvAhUVFozmkHwogCNT2uGA1pAaHcWi1uQADusKwOH+GGJMoR83cTRuXwcRPKnlyGB1tKkDcED1L7pWBtkhfjOnWSwM4hJaEEEComXBeCkcLBHEzEjZZ72usHwTcndrh3HSzgQj2P0-eLPzjzxSo9Lz309PeUCSwKaRyZeEDogHXOhQJtNDiqaABMpoAMymigpo4CwflVSRRZnLrWgx-ACfZQhOEtDmksO4i0EamiHuMeC0kMCuwwEsYwrZWxIm7OefsADdpyDttrZBp1+7iD-tAvBZ5ey921lqDWCBB6VmrHWc6zMdCoNIfhTeCE3pwl2IOXQLY9wlGXqDf4g8AL-BQSQ6e5U+wb2gfvLQAAyGRfc5oLUJqtdam1DD732Ijc0cVlz7wxv0ZSmMeC8XgNld4xA4iCFFm0VEDUEBWKioSTMUA5rRhABIz8ZlBQgAEsYDgDJlCFD4IUWE3jwJ8jFCALASA6DykVCAJEKpiAbW8aWbU4hlAAAE9QGlINUG8sBWwAHInQujdB6L0apCAhhSBoDiFRxBWB4MYQSCdOwcWSYQTJl8rDkHxqybo-ENpFL7AAbmLEgCgPxBbeCTK8BMCdoD5GypfOgdBjAlHGTwL8DhgF3hGuQQgvQ+TZSvASNwGh4CjJ2d6DBd5+jzKOQALzuG0bKxRSDsQTK8LZ3hFlQGWV-PgpBWxzNKAspZogxn9ADDAV52VxTrLKIijZWgUVlBQEi35ByjluDkKc2EMtLnYo+exBFqKADEMBsRMhSFAElVIvnB3UMJbKOANmjO8P0JYpA2h3G+T8cQ+UEVYv6BYsapBLrkDuAoUgWybkYDubdbcM5nZBOmG0CgcQsQJlkLAKk2UKWsCgFgeVDhFUMj2mwj62I1WMoZBCgFohso3w5Q8+1pBdWUANVoClOAcDEGxbC9Q9wExCuMNlAAHG6s4wbXkCposKrQ0bNmfmLBasaXhcb4xoCTeAuhaavAPM7A0uKTl1FKpQfGVyxU3iZJKnE8AR4JHENi8NIqY3eAQKwfBWhJQxq-Bmq1ikGF43ELmyMBbnjZCLTMrQ3be3stTWcdtyaB3pruSNOdPK+X7S0HQbFO7+ULpWeu25lq5DWp2NiYw27gW7oTCe-d8qHSDRKuSEthzjn4orbS6t2Kn3EFHsQVsGhgWgoFSUR1+QBySUvleMA0KV3XWymgUVZw9U+r9QG7FlJ5AJnLISShOhnxTFw1qAjEAnmmK0PB0IbbzQJj3PIbKCZxQIbNd6feSAQmUivCONJfNspFMMEU655ruN8B7QyATWohNaBEyAMTX4wnvRFGWZQdAYkJhwNE2JQU5RAA\n\n[11-effect]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBqlQRdLgBleDbNz3ObApqseDiJ6fOo8KBadSEYywPgATy+gKK7i0rHIpHWfGqxngpEIclBJ3BZ2sCU81mcrncPHMIAIf15ci4wgAjAB2JBYEAAXzwvEaygwACsuDI5AolMIIGBjFTqsBRHg8pVxKaTMY5RSKGAtIYJOJjIQkFYrMQoDwMIRsoTjHxphgoPANFZRP6GVbDA4HLIeIRqii0aIAFJMry6LQAClxAZTpvIxjcooAlFpdOYtMB+smntmiyWExg4qRYKX+hhATxs6RPgaE01K1o+3jRfA1Rns6WO2cu1ke1BafVh3nafXG3zCBhA03TUvxHwZw45bGeO6tABaa9aACC6QAKgBJADyADkoVfr2f44mtA-yDaNoEAACXaTpwOqLNs0TWl4FNO4QxKcthxrM4EGqVoOi6CQKy0GgMEI2CFDEcCcPEJh+iwiDuhoRDKiYPCAEJqPIuisQY-o+3EVsvGALRCJ9Q8FFNVjINPHgJLjUVqhhOE8Jg4T4K0YUFCgFCqxofpgEE4jlNU3YFX6GgHTObw6zTDM8CONDLi0VtYCQB0QCdF03SsdU5HxQN4FESgQ1ILt-RucgQwwWQwCsOJnEZKx9gAahUpSMGgQgaAMqAWCObxdz5JyAHEfgAIXcayzK0CTvEonhqukhNqkK8QStqaC9P3ZcNJzHSiKU01CncJyDz4cLyH1PgeEJDBCkIOVZwcC9r0vLQADUnwAUQAdQmF8AFkAAV3zWt8H0-RafxkrR6UZWYs2MCgXQrWJRGzQxbEMU1bMCYgCUIV1q2yy6GQzJzxFIOJ4IBsTuicu6i23KGJDKuyMph+7twypHAiM8q5G+m5slRuGMHHOFMYVfCjmewwzEFatyYUKps1hl0MCRGdMe8KmQDuYw4j6WnPvGcRIycwx0ReUp3oB8WVigQmWYRi0AdxqYCZzAB9U1Q0UcROsFy5tfkISiz2+6+DaWk+WnAHvG43jLrR4n5EA4DDnK7xsfGWbMaYObzysL8loAJQAVTfQOzytbNPruXonP1pFXQAAq093nIAGXgcaKi0fLSD4UQBCltPDDW0gNDuLQQPIAB3WFYGLuzDEmUIdbuJoir4OInkby5DD22lSBuCB6kz6bA2yXvxmbrJYGcQktCCCBUSHnvBSOLLysVpzU7s1g+DniG09B8GOcCffD7P8yD+cK+KRvo-xk38YUfKBJYFNI5+vCZyp50KA-o0HFKaAATKaAAzKaFApocAsC0BeFQZ0ziey0BXeANcnJ6Uei0F64A+B3HenTU0u9Ai6WSonDASxjDZmzEiBCHFkLYKulOfW3g6GQzIpBTByVFbsSQs-S4WoXYIB3gBICoFOHdHofwu+r89I+lhP8XYFZdBZnoiUO+JN-g7zkv8aRDEz6zVLGfeR38tAADJzGU1wW9AWWhvp8F+qLEA399j03NIpOCU13Ds36L7TGPBQrwEGuQYgcRBBGzaKiNaCAIlNUJE+KAuDowgGMSeWcgoQARWMBwBkyhCh8EKLCTJqktzKHFEgOg8pFQgCRCqYgv1Mnxm1OIZQAABPUBpSDVActmAA5K5V07pPTenVCGFIGhAoVHEFYHgxhIo1zgoFBphA2kgKsOQPmrJujhV+n00sABuM8SAKA-H+mca8rxLw12gPkJyIC6B0GMCUI5kkzxLErvxA0hBeh5RHLCS2Gh4AHKkt6ZhsxPpXJ+QALzuG0JyxRSABUvK8V53gblQDuagvgpBsyXNKNc25ohDn9ADDAOFTlxRPLKFS55WhaVlBQNStFl1yA-KbE5PsBI3BApZYigKlK6UAGIYDYiZCkKAfKqTIvzuoaKTkcDPIOd4foSxSBtDuCin44hRqUuZf0MJ11SAw3IHcBQpBXmgowOC70itzneAKdMNoFA4hYkvLIWAVInJCtYFALAlqHDWqBnIBRcJlGQulQyQlmLRBOXAUq-o-Ko0eq9VoIVOAcDEBZWS9Q9xLw6uME5AAHAms4Oa4VavEDqsAxbS1WptToOZfMaDC3pLoGWrxGKfW+b8uQTlCnir5sCg1rYmTGpxPAfeCRxAsoLXq0t3gECsHEE5SUdbA02tDUo7EPNm2tvgO2542RO32q0EuldWhFUvP6HOrQJbr1vJ4Bu4NXhjCnrVRqngTk6Aso-Zq899z11gpfVunY2I32fT-TwS8AGtA-pPKZQNZju1st7V+uo01KBDpZbB4gB9iDZg0DivFWqSjRvyOWRKIC+xgBJWcW9aB9VnBTeO9NmaWWUnkJeRMhIRE6EPFMDjWpuMQGhcErQ1HQizvNJeei8gnKXnFDRgN3pv5ICKZSPs1Zmk6ycn0wwfSQVIYGnwZdDJtNal01ofTIBDMSRKYokUCZlB0EqZeHAWBKnyiYHKIAA\n\n[12-effect-creator]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBqlQRdLgBleDbNz3ObApqseDiJ6fOo8KBadSEYywPgATy+gKK7i0rHIpHWfGqxngpEIclBJ3BZ2sCU81mcrncPHMIAIf15ci4wgAjAB2JBYEAAXzwvEaygwACsuDI5AolMIIGBjFTqsBRHg8pVxKaTMY5RSKGAtIYJOJjIQkFYrMQoDwMIRsoTjHxphgoPANFZRP6GVbDA4HO6tABaJNaABiAFEACrpAASWgAUlCAPIAOS0aZT6fSGcTSdjPFkPEI1RRaNEeaZXl0WgAFLiA63TeRjG5RQBKLS6cxaYD9FtPbtDkeNjBxUiwUf9DCAnjd0ifA2NpqTrR7vGi+Bqjvd0cbs5brI7qC0+rHvu0+eLvmEDCBpemp-iHwN4OHKdYNk2WjqnIKaoui1Jdt2q6wJaIo8OOx40HObYdqawBIShS5ykwdbxkmCZaAAglWACSJZQjWCZgaK1QZuQbRtAg2btJ03HVAhTa0vApp3CGJToVOM5nAg1StB0XQSBOWg0BgKkCQoYjcfJ4jEWcsk8d0NAiZUTCKQAhHpWmGVixn9Hu4irl4wBaCpPqAQopoWbxoE8N5DjgdUMJwop3ZqUJWjCgoUDiUp-TAC5oWmhFuwKv0UE8DBrYMt2jriM6rruml+KBvAoiUCGpBbv6NzkCGGCyGAVhxM4jJWPsADU4VuRe0CEDQSVQCwWgAOI-AAQu4o54A4Ol+cxw1jeS-Fdf+z7Rd2cWqctZLhDiz51eQ+p8DwhIYIUhByrecZWAxWgAGrUWmADqEyFgAsgACiWabFhm9FkUxjZ0gyHaKcYFAuhOsSiNlIC2IYuFHMQBKEK605HN49KMnISB5KQcRCejLSabxONg0O36ed0U1nOM-Wk+D379dT4wpTTWhyEjNzZPT5MYOecLM1oCoxWz0OGGYgrTsLChVN2ZMuhgSI3oL3hiyAdzGHEfSS5Jlx5JGOOGOiLylPDhPGysUA8wrlMSCrgQc1M3M9gA+qaoaKOI0W63rWge-IrlDu94N8G0tJ8tehPeHZDlaPL35amxHGHGz3isyzk39Ewl08KRyYAEoAKqlv9PAOFa639HcvQ4z73hIq6AAFNCE4YAAy8BHRUw2kHwogCGbqcOiAaakBodxaNm5AAO6wrAg964YkyhJ7dxNKNfBxE8C+XIY720qQNwQPUHdnYG2Q7+MS9ZLAziEloQQQKih-b4KRwsEctviDjLdD6wfC3wJkPcQeMgF63-oA+23gIHOCgRSABsD372zpuUBIyEHRs0KO4Q2IBL46CgKjGg4pTQACZTQAGZTQoFNDgD+Zx05aHHvAaeONQqQxaDDJYdx4ZS1NL-cY8UuqK0aN+JYxhuzdiRMJayYl2GYyvHXQIUjCZf1YUIr+VlRJ0L1ondiCAf6sT0fALicleLSK0XAlBoUfSwn+LsCcuguxGRKHA-m-wf6BX+OY4y9sLqZzZtYrBtQABkwTP4wzhjrLQSM+AoxwUE-Y0tzQhSEUE5WWd-H1xqvAHG7xiBxEEAHNoqI0wIEKeIUahJqJQBhtGEA-iLoOEFCAeqxgOAMmUIUPghRYTNIil+ZQJCSFIBIfKRUIAkQqmICjZpDZtTiGUAAAT1AaUg1QkLdgAOROhdG6D0XpLwhhSBoCqFRxBWB4MYBq09BIVWmYQRZJCrDkC1qybodUUabNHAAbjrEgCgPw0ZnCTK8BM09oD5BxiQugdBjAlF+T5OsXDHJx3IIQXofIcZ7gJG4DQ8Bvm+W9PI2YPtQXooAF53DaDjYopByoJleAi7w4KoCQsYXwUg3YQWlDBRC0QPz+gBhgFSnG4pYVlDFXCrQkqygoHFUy1F6KlxYthOHPFCraXlVFVKgAxDAbETIUhQA1VSelvd1BNRxjgOF3zvD9CWKQNodwGU-HEAdUV8r+j5KxqQUm5A7gKFIAiwlGBiXei-kC7wXTphtAoHELECZZCwCpDjHVrAoBYGDQ4UNwM5A2LhPY0lpqGS8tZaIHG5CbX9E1SWpNKatA6pwDgYgCqhXqHuAmN1xgcYAA4q1nDbVSl1uV3VaD7fCkCdYc1Yy8BrLWNBxCRl0BbV4JkfYGiVZiuoZ1KBa3xV61cTJfU4ngP-BI4gFVdo9f27wCBWDfy0JKft3lp0dnzXY7Ec7xALqXSu0oa7+h3ofdaidZwr1jufVOsNcdI1aAdU6ngOM6AKvg86oDULINEtzd6fqMGfaoZ4AmdDWhkMgQwdmoJsGN0Yuxtuw1e6FXEeIAA4g3YNAcq5S6kopb8jjg6iQvcYABVgaHDjNAnqzh1uPY25tCrKTyATE2Qk+idCASmHJrUimIDkpyVoAToRL3mgTEZeQOMEzikE1m70QSkA9MpHuacczPY402YYTZBKKPYL4PehkjmtTOa0K5kA7nvJ9NsahMUIA6BIDoAmHAWAYvyiYHKIAA\n\n[13-init-effect]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBqlQRdLgBleDbNz3ObApqseDiJ6fOo8KBadSEYywPgATy+gKK7i0rHIpHWfGqxngpEIclBJ3BZ2sCU81mcrncPHMIAIf15ci4wgAjAB2JBYEAAXzwvEaygwACsuDI5AolMIIGBjFTqsBRHg8pVxKaTMY5RSKGAtIYJOJjIQkFYrMQoDwMIRsoTjHxphgoPANFZRP6GVbDA4HO6tABaJNaABiAFEACrpAASWgAUlCAPIAOS0aZT6fSGcTSdjPFkPEI1RRaNEeaZXl0WgAFLiA63TeRjG5RQBKLS6cxaYD9FtPbtDkeNjBxUiwUf9DCAnjd0ifA2NpqTrR7vGi+Bqjvd0cbs5brI7qC0+rHvu0+eLvmEDCBpemp-iHwN4OHKdYNk2WjqnIKaoui1Jdt2q6wJaIo8OOx40HObYdqawBIShS5ykwdbxkmCZaAAglWACSJZQjWCZgaK1QZuQbRtAg2btJ03HVAhTa0vApp3CGJToVOM5nAg1StB0XQSBOWg0BgKkCQoYjcfJ4jEWcsk8d0NAiZUTCKQAhHpWmGVixn9Hu4irl4wBaCpPqAQopoWbxoE8N5DjgdUMJwop3ZqUJWjCgoUDiUp-TAC5oWmhFuwKv0UE8DBrYMt2jriM6rruml+KBvAoiUCGpBbv6NzkCGGCyGAVhxM4jJWPsADU4VuRe0CEDQSVQCwWgAOI-AAQu4o54A4Ol+cxw1jeS-Fdf+z7Rd2cWqctZLhDiz51eQ+p8DwhIYIUhByres2NtUI3iMWjRfEtgkrYBa2Sd48XLf0SKurtgE+lM8DdgwWg4KOGBLMY3ZlMeJQYEik39D1SB-XwAM3EDINgxDJjQxOU5w9AiO6ZpvEo5hfCwM4pqsJT1MUnTYW01TTOMywIGXTwpHJgAatRaYAOoTIWACyAAKJZpsWGb0WRTHXVo9KMrMXbGBQLr4-0ojZSAtiGLhRzEAShC-e9lxKx2KPiKQcRCUc3ied0KNq0O36OxIU1nOM-XO+r379Z74wpV7WhyEbNzZL7rsYOecKB1oCoxSH2uGGYgrTonChVN2LsuvDjQ3vHDs63cxhxH06dm+M4iRijhjoi8pT6-bWgNysUBR3n7sWi3YdTJHPYAPqmqGijiNFVeXKP8iuUOYvq3wbS0ny14t94dkOYrfsx-IbEcYcIfeMHQfE94TCc9z5EAEoAKqlnLPAOFa61IzwvTk0cwA-eTg3dz-iWwn+LsFGPAEjIW2nXEA+sdBQF+jQJgx9AhpQynBHWToXRuisIVAkxASplQZJVYw1Var1Uas1Qg0Dbr3UEIQW8Z944aAgPAAA7ijUK+MWg6yWHcaBwBE40COJ9QS+caE4yht2JEwlrJiQ4RbOQL9D4HCLoEP+nVhHdysqJdmiitR7wQOTVi7FOKk26FIrRyjvA+zUepfqE5dBdiMiUCxodDxwnJoFf4ZjjLKIuqfQIoVTrkgAGRBKOCnXWmheGt2Nr9QwhR3D7EzuaEKXVAnkELv0c+8ceA1XgCjd4xA4iCBnm0VEaYEDFPEKNQk1EoA62jCAYmF0HCChAPVIhCBSDKEKHwQosJWkRS-MoNAdAkBoHlIqEASIVTEBNq0hs2pxDKAAAJ6gNKQaoSFuwAHJ0H5Q9F6S8IYUgaAqhUcQVgeDGAaswwSFVZmEGWQAJisOQcurJuh1RNts0cABuOsSAKA-GnP0JMrwEzMOgPkFGTy6B0GMCUf5Pk6zcMcorcghBeh8hRnuAkbgNDwF+b5b0cjHL9HBZigAXncNoKNiikHKgmV4SLvCQqgNCrQGg+CkG7GC0oEKoWiD+f0AMMAaUo3FPCsokqEVaBlWUFAUqWXosxUuHFsJl4EuVfS8qErZUAGIYDYiZCkKA2qqSMtIHwdQTUUY4ARb87w-QlikDaHcJlPxxAHQlUq-ohTlakGduQO4ChSBIuJRgUlGk5K8RBWcHp0w2gUDiFiBMshYBUhRvq1gUAsDhocJGhkHYfSAJ2NiM2OqGQCvZaIFGABmB15KLVVvTZmrQ+qcA4GIMq0V6h7gJi9cYFGAAORtZxe00o9blb1WhR2IpAnWQtysvCl3LjQGu9JdBt1eCZM2BpVXYrqGdSg5dCV+tXEyQNOJ4C0wSOIZVg6fVju8AgVg4gUaSjHd5JdxbbGrvEOuyMW7njZB3XGl9N732g2fTUIds6v2LtJYrcDWgXVup4CjOgyq0PutfVBp5CGSVFrkCWuEuxkNmxwzwBMeHMPhodI-b08Tah7oxViuQKNekmtPcq2jrdKbEG7FynlfKSjVvyOODqTy9xgGFWcR9WgRkwdbVejtXblWUnkAmJshJ9E6EAlMDTWptMQEpXkrQ0nQgPvNAmIy8gUYJnFDJ-NTH3BID6ZSPc04FljxRtsww2yiUFuY0gPgb6GTea1L5rQ-mQCBe8gM0tS4xQgFGXQBMOAsBIDoPKBBQA\n\n[14-subscriptions]: https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwFYA0IAzgMYBOA9rLMgNoAMedAugQGYQKG2gB2AhmERIQGABYAXMNQLFyPcfHnIQAHigQAbgAJoAXgA6IPgAdjhgHwqA9Oo3n9PFYXjFxEOfZ5atK0Sk-e3gAi8GDkSA7e1n4BPgCusLFRsBBJgQDCoi4A1lriWVoARuQAHlo88CXieeRafOUC8DVaohAA5qIpHdUQ4pGB1ilpKkP9gVrpKcS5cnUNgs1gfNlNvXkFhs4IrvBQhvPwYz5Wo14Dp+PekxDTEDxtc8RZ08VlUOTwhOXk1Vsu1fkmvxBEdBqlQRdLgBleDbNz3ObApqseDiJ6fOo8KBadSEYywPgATy+gKK7i0rHIpHWfGqxngpEIclBJ3BZ2SbMuWgAqsYbOQAO5ePikCgCrQrYlaMIaJp-VzuHgsyHWBKeazOBUeEAEeVuORcYQARiwSAAzFgQABfPC8RrKDAAKy4MjkCiUwggYGMVOqwFEeDylXEgZMxitFIoYC0hgk4mMhCQVisxCgPAwhGyhOMfGmGCg8A0VlE2YZYcMDgcya0AFo61oANIAUQAmkEAPIAdQAcloodyAEJQ9IAJQAkgAFAAqY-bvbrNcrPFkPEI1Ul7yFULihRIpAghQZWl0WgAFLic2iA1pyMZ9auAJTH8xaYD9Fdrlp8LEIaknwvPq+RwQKwZ6FhgkpaAAhLoJ63vehAQfAhJPqQqJxKQSrsjiEB4rSTynvBiqIbm94Pv0Vr9HwMBNrK8gADK4e6DKnoYG6CkqOpfj+DLkWcaHiBhXink+ugvmhMrwLRijiIxa6KCxbHIZunGBqI35wLxDiUVhH7VHIDbIUEHHHmekqhlqPCiS+NDsVuO57geDKBsA5l1JZVpMEu1YLloABiTZTukAASWgAFJQnOWhNn5AXpFOtZ1kuekUqiTxhUyXgnueuGXk8gZEQa1lAWcKJXoRd7ERgGGwHx3gYICPCnmheIGk0YlaC1PqrvATqZSJdVaA1WRNVAtL1B1F74aIFUIRgpGKoGY3iHwD58TpDgpc6ch+WlWR-meNUWWRgE0GV6WZS5R3ufenneVYiU1loACC8Wzt2UKPclBrVFO5BtG0CDBe0nQg9U2VrrS8CBncBYlMVb5nAg1StB0XQSKZNAYNjkMKGIIPo+IXlnKjoPdDQsOVEwplQaThMU1iVP9AJQmvkNOMrQoakE2DOkbcuP19rC-ymaeuPQ1oeq7MVND9MA2MZpzEtS1ANr9NtPC7VeikgHGCZJlYGv4rm8CiJQBakA12Y3OQBYYLIYBWHEziMlY+wANSS0rGDQIQNAqywWgAOI-AO7gPngDjE5tgsh+IYe1BDStLeNxWnvLHNQ4GhTuEgOLjfb5Det+hIYLuVp8THq7VHH3aNF8SdZ-nK1p4j9WZ1z-RIomzd8BmUzwKeDBaDgD4YEsxinmUHUlBgSIR-0vt58tfeEAPQ+BqP48mFPgGz9AC8kzz3R52dfCwM4gasOfl8UjfEvXxfD-3yw2mVwL1dC3CvKmeLgFtzoUCYtvYq2PLBcoCRaqdXQphL2UNmYwK8DQGEcJAziwzMLHY2InpGmJvzFKKD-jGSFL-JW-9F5APQaA2CJ4eCQNQoguBCgEGCVgcgzBIYmG9VAZ7XB2l7qPS0AANTHE2TsEx2wAFkJxzibN2Kcn0FzfU-vSRkswTzGAoAmZ8-QZqGFsIYFyRxiAEkID3AB4xVGZTzuIUgcRoZHG8HTMGedNG3kQs47okdsLeBVq4rRiEVbePGGrbCcgTE3GyP49xGA2qoIooGWW2E9EgDMFxYANogxVFPG4hMc9GhrWCYEFJdxjBxD6OkxxeRSx50MOiF4pRDFVPqSsKA0S8meIkEU8Y4SphRLPAAfUDIWGSCMqneBGfIRWt4JxaL4G0WkioRLjOgawrwuTEJun+oDQ4PitChJCYfbwTB34+XrCObk84kpYTDOnRePBeinyOMAbup9A6dPEG8tBHDdh5zoVQbOucYwgEMToKAPcaBMAOYEDWWt0SkFYrrcQ8ZEzJiNgSYgptzYMitsYG2dsHZOxdoQUFtd66DVfmcDQEB4ACjzn-DqKSlh3FBRkxJRwFboO7tvSep4kQw0ZvDQCVi5B3L2fyqpHz6Xew+QzOGlKuRbIBggU+f1lXwGBmjMGAr5XdMCH4rhGC4S7DASeSmJQ9XeDif8U+hDXA6qpnqiuRz9XexzrUAAZB6o4KSDHpK0CYvgZjakgHdfsTJChsnoPdYU-oJyik8FtvAZe5BiBxEEFMtoqImwIAzfHQkY4oCIvLCAF1hAHJkAgJVA00qoanSXOMKhPzsQwVoZArQXqjhNuNdiF8dAO3erCTwQyhJiFNUMM9UUgpeSgrteIXkh8u0gObdBcB-zYADqXVDI1-wTUqDPOg32GAED3HyLWLQRonydqHSOsdiLJ1ijHbOjhY6XWUorg4HUIAHZ4t-MoQofBDzSCIBw4iygsAAA4kBGiNNaW0IAkQOmIGYr9K53TiGUAAAS9D6Ug1QaqngAOR61RSmNMfUCwpA0JbCo4grA8GMI7AUUNLbIcIJhgATFYcg5TWTdHtmYwjD4ADcS4kAUB+CVbwdZXg1gFNAfIecON0DoMYEoomeD82ZV4YAWgfSEF6IqPOaECRuFlMJ-mGARU6f6LJgzAAvO4bQ87FFIBbGsrwNPeHk1ARTWgNAilPDJ0ocmFOiBE-0HMMAnN5yNKpsocW1MXvi1oFA8WvN6fIAZ+8xnYSLPM7ZqkFtYtJYAMQwGxEyFIUAMuufc6QaiEBnZ5xwGp4T3h+hLFIG0O4HmfjiCLrF9L74MJMlIK48gdwFCkA05Z6z+MtXdCk0UXM2Q2gUDiFiGsshYBUjzqV1gUAsCzYcFZhkmUd1YOW3VhkoXfOiDzmaNrhW3O3Z23trQpWcA4GIBlqL6h7g1gG8YPOEHntnH+05vryLBtaDB+p-hWEztqK8KU8pNBxCll0C0141MAH6cM3IPOgGqvlPgBltNajxs4ngNfBI4gMvA6G+D7wCBWCfK0AAdnBzpZHF3QFo-EBjrHOPSh4-6GzjnrWEdnCZ3DnnS4+ezGMMtrrPWeB5zoBltXvXJdKYV+meboCVcAJ1zwGseutBa+0jGJH7rlsE5y3UXclAycZct8Qc+xBTwBYRcFkod38hPk9hxiSEXZe3jzmgYbZx3vU6+z9jLlJ5A1jXISFVOgVpTCT26VPEB7PJq0KH0IjPgw1kpvIPONYjQSRO+md1SBDyUjQq+NDMk86EcMIRizp2G98HZ0eYAbfK9aE7yAbvOkv16jA8IOgSA6A1hwKaOg1ooVAA\n"
  },
  {
    "path": "index.d.ts",
    "content": "// Minimum TypeScript Version: 4.2\n\n// This requires every property of an object or none at all.\ntype AllOrNothing<T> = T | { [K in keyof T]?: never }\n\n// This ensures at least one property in an object is present.\ntype AtLeastOne<T> = { [K in keyof T]: Pick<T, K> }[keyof T]\n// Credit: https://stackoverflow.com/a/59987826/1935675\n\n// This ensures at least one object property group is present.\ntype AtLeastSomething<T, U> = U | AtLeastOne<T> & AllOrNothing<U>\n\n// Most event typings are provided by TypeScript itself.\ntype EventsMap =\n  & { [K in keyof HTMLElementEventMap as `on${K}`]: HTMLElementEventMap[K] }\n  & { [K in keyof WindowEventMap as `on${K}`]: WindowEventMap[K] }\n  & { onsearch: Event }\n\n// Indexable values are able to use subscripting.\ntype Indexable = string | unknown[] | Record<string, any>\n\n// This validates plain objects while invalidating array objects and string\n// objects by disallowing numerical indexing.\ntype IndexableByKey = Record<number, never>\n\n// Empty strings can cause issues in certain places.\ntype NonEmptyString<T> = T extends \"\" ? never : T\n\n// -----------------------------------------------------------------------------\n\ndeclare module \"hyperapp\" {\n  // `app()` initiates a Hyperapp instance. Only `app()`'s `node:` property and\n  // effecters and subscribers are allowed to have side effects.\n  function app<S>(props: App<S>): Dispatch<S>\n\n  // `h()` builds a virtual DOM node.\n  function h<S, C = unknown, T extends string = string>(\n    tag: NonEmptyString<T>,\n    props: CustomPayloads<S, C> & Props<S>,\n    children?: MaybeVNode<S> | readonly MaybeVNode<S>[]\n  ): ElementVNode<S>\n\n  // `memo()` stores a view along with any given data for it.\n  function memo<S, D extends Indexable = Indexable>(\n    view: (data: D) => VNode<S>,\n    data: D\n  ): VNode<S>\n\n  // `text()` creates a virtual DOM node representing plain text.\n  function text<T = unknown>(\n    // Values, aside from symbols and functions, can be handled.\n    value: T extends symbol | ((..._: unknown[]) => unknown) ? never : T\n  ): TextVNode\n\n  // ---------------------------------------------------------------------------\n\n  // This lets you make a variant of `h()` which is aware of your Hyperapp\n  // instance's state. The `_ extends never` ensures that any state-aware\n  // `h()` doesn't have an explicit state type that contradicts the\n  // state type it actually uses.\n  interface TypedH<S> {\n    <_ extends never, C = unknown, T extends string = string>(\n      tag: NonEmptyString<T>,\n      props: CustomPayloads<S, C> & Props<S>,\n      children?: MaybeVNode<S> | readonly MaybeVNode<S>[]\n    ): ElementVNode<S>\n  }\n\n  // ---------------------------------------------------------------------------\n\n  // An action transforms existing state and/or wraps another action.\n  type Action<S, P = any> = (state: S, payload: P) => Dispatchable<S>\n\n  // A Hyperapp instance typically has an initial state and a top-level view\n  // mounted over an available DOM element.\n  type App<S> =\n    Readonly<AtLeastSomething<{\n      // State is established through either direct assignment or an action.\n      init: Dispatchable<S>\n\n      // The subscriptions function manages a set of subscriptions.\n      subscriptions: (state: S) =>\n        readonly (boolean | undefined | Subscription<S>)[]\n\n      // Dispatching can be augmented to do custom processing.\n      dispatch: (dispatch: Dispatch<S>) => Dispatch<S>\n    }, {\n      // The top-level view can build a virtual DOM node depending on the state.\n      view: (state: S) => VNode<S>\n\n      // The mount node is where a Hyperapp instance will get placed.\n      node: Node\n    }>>\n\n  // The `class` property represents an HTML class attribute string.\n  type ClassProp =\n    | boolean\n    | string\n    | undefined\n    | Record<string, boolean | undefined>\n    | ClassProp[]\n\n  // This lets event-handling actions properly accept custom payloads.\n  type CustomPayloads<S, T> = {\n    [K in keyof T]?:\n      K extends \"style\"\n      ? StyleProp\n      : T[K] extends [action: Action<S, infer P>, payload: unknown]\n      ? readonly [action: Action<S, P>, payload: P]\n      : T[K]\n  }\n\n  // Dispatching will cause state transitions.\n  type Dispatch<S> = (dispatchable: Dispatchable<S>, payload?: unknown) => void\n\n  // A dispatchable entity is used to cause a state transition.\n  type Dispatchable<S, P = any> =\n    | S\n    | [state: S, ...effects: MaybeEffect<S, P>[]]\n    | Action<S, P>\n    | readonly [action: Action<S, P>, payload: P]\n\n  // An effecter is the function that runs an effect.\n  type Effecter<S, P = any> = (\n    dispatch: Dispatch<S>,\n    payload: P\n  ) => void | Promise<void>\n\n  // An effect is where side effects and any additional dispatching may occur.\n  type Effect<S, P = any> =\n    | Effecter<S, P>\n    | readonly [effecter: Effecter<S, P>, payload: P]\n\n  \n  // Effects can be declared conditionally.\n  type MaybeEffect<S, P> = null | undefined | boolean | \"\" | 0 | Effect<S, P>\n\n\n  // Event handlers are implemented using actions.\n  type EventActions<S> = {\n    [K in keyof EventsMap]:\n      | Action<S, EventsMap[K]>\n      | readonly [action: Action<S>, payload: unknown]\n  }\n\n  // In certain places a virtual DOM node can be made optional.\n  type MaybeVNode<S> = boolean | null | undefined | VNode<S>\n\n  // Virtual DOM properties will often correspond to HTML attributes.\n  type Props<S> =\n    Readonly<\n      Partial<\n        Omit<HTMLElement, keyof (\n          DocumentAndElementEventHandlers &\n          ElementCSSInlineStyle &\n          GlobalEventHandlers\n        )> &\n        ElementCreationOptions &\n        EventActions<S>\n      > &\n      {\n        [_: string]: unknown\n        class?: ClassProp\n        key?: VNode<S>[\"key\"]\n        style?: StyleProp\n\n        // By disallowing `_VNode` we ensure values having the `VNode` type are\n        // not mistaken for also having the `Props` type.\n        _VNode?: never\n      }\n    >\n\n  // The `style` property represents inline CSS. This relies on TypeScript's CSS\n  // property definitions. Custom properties aren't covered as well as any newer\n  // properties yet to be recognized by TypeScript. The only way to accommodate\n  // them is to relax the adherence to TypeScript's CSS property definitions.\n  // It's a poor trade-off given the likelihood of using such properties.\n  // However, you can use type casting if you want to use them.\n  type StyleProp = IndexableByKey & {\n    [K in keyof CSSStyleDeclaration]?: CSSStyleDeclaration[K] | null\n  }\n\n  // A subscription reacts to external activity.\n  type Subscription<S, P = any> = readonly [\n    subscriber: (dispatch: Dispatch<S>, payload: P) => Unsubscribe,\n    payload: P\n  ]\n\n  // An unsubscribe function cleans up a canceled subscription.\n  type Unsubscribe = () => void\n\n  // A virtual DOM node (a.k.a. VNode) represents an actual DOM element.\n  type ElementVNode<S> = {\n    readonly props: Props<S>\n    readonly children: readonly MaybeVNode<S>[]\n    node: null | undefined | Node\n\n    // Hyperapp takes care of using native Web platform event handlers for us.\n    events?:\n      Record<\n        string,\n        Action<S> | readonly [action: Action<S>, payload: unknown]\n      >\n\n    // A key can uniquely associate a VNode with a certain DOM element.\n    readonly key: string | null | undefined\n\n    // A VNode's tag is either an element name or a memoized view function.\n    readonly tag: string | ((data: Indexable) => VNode<S>)\n\n    // If the VNode's tag is a function then this data will get passed to it.\n    memo?: Indexable\n\n    // VNode types are based on actual DOM node types:\n    // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\n    readonly type: 1\n\n    // `_VNode` is a phantom guard property which gives us a way to tell `VNode`\n    // objects apart from `Props` objects. Since we don't expect users to make\n    // their own VNodes manually, we can take advantage of this trick which\n    // is unique to TypeScript type definitions for JavaScript code.\n    _VNode: true\n  }\n\n  // Certain VNodes specifically represent Text nodes and don't rely on state.\n  type TextVNode = {\n    readonly props: {}\n    readonly children: []\n    node: null | undefined | Node\n    readonly key: undefined\n    readonly tag: string\n    readonly type: 3\n    _VNode: true\n  }\n  \n  // VNodes may represent either Text or Element nodes.\n  type VNode<S> = ElementVNode<S> | TextVNode\n}\n"
  },
  {
    "path": "index.js",
    "content": "var SSR_NODE = 1\nvar TEXT_NODE = 3\nvar EMPTY_OBJ = {}\nvar EMPTY_ARR = []\nvar SVG_NS = \"http://www.w3.org/2000/svg\"\n\nvar id = (a) => a\nvar map = EMPTY_ARR.map\nvar isArray = Array.isArray\n\nvar createClass = (obj) => {\n  var out = \"\"\n\n  if (typeof obj === \"string\") return obj\n\n  if (isArray(obj)) {\n    for (var k = 0, tmp; k < obj.length; k++) {\n      if ((tmp = createClass(obj[k]))) {\n        out += (out && \" \") + tmp\n      }\n    }\n  } else {\n    for (var k in obj) {\n      if (obj[k]) out += (out && \" \") + k\n    }\n  }\n\n  return out\n}\n\nvar shouldRestart = (a, b) => {\n  for (var k in { ...a, ...b }) {\n    if (typeof (isArray(a[k]) ? a[k][0] : a[k]) === \"function\") {\n      b[k] = a[k]\n    } else if (a[k] !== b[k]) return true\n  }\n}\n\nvar patchSubs = (oldSubs, newSubs = EMPTY_ARR, dispatch) => {\n  for (\n    var subs = [], i = 0, oldSub, newSub;\n    i < oldSubs.length || i < newSubs.length;\n    i++\n  ) {\n    oldSub = oldSubs[i]\n    newSub = newSubs[i]\n\n    subs.push(\n      newSub && newSub !== true\n        ? !oldSub ||\n          newSub[0] !== oldSub[0] ||\n          shouldRestart(newSub[1], oldSub[1])\n          ? [\n              newSub[0],\n              newSub[1],\n              (oldSub && oldSub[2](), newSub[0](dispatch, newSub[1])),\n            ]\n          : oldSub\n        : oldSub && oldSub[2]()\n    )\n  }\n  return subs\n}\n\nvar getKey = (vdom) => (vdom == null ? vdom : vdom.key)\n\nvar patchProperty = (node, key, oldValue, newValue, listener, isSvg) => {\n  if (key === \"style\") {\n    for (var k in { ...oldValue, ...newValue }) {\n      oldValue = newValue == null || newValue[k] == null ? \"\" : newValue[k]\n      if (k[0] === \"-\") {\n        node[key].setProperty(k, oldValue)\n      } else {\n        node[key][k] = oldValue\n      }\n    }\n  } else if (key[0] === \"o\" && key[1] === \"n\") {\n    if (\n      !((node.events || (node.events = {}))[(key = key.slice(2))] = newValue)\n    ) {\n      node.removeEventListener(key, listener)\n    } else if (!oldValue) {\n      node.addEventListener(key, listener)\n    }\n  } else if (!isSvg && key !== \"list\" && key !== \"form\" && key in node) {\n    node[key] = newValue == null ? \"\" : newValue\n  } else if (newValue == null || newValue === false) {\n    node.removeAttribute(key)\n  } else {\n    node.setAttribute(key, newValue)\n  }\n}\n\nvar createNode = (vdom, listener, isSvg) => {\n  var props = vdom.props\n  var node =\n    vdom.type === TEXT_NODE\n      ? document.createTextNode(vdom.tag)\n      : (isSvg = isSvg || vdom.tag === \"svg\")\n      ? document.createElementNS(SVG_NS, vdom.tag, props.is && props)\n      : document.createElement(vdom.tag, props.is && props)\n\n  for (var k in props) {\n    patchProperty(node, k, null, props[k], listener, isSvg)\n  }\n\n  for (var i = 0; i < vdom.children.length; i++) {\n    node.appendChild(\n      createNode(\n        (vdom.children[i] = maybeVNode(vdom.children[i])),\n        listener,\n        isSvg\n      )\n    )\n  }\n\n  return (vdom.node = node)\n}\n\nvar patch = (parent, node, oldVNode, newVNode, listener, isSvg) => {\n  if (oldVNode === newVNode) {\n  } else if (\n    oldVNode != null &&\n    oldVNode.type === TEXT_NODE &&\n    newVNode.type === TEXT_NODE\n  ) {\n    if (oldVNode.tag !== newVNode.tag) node.nodeValue = newVNode.tag\n  } else if (oldVNode == null || oldVNode.tag !== newVNode.tag) {\n    node = parent.insertBefore(\n      createNode((newVNode = maybeVNode(newVNode)), listener, isSvg),\n      node\n    )\n    if (oldVNode != null) {\n      parent.removeChild(oldVNode.node)\n    }\n  } else {\n    var tmpVKid\n    var oldVKid\n\n    var oldKey\n    var newKey\n\n    var oldProps = oldVNode.props\n    var newProps = newVNode.props\n\n    var oldVKids = oldVNode.children\n    var newVKids = newVNode.children\n\n    var oldHead = 0\n    var newHead = 0\n    var oldTail = oldVKids.length - 1\n    var newTail = newVKids.length - 1\n\n    isSvg = isSvg || newVNode.tag === \"svg\"\n\n    for (var i in { ...oldProps, ...newProps }) {\n      if (\n        (i === \"value\" || i === \"selected\" || i === \"checked\"\n          ? node[i]\n          : oldProps[i]) !== newProps[i]\n      ) {\n        patchProperty(node, i, oldProps[i], newProps[i], listener, isSvg)\n      }\n    }\n\n    while (newHead <= newTail && oldHead <= oldTail) {\n      if (\n        (oldKey = getKey(oldVKids[oldHead])) == null ||\n        oldKey !== getKey(newVKids[newHead])\n      ) {\n        break\n      }\n\n      patch(\n        node,\n        oldVKids[oldHead].node,\n        oldVKids[oldHead],\n        (newVKids[newHead] = maybeVNode(\n          newVKids[newHead++],\n          oldVKids[oldHead++]\n        )),\n        listener,\n        isSvg\n      )\n    }\n\n    while (newHead <= newTail && oldHead <= oldTail) {\n      if (\n        (oldKey = getKey(oldVKids[oldTail])) == null ||\n        oldKey !== getKey(newVKids[newTail])\n      ) {\n        break\n      }\n\n      patch(\n        node,\n        oldVKids[oldTail].node,\n        oldVKids[oldTail],\n        (newVKids[newTail] = maybeVNode(\n          newVKids[newTail--],\n          oldVKids[oldTail--]\n        )),\n        listener,\n        isSvg\n      )\n    }\n\n    if (oldHead > oldTail) {\n      while (newHead <= newTail) {\n        node.insertBefore(\n          createNode(\n            (newVKids[newHead] = maybeVNode(newVKids[newHead++])),\n            listener,\n            isSvg\n          ),\n          (oldVKid = oldVKids[oldHead]) && oldVKid.node\n        )\n      }\n    } else if (newHead > newTail) {\n      while (oldHead <= oldTail) {\n        node.removeChild(oldVKids[oldHead++].node)\n      }\n    } else {\n      for (var keyed = {}, newKeyed = {}, i = oldHead; i <= oldTail; i++) {\n        if ((oldKey = oldVKids[i].key) != null) {\n          keyed[oldKey] = oldVKids[i]\n        }\n      }\n\n      while (newHead <= newTail) {\n        oldKey = getKey((oldVKid = oldVKids[oldHead]))\n        newKey = getKey(\n          (newVKids[newHead] = maybeVNode(newVKids[newHead], oldVKid))\n        )\n\n        if (\n          newKeyed[oldKey] ||\n          (newKey != null && newKey === getKey(oldVKids[oldHead + 1]))\n        ) {\n          if (oldKey == null) {\n            node.removeChild(oldVKid.node)\n          }\n          oldHead++\n          continue\n        }\n\n        if (newKey == null || oldVNode.type === SSR_NODE) {\n          if (oldKey == null) {\n            patch(\n              node,\n              oldVKid && oldVKid.node,\n              oldVKid,\n              newVKids[newHead],\n              listener,\n              isSvg\n            )\n            newHead++\n          }\n          oldHead++\n        } else {\n          if (oldKey === newKey) {\n            patch(\n              node,\n              oldVKid.node,\n              oldVKid,\n              newVKids[newHead],\n              listener,\n              isSvg\n            )\n            newKeyed[newKey] = true\n            oldHead++\n          } else {\n            if ((tmpVKid = keyed[newKey]) != null) {\n              patch(\n                node,\n                node.insertBefore(tmpVKid.node, oldVKid && oldVKid.node),\n                tmpVKid,\n                newVKids[newHead],\n                listener,\n                isSvg\n              )\n              newKeyed[newKey] = true\n            } else {\n              patch(\n                node,\n                oldVKid && oldVKid.node,\n                null,\n                newVKids[newHead],\n                listener,\n                isSvg\n              )\n            }\n          }\n          newHead++\n        }\n      }\n\n      while (oldHead <= oldTail) {\n        if (getKey((oldVKid = oldVKids[oldHead++])) == null) {\n          node.removeChild(oldVKid.node)\n        }\n      }\n\n      for (var i in keyed) {\n        if (newKeyed[i] == null) {\n          node.removeChild(keyed[i].node)\n        }\n      }\n    }\n  }\n\n  return (newVNode.node = node)\n}\n\nvar propsChanged = (a, b) => {\n  for (var k in a) if (a[k] !== b[k]) return true\n  for (var k in b) if (a[k] !== b[k]) return true\n}\n\nvar maybeVNode = (newVNode, oldVNode) =>\n  newVNode !== true && newVNode !== false && newVNode\n    ? typeof newVNode.tag === \"function\"\n      ? ((!oldVNode ||\n          oldVNode.memo == null ||\n          propsChanged(oldVNode.memo, newVNode.memo)) &&\n          ((oldVNode = newVNode.tag(newVNode.memo)).memo = newVNode.memo),\n        oldVNode)\n      : newVNode\n    : text(\"\")\n\nvar recycleNode = (node) =>\n  node.nodeType === TEXT_NODE\n    ? text(node.nodeValue, node)\n    : createVNode(\n        node.nodeName.toLowerCase(),\n        EMPTY_OBJ,\n        map.call(node.childNodes, recycleNode),\n        SSR_NODE,\n        node\n      )\n\nvar createVNode = (tag, { key, ...props }, children, type, node) => ({\n  tag,\n  props,\n  key,\n  children,\n  type,\n  node,\n})\n\nexport var memo = (tag, memo) => ({ tag, memo })\n\nexport var text = (value, node) =>\n  createVNode(value, EMPTY_OBJ, EMPTY_ARR, TEXT_NODE, node)\n\nexport var h = (tag, { class: c, ...props }, children = EMPTY_ARR) =>\n  createVNode(\n    tag,\n    { ...props, ...(c ? { class: createClass(c) } : EMPTY_OBJ) },\n    isArray(children) ? children : [children]\n  )\n\nexport var app = ({\n  node,\n  view,\n  subscriptions,\n  dispatch = id,\n  init = EMPTY_OBJ,\n}) => {\n  var vdom = node && recycleNode(node)\n  var subs = []\n  var state\n  var busy\n\n  var update = (newState) => {\n    if (state !== newState) {\n      if ((state = newState) == null) dispatch = subscriptions = render = id\n      if (subscriptions) subs = patchSubs(subs, subscriptions(state), dispatch)\n      if (view && !busy) requestAnimationFrame(render, (busy = true))\n    }\n  }\n\n  var render = () =>\n    (node = patch(\n      node.parentNode,\n      node,\n      vdom,\n      (vdom = view(state)),\n      listener,\n      (busy = false)\n    ))\n\n  var listener = function (event) {\n    dispatch(this.events[event.type], event)\n  }\n\n  return (\n    (dispatch = dispatch((action, props) =>\n      typeof action === \"function\"\n        ? dispatch(action(state, props))\n        : isArray(action)\n        ? typeof action[0] === \"function\"\n          ? dispatch(action[0], action[1])\n          : action\n              .slice(1)\n              .map(\n                (fx) => fx && fx !== true && (fx[0] || fx)(dispatch, fx[1]),\n                update(action[0])\n              )\n        : update(action)\n    ))(init),\n    dispatch\n  )\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"hyperapp\",\n  \"version\": \"2.0.22\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"description\": \"The tiny framework for building hypertext applications.\",\n  \"repository\": \"jorgebucaran/hyperapp\",\n  \"author\": \"Jorge Bucaran\",\n  \"license\": \"MIT\",\n  \"files\": [\n    \"*.[tj]s\"\n  ],\n  \"keywords\": [\n    \"framework\",\n    \"hyperapp\",\n    \"frontend\",\n    \"vdom\",\n    \"web\",\n    \"app\",\n    \"ui\"\n  ],\n  \"scripts\": {\n    \"test\": \"c8 twist tests/*.js\",\n    \"info\": \"node --print \\\"('$pkg' ? '@$npm_package_name/$pkg@' : '') + require('./${pkg:+packages/$pkg/}package').version\\\"\",\n    \"deploy\": \"npm test && git commit --all --message $tag && git tag --sign $tag --message $tag && git push && git push --tags\",\n    \"release\": \"tag=$(npm run --silent info) npm run deploy && cd ./${pkg:+packages/$pkg} && npm publish --access public\"\n  },\n  \"devDependencies\": {\n    \"twist\": \"*\",\n    \"c8\": \"*\"\n  }\n}\n"
  },
  {
    "path": "packages/dom/README.md",
    "content": "# @hyperapp/dom\n\n> Inspect the DOM, focus and blur.\n\n## Installation\n\n```console\nnpm install @hyperapp/dom\n```\n\n```js\nimport { focus, blur } from \"@hyperapp/dom\"\n```\n\nOr without a build step—import it right in your browser.\n\n```html\n<script type=\"module\">\n  import { focus, blur } from \"https://unpkg.com/@hyperapp/dom\"\n</script>\n```\n\n## License\n\n[MIT](../../LICENSE.md)\n"
  },
  {
    "path": "packages/dom/index.js",
    "content": "const justFocus = (_, { id, ...props }) =>\n  requestAnimationFrame(() => document.getElementById(id).focus(props))\n\nconst justBlur = (_, id) => document.getElementById(id).blur()\n\nexport const focus = (id, { preventScroll } = {}) => [\n  justFocus,\n  { id, preventScroll },\n]\nexport const blur = (id) => [justBlur, id]\n"
  },
  {
    "path": "packages/dom/package.json",
    "content": "{\n  \"name\": \"@hyperapp/dom\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"description\": \"Inspect the DOM, focus and blur.\",\n  \"repository\": \"https://github.com/jorgebucaran/hyperapp/tree/main/packages/dom\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"hyperapp\",\n    \"focus\",\n    \"blur\",\n    \"dom\"\n  ]\n}\n"
  },
  {
    "path": "packages/events/README.md",
    "content": "# @hyperapp/events\n\n> Subscribe to mouse, keyboard, window, and frame events.\n\n## Installation\n\n```console\nnpm install @hyperapp/events\n```\n\n## License\n\n[MIT](../../LICENSE.md)\n"
  },
  {
    "path": "packages/events/index.js",
    "content": "const listeners = {}\n\nconst fx = (subscriber) => (action) => [subscriber, action]\n\nconst globalListener = (event) => {\n  for (const [dispatch, actions] of listeners[event.type])\n    for (const action of actions) dispatch(action, event)\n}\n\nconst on = (type) =>\n  fx((dispatch, action) => {\n    if (!listeners[type]) {\n      listeners[type] = new Map()\n      addEventListener(type, globalListener)\n    }\n\n    listeners[type].set(\n      dispatch,\n      (listeners[type].get(dispatch) || []).concat(action)\n    )\n\n    return () => {\n      const actions = listeners[type].get(dispatch).filter((a) => a !== action)\n\n      listeners[type].set(dispatch, actions)\n\n      if (\n        actions.length === 0 &&\n        listeners[type].delete(dispatch) &&\n        listeners[type].size === 0\n      ) {\n        delete listeners[type]\n        removeEventListener(type, globalListener)\n      }\n    }\n  })\n\nexport const onMouseMove = on(\"mousemove\")\nexport const onMouseDown = on(\"mousedown\")\nexport const onMouseUp = on(\"mouseup\")\nexport const onKeyDown = on(\"keydown\")\nexport const onKeyUp = on(\"keyup\")\nexport const onClick = on(\"click\")\nexport const onFocus = on(\"focus\")\nexport const onBlur = on(\"blur\")\n"
  },
  {
    "path": "packages/events/package.json",
    "content": "{\n  \"name\": \"@hyperapp/events\",\n  \"version\": \"2.0.0\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"description\": \"Subscribe to mouse, keyboard, window, and frame events.\",\n  \"repository\": \"https://github.com/jorgebucaran/hyperapp/tree/main/packages/events\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"hyperapp\",\n    \"events\",\n    \"keyboard\",\n    \"window\",\n    \"mouse\"\n  ]\n}\n"
  },
  {
    "path": "packages/html/README.md",
    "content": "# @hyperapp/html\n\n> Write HTML with plain functions.\n\nHyperapp's built-in `h()` function is intentionally primitive to give you the freedom to write views any way you like it. If you prefer a functional approach over templating solutions like JSX or template literals, here is a collection of functions—one for [each HTML tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element)—to make your views faster to write and easier to read.\n\nHere's the first example to get you started. [Try it in your browser](https://codepen.io/jorgebucaran/pen/MrBgMy?editors=1000).\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <script type=\"module\">\n      import { app } from \"https://unpkg.com/hyperapp\"\n      import {\n        main,\n        h1,\n        button,\n        text,\n      } from \"https://unpkg.com/@hyperapp/html?module\"\n\n      const Subtract = (state) => ({ ...state, count: state.count - 1 })\n      const Add = (state) => ({ ...state, count: state.count + 1 })\n\n      app({\n        init: (count = 0) => ({ count }),\n        view: (state) =>\n          main([\n            h1(text(state.count)),\n            button({ onclick: Subtract }, text(\"-\")),\n            button({ onclick: Add }, text(\"+\")),\n          ]),\n        node: document.getElementById(\"app\"),\n      })\n    </script>\n  </head>\n  <body>\n    <main id=\"app\"></main>\n  </body>\n</html>\n```\n\n> Looking for [@hyperapp/svg](../svg) instead?\n\n## Installation\n\n```console\nnpm install @hyperapp/html\n```\n\nThen with a module bundler like [Rollup](https://rollupjs.org) or [Webpack](https://webpack.js.org) import it in your application and get right down to business.\n\n```js\nimport { a, form, input } from \"@hyperapp/html\"\n```\n\nDon't want to set up a build step? Import it in a `<script>` tag as a module.\n\n```html\n<script type=\"module\">\n  import { a, form, input } from \"https://unpkg.com/@hyperapp/html?module\"\n</script>\n```\n\n## License\n\n[MIT](../../LICENSE.md)\n"
  },
  {
    "path": "packages/html/index.js",
    "content": "import { h } from \"hyperapp\"\n\nconst EMPTY_ARR = []\nconst EMPTY_OBJ = {}\n\nconst tag = (tag) => (\n  props = EMPTY_OBJ,\n  children = props.tag != null || Array.isArray(props) ? props : EMPTY_ARR\n) => h(tag, props === children ? EMPTY_OBJ : props, children)\n\nexport const a = tag(\"a\")\nexport const b = tag(\"b\")\nexport const i = tag(\"i\")\nexport const p = tag(\"p\")\nexport const q = tag(\"q\")\nexport const s = tag(\"s\")\nexport const br = tag(\"br\")\nexport const dd = tag(\"dd\")\nexport const dl = tag(\"dl\")\nexport const dt = tag(\"dt\")\nexport const em = tag(\"em\")\nexport const h1 = tag(\"h1\")\nexport const h2 = tag(\"h2\")\nexport const h3 = tag(\"h3\")\nexport const h4 = tag(\"h4\")\nexport const h5 = tag(\"h5\")\nexport const h6 = tag(\"h6\")\nexport const hr = tag(\"hr\")\nexport const li = tag(\"li\")\nexport const ol = tag(\"ol\")\nexport const rp = tag(\"rp\")\nexport const rt = tag(\"rt\")\nexport const td = tag(\"td\")\nexport const th = tag(\"th\")\nexport const tr = tag(\"tr\")\nexport const ul = tag(\"ul\")\nexport const bdi = tag(\"bdi\")\nexport const bdo = tag(\"bdo\")\nexport const col = tag(\"col\")\nexport const del = tag(\"del\")\nexport const dfn = tag(\"dfn\")\nexport const div = tag(\"div\")\nexport const img = tag(\"img\")\nexport const ins = tag(\"ins\")\nexport const kbd = tag(\"kbd\")\nexport const map = tag(\"map\")\nexport const nav = tag(\"nav\")\nexport const pre = tag(\"pre\")\nexport const rtc = tag(\"rtc\")\nexport const sub = tag(\"sub\")\nexport const sup = tag(\"sup\")\nexport const wbr = tag(\"wbr\")\nexport const abbr = tag(\"abbr\")\nexport const area = tag(\"area\")\nexport const cite = tag(\"cite\")\nexport const code = tag(\"code\")\nexport const data = tag(\"data\")\nexport const form = tag(\"form\")\nexport const main = tag(\"main\")\nexport const mark = tag(\"mark\")\nexport const ruby = tag(\"ruby\")\nexport const samp = tag(\"samp\")\nexport const span = tag(\"span\")\nexport const time = tag(\"time\")\nexport const aside = tag(\"aside\")\nexport const audio = tag(\"audio\")\nexport const input = tag(\"input\")\nexport const label = tag(\"label\")\nexport const meter = tag(\"meter\")\nexport const param = tag(\"param\")\nexport const small = tag(\"small\")\nexport const table = tag(\"table\")\nexport const tbody = tag(\"tbody\")\nexport const tfoot = tag(\"tfoot\")\nexport const thead = tag(\"thead\")\nexport const track = tag(\"track\")\nexport const video = tag(\"video\")\nexport const button = tag(\"button\")\nexport const canvas = tag(\"canvas\")\nexport const dialog = tag(\"dialog\")\nexport const figure = tag(\"figure\")\nexport const footer = tag(\"footer\")\nexport const header = tag(\"header\")\nexport const iframe = tag(\"iframe\")\nexport const legend = tag(\"legend\")\nexport const object = tag(\"object\")\nexport const option = tag(\"option\")\nexport const output = tag(\"output\")\nexport const select = tag(\"select\")\nexport const source = tag(\"source\")\nexport const strong = tag(\"strong\")\nexport const address = tag(\"address\")\nexport const article = tag(\"article\")\nexport const caption = tag(\"caption\")\nexport const details = tag(\"details\")\nexport const section = tag(\"section\")\nexport const summary = tag(\"summary\")\nexport const picture = tag(\"picture\")\nexport const colgroup = tag(\"colgroup\")\nexport const datalist = tag(\"datalist\")\nexport const fieldset = tag(\"fieldset\")\nexport const menuitem = tag(\"menuitem\")\nexport const optgroup = tag(\"optgroup\")\nexport const progress = tag(\"progress\")\nexport const textarea = tag(\"textarea\")\nexport const blockquote = tag(\"blockquote\")\nexport const figcaption = tag(\"figcaption\")\n\nexport { text } from \"hyperapp\""
  },
  {
    "path": "packages/html/package.json",
    "content": "{\n  \"name\": \"@hyperapp/html\",\n  \"version\": \"2.0.0\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"description\": \"Write HTML with plain functions.\",\n  \"repository\": \"https://github.com/jorgebucaran/hyperapp/tree/main/packages/html\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"hyperapp\",\n    \"html\"\n  ],\n  \"peerDependencies\": {\n    \"hyperapp\": \"^2.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/svg/README.md",
    "content": "# @hyperapp/svg\n\n> Draw SVG with plain functions.\n\nHTML's evil twin. Here's a collection of functions—one for [each SVG tag](https://developer.mozilla.org/en-US/docs/Web/SVG)—to help you get started with SVG in Hyperapp.\n\nWant to draw some circles? [Try this example in your browser](https://codepen.io/jorgebucaran/pen/preYMW?editors=1000).\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <script type=\"module\">\n      import { app } from \"https://unpkg.com/hyperapp\"\n      import { main } from \"https://unpkg.com/@hyperapp/html?module\"\n      import { svg, use, circle } from \"https://unpkg.com/@hyperapp/svg?module\"\n\n      app({\n        init: {},\n        view: () =>\n          main([\n            svg({ viewBox: \"0 0 30 10\" }, [\n              circle({ id: \"symbol\", cx: 5, cy: 5, r: 4, stroke: \"#0366d6\" }),\n              use({ href: \"#symbol\", x: 10, fill: \"#0366d6\" }),\n              use({ href: \"#symbol\", x: 20, fill: \"white\" }),\n            ]),\n          ]),\n        node: document.getElementById(\"app\"),\n      })\n    </script>\n  </head>\n  <body>\n    <main id=\"app\"></main>\n  </body>\n</html>\n```\n\n## Installation\n\n```console\nnpm install @hyperapp/svg\n```\n\nThen with a module bundler like [Rollup](https://rollupjs.org) or [Webpack](https://webpack.js.org) import it in your application and get right down to business.\n\n```js\nimport { svg, use, circle } from \"@hyperapp/svg\"\n```\n\nDon't want to set up a build step? Import it in a `<script>` tag as a module.\n\n```html\n<script type=\"module\">\n  import { svg, use, circle } from \"https://unpkg.com/@hyperapp/svg?module\"\n</script>\n```\n\n## License\n\n[MIT](../../LICENSE.md)\n"
  },
  {
    "path": "packages/svg/index.js",
    "content": "import { h } from \"hyperapp\"\n\nconst EMPTY_ARR = []\nconst EMPTY_OBJ = {}\n\nconst tag = (tag) => (\n  props,\n  children = props.tag != null || Array.isArray(props) ? props : EMPTY_ARR\n) => h(tag, props === children ? EMPTY_OBJ : props, children)\n\nexport const a = tag(\"a\")\nexport const g = tag(\"g\")\nexport const svg = tag(\"svg\")\nexport const use = tag(\"use\")\nexport const set = tag(\"set\")\nexport const line = tag(\"line\")\nexport const path = tag(\"path\")\nexport const rect = tag(\"rect\")\nexport const desc = tag(\"desc\")\nexport const defs = tag(\"defs\")\nexport const mask = tag(\"mask\")\nexport const tref = tag(\"tref\")\nexport const font = tag(\"font\")\nexport const stop = tag(\"stop\")\nexport const view = tag(\"view\")\nexport const text_ = tag(\"text\")\nexport const image = tag(\"image\")\nexport const mpath = tag(\"mpath\")\nexport const title = tag(\"title\")\nexport const glyph = tag(\"glyph\")\nexport const tspan = tag(\"tspan\")\nexport const style = tag(\"style\")\nexport const circle = tag(\"circle\")\nexport const marker = tag(\"marker\")\nexport const symbol = tag(\"symbol\")\nexport const feTile = tag(\"feTile\")\nexport const cursor = tag(\"cursor\")\nexport const filter = tag(\"filter\")\nexport const switch_ = tag(\"switch\")\nexport const ellipse = tag(\"ellipse\")\nexport const polygon = tag(\"polygon\")\nexport const animate = tag(\"animate\")\nexport const pattern = tag(\"pattern\")\nexport const feBlend = tag(\"feBlend\")\nexport const feFlood = tag(\"feFlood\")\nexport const feFuncA = tag(\"feFuncA\")\nexport const feFuncB = tag(\"feFuncB\")\nexport const feFuncG = tag(\"feFuncG\")\nexport const feFuncR = tag(\"feFuncR\")\nexport const feImage = tag(\"feImage\")\nexport const feMerge = tag(\"feMerge\")\nexport const polyline = tag(\"polyline\")\nexport const metadata = tag(\"metadata\")\nexport const altGlyph = tag(\"altGlyph\")\nexport const glyphRef = tag(\"glyphRef\")\nexport const textPath = tag(\"textPath\")\nexport const feOffset = tag(\"feOffset\")\nexport const clipPath = tag(\"clipPath\")\nexport const altGlyphDef = tag(\"altGlyphDef\")\nexport const feComposite = tag(\"feComposite\")\nexport const feMergeNode = tag(\"feMergeNode\")\nexport const feSpotLight = tag(\"feSpotLight\")\nexport const animateColor = tag(\"animateColor\")\nexport const altGlyphItem = tag(\"altGlyphItem\")\nexport const feMorphology = tag(\"feMorphology\")\nexport const feTurbulence = tag(\"feTurbulence\")\nexport const fePointLight = tag(\"fePointLight\")\nexport const colorProfile = tag(\"colorProfile\")\nexport const foreignObject = tag(\"foreignObject\")\nexport const animateMotion = tag(\"animateMotion\")\nexport const feColorMatrix = tag(\"feColorMatrix\")\nexport const linearGradient = tag(\"linearGradient\")\nexport const radialGradient = tag(\"radialGradient\")\nexport const feGaussianBlur = tag(\"feGaussianBlur\")\nexport const feDistantLight = tag(\"feDistantLight\")\nexport const animateTransform = tag(\"animateTransform\")\nexport const feConvolveMatrix = tag(\"feConvolveMatrix\")\nexport const feDiffuseLighting = tag(\"feDiffuseLighting\")\nexport const feDisplacementMap = tag(\"feDisplacementMap\")\nexport const feSpecularLighting = tag(\"feSpecularLighting\")\nexport const feComponentTransfer = tag(\"feComponentTransfer\")\n"
  },
  {
    "path": "packages/svg/package.json",
    "content": "{\n  \"name\": \"@hyperapp/svg\",\n  \"version\": \"2.0.0\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"description\": \"Draw SVG with plain functions.\",\n  \"repository\": \"https://github.com/jorgebucaran/hyperapp/tree/main/packages/svg\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"hyperapp\",\n    \"svg\"\n  ],\n  \"peerDependencies\": {\n    \"hyperapp\": \"^2.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/time/README.md",
    "content": "# @hyperapp/time\n\n> Subscribe to intervals, get the time now.\n\n## Installation\n\n```console\nnpm install @hyperapp/time\n```\n\n```js\nimport { every, delay, now } from \"@hyperapp/time\"\n```\n\nOr without a build step—import it right in your browser.\n\n```html\n<script type=\"module\">\n  import { every, delay, now } from \"https://unpkg.com/@hyperapp/time\"\n</script>\n```\n\n## License\n\n[MIT](../../LICENSE.md)\n"
  },
  {
    "path": "packages/time/index.js",
    "content": "const timeout = (dispatch, props) =>\n  setTimeout(() => dispatch(props.action), props.delay)\n\nconst interval = (dispatch, props) => {\n  const id = setInterval(() => {\n    dispatch(props.action, Date.now())\n  }, props.delay)\n  return () => clearInterval(id)\n}\n\nconst getTime = (dispatch, props) => dispatch(props.action, Date.now())\n\n/**\n * @example\n * app({\n *   subscriptions: (state) => [\n *   // Dispatch RequestResource every delayInMilliseconds\n *   every(state.delayInMilliseconds, RequestResource),\n *   ],\n * })\n */\nexport const every = (delay, action) => [interval, { delay, action }]\n\n/**\n * @example\n * const SlowClap = (state, ms = 1200) => [state, delay(ms, Clap)]\n */\nexport const delay = (delay, action) => [timeout, { delay, action }]\n\n/**\n * @example\n * now(NewTime)\n */\nexport const now = (action) => [getTime, { action }]\n"
  },
  {
    "path": "packages/time/package.json",
    "content": "{\n  \"name\": \"@hyperapp/time\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"main\": \"index.js\",\n  \"description\": \"Subscribe to intervals, get the time now.\",\n  \"repository\": \"https://github.com/jorgebucaran/hyperapp/tree/main/packages/time\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"hyperapp\",\n    \"interval\",\n    \"delay\",\n    \"time\",\n    \"now\"\n  ]\n}\n"
  },
  {
    "path": "tests/index.test.js",
    "content": "import { h, text } from \"../index.js\"\nimport { t, deepEqual } from \"twist\"\n\nexport default [\n  t(\"hyperapp\", [\n    t(\"hyperscript function\", [\n      t(\"create virtual nodes\", [\n        deepEqual(h(\"zord\", { foo: true }, []), {\n          children: [],\n          key: undefined,\n          node: undefined,\n          props: {\n            foo: true,\n          },\n          type: undefined,\n          tag: \"zord\",\n        }),\n      ]),\n    ]),\n    t(\"text function\", [\n      deepEqual(text(\"hyper\"), {\n        children: [],\n        key: undefined,\n        node: undefined,\n        props: {},\n        type: 3,\n        tag: \"hyper\",\n      }),\n    ]),\n  ]),\n]\n"
  }
]