{"_id":"@arve.knudsen/choo","_rev":"3-5566e2ac58e6200f16d93bef5db085ce","name":"@arve.knudsen/choo","description":"A 5kb framework for creating sturdy frontend applications","dist-tags":{"latest":"4.1.1"},"versions":{"4.1.0":{"name":"@arve.knudsen/choo","version":"4.1.0","description":"A 5kb framework for creating sturdy frontend applications","main":"index.js","scripts":{"deps":"./scripts/test deps","test:electron":"./scripts/test electron","test:cov":"./scripts/test cov","test:server":"./scripts/test server","test:browser":"./scripts/test browser","test:browser-local":"./scripts/test browser-local","preversion":"if [ ! -z $SKIP_TEST ]; then npm run test:browser; fi","test":"npm run test:electron","build:dev":"./scripts/build dev","build:min":"./scripts/build min","prepublish":"npm run build:dev && npm run build:min","instrument:discify":"./scripts/instrument discify","instrument:minified":"./scripts/instrument minified","instrument:gzip":"./scripts/instrument gzip"},"repository":{"type":"git","url":"git+https://github.com/aknuds1/choo.git"},"keywords":["client","frontend","framework","minimal","composable","tiny"],"files":["index.js","mount.js","html.js","dist/"],"license":"MIT","dependencies":{"barracks":"^9.1.0","document-ready":"~1.0.2","global":"^4.3.0","nanoraf":"^2.1.1","sheet-router":"^4.0.1","xtend":"^4.0.1","@arve.knudsen/yo-yo":"^1.4.5"},"devDependencies":{"append-child":"~1.0.0","bankai":"^3.1.0","browserify":"^13.0.1","browserify-istanbul":"^2.0.0","bundle-collapser":"^1.2.1","dependency-check":"^2.5.1","disc":"^1.3.2","envify":"^3.4.1","es2020":"^1.0.1","geval":"~2.1.1","gzip-size-cli":"^1.0.0","insert-css":"^1.0.0","istanbul":"^0.4.4","min-document":"~2.19.0","pretty-bytes-cli":"^2.0.0","proxyquire":"~1.7.10","proxyquire-universal":"~1.0.8","proxyquireify":"~3.2.0","server-router":"^3.0.0","sheetify":"^5.1.0","standard":"^8.0.0","standard-markdown":"^2.2.0","tachyons":"^4.0.0-beta.19","tape":"^4.5.1","tape-istanbul":"~1.0.2","tape-run":"~2.1.4","uglifyify":"^3.0.2","uglifyjs":"^2.4.10","unassertify":"^2.0.3","yo-yoify":"^3.1.0","zuul":"github:toddself/zuul"},"bugs":{"url":"https://github.com/aknuds1/choo/issues"},"homepage":"https://github.com/aknuds1/choo#readme","_id":"@arve.knudsen/choo@4.1.0","_shasum":"84bd0025ecc22ad120af5d22e73a010b6e73f718","_from":".","_npmVersion":"4.1.2","_nodeVersion":"7.5.0","_npmUser":{"name":"arve.knudsen","email":"arve.knudsen@gmail.com"},"dist":{"shasum":"84bd0025ecc22ad120af5d22e73a010b6e73f718","tarball":"https://registry.npmjs.org/@arve.knudsen/choo/-/choo-4.1.0.tgz","integrity":"sha512-8rn+sZZVygidClNreq0TBz2wQTE+3eRlU/7JaFDkWM88mqLKYbh+d/j7bqthBaeSnXiWKttWZrLaN3DvzRG/PA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCuDbdNdv/CbKzmIbTUbYI4wtRfZelZHMV2JZ1OrkoK6wIgI9gGhKL6AluFEVSEvQ7aZj8aqjfmGExOAd5vEj4Qcrw="}]},"maintainers":[{"name":"arve.knudsen","email":"arve.knudsen@gmail.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/choo-4.1.0.tgz_1487761813189_0.7787019140087068"}},"4.1.1":{"name":"@arve.knudsen/choo","version":"4.1.1","description":"A 5kb framework for creating sturdy frontend applications","main":"index.js","scripts":{"deps":"./scripts/test deps","test:electron":"./scripts/test electron","test:cov":"./scripts/test cov","test:server":"./scripts/test server","test:browser":"./scripts/test browser","test:browser-local":"./scripts/test browser-local","preversion":"if [ ! -z $SKIP_TEST ]; then npm run test:browser; fi","test":"npm run test:electron","build:dev":"./scripts/build dev","build:min":"./scripts/build min","prepublish":"npm run build:dev && npm run build:min","instrument:discify":"./scripts/instrument discify","instrument:minified":"./scripts/instrument minified","instrument:gzip":"./scripts/instrument gzip"},"repository":{"type":"git","url":"git+https://github.com/aknuds1/choo.git"},"keywords":["client","frontend","framework","minimal","composable","tiny"],"files":["index.js","mount.js","html.js","dist/"],"license":"MIT","dependencies":{"barracks":"^9.1.0","document-ready":"~1.0.2","global":"^4.3.0","nanoraf":"^2.1.1","nanotick":"^1.1.5","@arve.knudsen/sheet-router":"^4.2.4","xtend":"^4.0.1","@arve.knudsen/yo-yo":"^1.4.5"},"devDependencies":{"append-child":"~1.0.0","bankai":"^3.1.0","browserify":"^13.0.1","browserify-istanbul":"^2.0.0","bundle-collapser":"^1.2.1","dependency-check":"^2.5.1","disc":"^1.3.2","envify":"^3.4.1","es2020":"^1.0.1","geval":"~2.1.1","gzip-size-cli":"^1.0.0","insert-css":"^1.0.0","istanbul":"^0.4.4","min-document":"~2.19.0","pretty-bytes-cli":"^2.0.0","proxyquire":"~1.7.10","proxyquire-universal":"~1.0.8","proxyquireify":"~3.2.0","server-router":"^3.0.0","sheetify":"^5.1.0","standard":"^8.0.0","standard-markdown":"^2.2.0","tachyons":"^4.0.0-beta.19","tape":"^4.5.1","tape-istanbul":"~1.0.2","tape-run":"~2.1.4","uglifyify":"^3.0.2","uglifyjs":"^2.4.10","unassertify":"^2.0.3","yo-yoify":"^3.1.0","zuul":"github:toddself/zuul"},"bugs":{"url":"https://github.com/aknuds1/choo/issues"},"homepage":"https://github.com/aknuds1/choo#readme","_id":"@arve.knudsen/choo@4.1.1","_shasum":"76aa119509daef2bcd40283d0b348081b396904b","_from":".","_npmVersion":"4.1.2","_nodeVersion":"7.7.0","_npmUser":{"name":"arve.knudsen","email":"arve.knudsen@gmail.com"},"dist":{"shasum":"76aa119509daef2bcd40283d0b348081b396904b","tarball":"https://registry.npmjs.org/@arve.knudsen/choo/-/choo-4.1.1.tgz","integrity":"sha512-3qkKr4b4GvHgZZ6Ib3HGddCfkX9YhKRWb0FrQLfSoNEZcqGh0FyybwDvSV/Y64egcFpV1mBCu2kVjOvUwQr2Ng==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD3X/WoyYME5wfFw6eS3S/qotY1KlMGEH26SXZ4x7uRBwIgAkE1tisAQxSZdHsvQ9unbUp1IROxFOcV9kt/Ph844h0="}]},"maintainers":[{"name":"arve.knudsen","email":"arve.knudsen@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/choo-4.1.1.tgz_1488476100041_0.5588985504582524"}}},"readme":"<h1 align=\"center\">choo</h1>\n\n<div align=\"center\">\n  :steam_locomotive::train::train::train::train::train:\n</div>\n<div align=\"center\">\n  <strong>Fun functional programming</strong>\n</div>\n<div align=\"center\">\n  A <code>5kb</code> framework for creating sturdy frontend applications\n</div>\n\n<br />\n\n<div align=\"center\">\n  <!-- Stability -->\n  <a href=\"https://nodejs.org/api/documentation.html#documentation_stability_index\">\n    <img src=\"https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square\"\n      alt=\"API stability\" />\n  </a>\n  <!-- NPM version -->\n  <a href=\"https://npmjs.org/package/choo\">\n    <img src=\"https://img.shields.io/npm/v/choo.svg?style=flat-square\"\n      alt=\"NPM version\" />\n  </a>\n  <!-- Build Status -->\n  <a href=\"https://travis-ci.org/yoshuawuyts/choo\">\n    <img src=\"https://img.shields.io/travis/yoshuawuyts/choo/master.svg?style=flat-square\"\n      alt=\"Build Status\" />\n  </a>\n  <!-- Test Coverage -->\n  <a href=\"https://codecov.io/github/yoshuawuyts/choo\">\n    <img src=\"https://img.shields.io/codecov/c/github/yoshuawuyts/choo/master.svg?style=flat-square\"\n      alt=\"Test Coverage\" />\n  </a>\n  <!-- Downloads -->\n  <a href=\"https://npmjs.org/package/choo\">\n    <img src=\"https://img.shields.io/npm/dm/choo.svg?style=flat-square\"\n      alt=\"Downloads\" />\n  </a>\n  <!-- Standard -->\n  <a href=\"https://codecov.io/github/yoshuawuyts/choo\">\n    <img src=\"https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square\"\n      alt=\"Standard\" />\n  </a>\n</div>\n\n<div align=\"center\">\n  <h3>\n    <a href=\"https://yoshuawuyts.gitbooks.io/choo/content\">\n      Handbook\n    </a>\n    <span> | </span>\n      <a href=\"https://github.com/YerkoPalma/awesome-choo\">\n        Ecosystem\n      </a>\n    <span> | </span>\n      <a href=\"https://github.com/trainyard/choo-cli\">\n        CLI\n      </a>\n    <span> | </span>\n    <a href=\"https://github.com/yoshuawuyts/choo/blob/master/.github/CONTRIBUTING.md\">\n      Contributing\n    </a>\n    <span> | </span>\n    <a href=\"https://webchat.freenode.net/?channels=choo\">\n      Chat\n    </a>\n  </h3>\n</div>\n\n<div align=\"center\">\n  <sub>The little framework that could. Built with ❤︎ by\n  <a href=\"https://twitter.com/yoshuawuyts\">Yoshua Wuyts</a> and\n  <a href=\"https://github.com/yoshuawuyts/choo/graphs/contributors\">\n    contributors\n  </a>\n</div>\n\n<h2>Table of Contents</h2>\n<details>\n  <summary>Table of Contents</summary>\n  <li><a href=\"#features\">Features</a></li>\n  <li><a href=\"#demos\">Demos</a></li>\n  <li><a href=\"#example\">Example</a></li>\n  <li><a href=\"#philosophy\">Philosophy</a></li>\n  <li><a href=\"#concepts\">Concepts</a></li>\n  <li><a href=\"#badges\">Badges</a></li>\n  <li><a href=\"#api\">API</a></li>\n  <li><a href=\"#faq\">FAQ</a></li>\n  <li><a href=\"#installation\">Installation</a></li>\n  <li><a href=\"#see-also\">See Also</a></li>\n  <li><a href=\"#support\">Support</a></li>\n</details>\n\n## Features\n- __minimal size:__ weighing `5kb`, `choo` is a tiny little framework\n- __single state:__ immutable single state helps reason about changes\n- __small api:__ with only 6 methods, there's not a lot to learn\n- __minimal tooling:__ built for the cutting edge `browserify` compiler\n- __transparent side effects:__ using `effects` and `subscriptions` brings\n  clarity to IO\n- __omakase:__ composed out of a balanced selection of open source packages\n- __isomorphic:__ renders seamlessly in both Node and browsers\n- __very cute:__ choo choo!\n\n## Demos\n- :truck: [Input example](http://requirebin.com/?gist=229bceda0334cf30e3044d5f5c600960)\n  ([repo](examples/title/))\n- :water_buffalo: [HTTP effects example](https://fork-fang.hyperdev.space/)\n  ([repo](https://hyperdev.com/#!/project/fork-fang))\n- :mailbox: [Mailbox routing](examples/mailbox/)\n- :ok_hand: [TodoMVC](http://shuheikagawa.com/todomvc-choo/)\n  ([repo](https://github.com/shuhei/todomvc-choo))\n- :fire: [Choo-firebase](https://github.com/fyrkant/choo-firebase)\n- :seedling: [Grow](https://grow.static.land/)\n  ([repo](https://github.com/sethvincent/grow))\n- :newspaper: [Hacker News Reader](https://hackernews-choo.surge.sh/) ([repo](https://github.com/kvnneff/hackernews-choo))\n- :earth_africa: [Thing Translator](https://oxism.com/thing-translator/) ([repo](https://github.com/dmotz/thing-translator))\n\n_note: If you've built something cool using `choo` or are using it in\nproduction, we'd love to hear from you!_\n\n## Example\nLet's create an input box that changes the content of a textbox in real time.\n[Click here to see the app running](http://requirebin.com/?gist=229bceda0334cf30e3044d5f5c600960).\n```js\nvar html = require('choo/html')\nvar choo = require('choo')\nvar app = choo()\n\napp.model({\n  state: { title: 'Not quite set yet' },\n  reducers: {\n    update: function (state, data) {\n      return { title: data }\n    }\n  }\n})\n\nfunction mainView (state, prev, send) {\n  return html`\n    <main>\n      <h1>Title: ${state.title}</h1>\n      <input type=\"text\" oninput=${update}>\n    </main>\n  `\n\n  function update (e) {\n    send('update', e.target.value)\n  }\n}\n\napp.router(['/', mainView])\n\nvar tree = app.start()\ndocument.body.appendChild(tree)\n```\n\nTo run it, save it as `client.js` and run with [bankai][bankai]. `bankai` is\nconvenient but any [browserify][browserify] based tool should do:\n```sh\n# run and reload on port 8080\n$ bankai client.js -p 8080 --open\n\n# compile to static files in `./dist/`\n$ bankai build index.js dist/\n\n# deploy to github pages using `tschaub/gh-pages`\n$ gh-pages -d dist/\n```\n\n## Philosophy\nWe believe programming should be fun and light, not stern and stressful. It's\ncool to be cute; using serious words without explaining them doesn't make for\nbetter results - if anything it scares people off. We don't want to be scary,\nwe want to be nice and fun, and then _casually_ be the best choice around.\n_Real casually._\n\nWe believe frameworks should be disposable, and components recyclable. We don't\nlike the current state of web development where walled gardens jealously\ncompete with one another. We want you to be free, not shackled to a damp\ndungeon wall. By making the DOM the lowest common denominator, switching from\none framework to another becomes frictionless. Components should run anywhere\nthat has a DOM, regardless of the framework. `choo` is modest in its design; we\ndon't believe it will be top of the class forever, so we've made it as easy to\ntoss out as it is to pick up.\n\nWe don't believe that bigger is better. Big APIs, big dependencies, large file\nsizes - we see them as omens of impending userland complexity. We  want\neveryone on a team, no matter the size, to fully understand how an application\nis laid out. And once an application is built, we want it to be small,\nperformant and easy to reason about. All of which makes for easy to debug code,\nbetter results and super smiley faces.\n\n## Concepts\n`choo` cleanly structures internal data flow, so that all pieces of logic can\nbe combined into a nice, cohesive machine. Roughly speaking there are two parts\nto `choo`: the views and the models. Models take care of state and logic, and\nviews are responsible for displaying the interface and responding to user\ninteractions.\n\nAll of `choo`'s state is contained in a single object and whenever it changes\nthe views receive a new version of the state which they can use to safely\nrender a complete new representation of the DOM. The DOM is efficiently updated\nusing DOM diffing/patching.\n\nThe logic in choo exist in three different kinds of actions, each with their\nown role: `effects`, `subscriptions` and `reducers`.\n\n- __Effects__ makes an asynchronous operation and calls another action when\n  it's done.\n\n- __Subscriptions__ (called once when the DOM loads) listens for external input\n  like keyboard or WebSocket events and then calls another action.\n\n- __Reducers__ receives the current state and returns an updated version of the\n  state which is then sent to the views.\n\n```txt\n ┌─────────────────┐\n │  Subscriptions ─┤     User ───┐\n └─ Effects  ◀─────┤             ▼\n ┌─ Reducers ◀─────┴─────────── DOM ◀┐\n │                                    │\n └▶ Router ─────State ───▶ Views ────┘\n```\n\n### Models\n`models` are objects that contain initial `state`, `subscriptions`, `effects`\nand `reducers`. They're generally grouped around a theme (or domain, if you\nlike). To provide some sturdiness to your `models`, they can either be\nnamespaced or not. Namespacing means that only state within the model can be\naccessed. Models can still trigger actions on other models, though it's\nrecommended to keep that to a minimum.\n\nSo say we have a `todos` namespace, an `add` reducer and a `todos` model.\nOutside the model they're called by `send('todos:add')` and\n`state.todos.items`. Inside the namespaced model they're called by\n`send('todos:add')` and `state.items`. An example namespaced model:\n```js\nvar app = choo()\napp.model({\n  namespace: 'todos',\n  state: { items: [] },\n  reducers: {\n    add: function (state, data) {\n      return { items: state.items.concat(data.payload) }\n    }\n  }\n})\n```\n\nIn most cases using namespaces is beneficial, as having clear boundaries makes\nit easier to follow logic. But sometimes you need to call `actions` that\noperate over multiple domains (such as a \"logout\" `action`), or have a\n`subscription` that might trigger multiple `reducers` (such as a `websocket`\nthat calls a different `action` based on the incoming data).\n\nIn these cases you probably want to have a `model` that doesn't use namespaces,\nand has access to the full application state. Try and keep the logic in these\n`models` to a minimum, and declare as few `reducers` as possible. That way the\nbulk of your logic will be safely shielded, with only a few points touching every\npart of your application.\n\n### Effects\n`effects` are similar to `reducers` except instead of modifying the state they\ncause side `effects` by interacting servers, databases, DOM APIs, etc. Often\nthey'll call a reducer when they're done to update the state. For instance, you\nmay have an effect called getUsers that fetches a list of users from a server\nAPI using AJAX. Assuming the AJAX request completes successfully, the effect\ncan pass off the list of users to a reducer called receiveUsers which simply\nupdates the state with that list, separating the concerns of interacting with\nan API from updating the application's state.\n\nThis is an example `effect` that is called once when the application loads and\ncalls the `'todos:add'` `reducer` when it receives data from the server:\n\n```js\nvar choo = require('choo')\nvar http = require('xhr')\nvar app = choo()\n\napp.model({\n  namespace: 'todos',\n  state: { values: [] },\n  reducers: {\n    add: function (state, data) {\n      return { todos: data }\n    }\n  },\n  effects: {\n    addAndSave: function (state, data, send, done) {\n      var opts = { body: data.payload, json: true }\n      http.post('/todo', opts, function (err, res, body) {\n        if (err) return done(err)\n        data.payload.id = body.id\n        send('todos:add', data, function (err, value) {\n          if (err) return done(err)\n          done(null, value)\n        })\n      })\n    }\n  },\n  subscriptions: {\n    'called-once-when-the-app-loads': function (send, done) {\n      send('todos:addAndSave', done)\n    }\n  }\n})\n```\n\n### Subscriptions\nSubscriptions are a way of receiving data from a source. For example when\nlistening for events from a server using `SSE` or `Websockets` for a\nchat app, or when catching keyboard input for a videogame.\n\nAn example subscription that logs `\"dog?\"` every second:\n```js\nvar choo = require('choo')\n\nvar app = choo()\napp.model({\n  namespace: 'app',\n  effects: {\n    print: function (state, data) {\n      console.log(data.payload)\n    }\n  },\n  subscriptions: {\n    callDog: function (send, done) {\n      setInterval(function () {\n        var data = { payload: 'dog?', myOtherValue: 1000 }\n        send('app:print', data, function (err) {\n          if (err) return done(err)\n        })\n      }, 1000)\n    }\n  }\n})\n```\n\nIf a `subscription` runs into an error, it can call `done(err)` to signal the\nerror to the error hook.\n\n### Router\nThe `router` manages which `views` are rendered at any given time. It also\nsupports rendering a default `view` if no routes match.\n\n```js\nvar app = choo()\napp.router({ default: '/404' }, [\n  [ '/', require('./views/empty') ],\n  [ '/404', require('./views/error') ],\n  [ '/:mailbox', require('./views/mailbox'), [\n    [ '/:message', require('./views/email') ]\n  ]]\n])\n```\n\nRoutes on the `router` are passed in as a nested array. This means that the\nentry point of the application also becomes a site map, making it easier to\nfigure out how views relate to each other.\n\nUnder the hood `choo` uses [sheet-router]. Internally the\ncurrently rendered route is kept in `state.location`. To access the route\n`:params` you can use `state.location.params`. If you want to modify\nthe location programmatically the `effect` for the location can be called\nusing `send('location:set', href)`. This will not work\nfrom within namespaced `models`, and usage should preferably be kept to a\nminimum. Changing views all over the place tends to lead to messiness.\n\n### Views\nViews are pure functions that return a DOM tree for the router to render.\nThey’re passed the current state, and any time the state changes they’re run\nagain with the new state.\n\nViews are also passed the `send` function, which they can use to dispatch\nactions that can update the state. For example, the DOM tree can have an\n`onclick` handler that dispatches an `add` action.\n\n```js\nfunction view (state, prev, send) {\n  return html`\n    <div>\n      <h1>Total todos: ${state.todos.length}</h1>\n      <button onclick=${addTodo}>Add</button>\n    </div>\n  `\n\n  function addTodo (e) {\n    send('add', { title: 'demo' })\n  }\n}\n```\n\nIn this example, when the `Add` button is clicked, the view will dispatch an\n`add` action that the model’s `add` reducer will receive. [As seen\nabove](#models), the reducer will add an item to the state’s `todos` array. The\nstate change will cause this view to be run again with the new state, and the\nresulting DOM tree will be used to [efficiently patch the\nDOM](#does-choo-use-a-virtual-dom).\n\n### Plugins\nSometimes it's necessary to change the way `choo` itself works. For example to\nreport whenever an action is triggered, handle errors globally or perist state\nsomewhere. This is done through something called `plugins`. Plugins are objects\nthat contain `hook` and `wrap` functions and are passed to `app.use()`:\n\n```js\nvar log = require('choo-log')\nvar choo = require('choo')\nvar app = choo()\n\napp.use(log())\n\nvar tree = app.start()\ndocument.body.appendChild(tree)\n```\n\nGenerally people using `choo` shouldn't be too worried about the specifics of\n`plugins`, as the internal API is (unfortunately by necessity) quite complex.\nAfter all they're the most powerful way to modify a `choo` application.\n\n__:warning: Warning :warning:: plugins should only be used as a last resort.\nIt creates peer dependencies which makes upgrading versions and switching\nframeworks a lot harder. Please exhaust all other options before using\nplugins.__\n\nIf you want to learn more about creating your own `plugins`, and which `hooks`\nand `wrappers` are available, head on over to [app.use()](#appusehooks).\n\n## Badges\nUsing `choo` in a project? Show off which version you've used using a badge:\n\n\n[![built with choo v4](https://img.shields.io/badge/built%20with%20choo-v4-ffc3e4.svg?style=flat-square)](https://github.com/yoshuawuyts/choo)\n```md\n[![built with choo v4](https://img.shields.io/badge/built%20with%20choo-v4-ffc3e4.svg?style=flat-square)](https://github.com/yoshuawuyts/choo)\n```\n\n## API\nThis section provides documentation on how each function in `choo` works. It's\nintended to be a technical reference. If you're interested in learning choo for\nthe first time, consider reading through the [handbook] or\n[concepts](#concepts) first :sparkles:\n\n### app = choo(opts)\nInitialize a new `choo` app. Takes an optional object of handlers that is\npassed to [app.use()](#appusehooks).\n\nOpts can also contain the following values:\n- __opts.history:__ default: `true`. Enable a `subscription` to the browser\n  history API. e.g. updates the internal `location.href` state whenever the\n  browsers \"forward\" and \"backward\" buttons are pressed.\n- __opts.href:__ default: `true`. Handle all relative `<a\n  href=\"<location>\"></a>` clicks and update internal `state.location`\n  accordingly.\n- __opts.hash:__ default: `false`. Enable a `subscription` to the hash change\n  event, updating the internal `state.location` state whenever the URL hash\n  changes (eg `localhost/#posts/123`). Enabling this option automatically\n  disables `opts.history` and `opts.href`.\n\n### app.model(obj)\nCreate a new model. Models modify data and perform IO. Takes the following\narguments:\n- __namespace:__ namespace the model so that it cannot access any properties\n  and handlers in other models\n- __state:__ initial values of `state` inside the model\n- __reducers:__ synchronous operations that modify state. Triggered by\n  `actions`. Signature of `(state, data)`.\n- __effects:__ asynchronous operations that don't modify state directly.\n  Triggered by `actions`, can call `actions`. Signature of `(state, data,\n  send, done)`\n- __subscriptions:__ asynchronous read-only operations that don't modify state\n  directly. Can call `actions`. Signature of `(send, done)`.\n\n#### send(actionName, data?[,callback])\nSend a new action to the models with optional data attached. Namespaced models\ncan be accessed by prefixing the name with the namespace separated with a `:`,\ne.g. `namespace:name`.\n\nWhen sending data from inside a `model` it expects exactly three arguments: the name of the action you're calling, the data you want to send, and finally a callback to handle errors through the global `onError()` hook. So if you want to send two values, you'd have to either send an array or object containing them.\n\n#### done(err?, res?)\nWhen an `effect` or `subscription` is done executing, or encounters an error,\nit should call the final `done(err, res)` callback. If an `effect` was called\nby another `effect` it will call the callback of the caller. When an error\npropegates all the way to the top, the `onError` handler will be called,\nregistered in `choo(handlers)`. If no callback is registered, errors will\n`throw`.\n\n### app.router(defaultRoute?, (route) => [routes])\nCreates a new router. Takes a function that exposes a single `route` function,\nand that expects a tree of `routes` to be returned. See [sheet-router] for full\ndocumentation. Registered views have a signature of `(state, prev, send)`,\nwhere `state` is the current `state`, `prev` is the last state,\n`state.location.params` is URI partials and `send()` can be called to trigger\nactions. If `defaultRoute` is passed in, that will be called if no paths match.\nIf no `defaultRoute` is specified it will throw instead.\n\n### app.use(hooks)\nRegister an object of hooks on the application. This is useful to extend the\nway `choo` works, adding custom behavior and listeners. Generally returning\nobjects of `hooks` is done by returning them from functions (which we call\n`plugins` throughout the documentation).\n\nThere are several `hooks` and `wrappers` that are picked up by `choo`:\n- __onError(err, state, createSend):__ called when an `effect` or\n  `subscription` emit an error. If no handler is passed, the default handler\n  will `throw` on each error.\n- __onAction(state, data, name, caller, createSend):__ called when an\n  `action` is fired.\n- __onStateChange(state, data, prev, caller, createSend):__ called after a\n  reducer changes the `state`.\n- __wrapSubscriptions(fn):__ wraps a `subscription` to add custom behavior\n- __wrapReducers(fn):__ wraps a `reducer` to add custom behavior\n- __wrapEffects(fn):__ wraps an `effect` to add custom behavior\n- __wrapInitialState(fn):__ mutate the complete initial `state` to add custom\n  behavior - useful to mutate the state before starting up\n\n__:warning: Warning :warning:: plugins should only be used as a last resort.\nIt creates peer dependencies which makes upgrading versions and switching\nframeworks a lot harder. Please exhaust all other options before using\nplugins.__\n\n`createSend()` is a special function that allows the creation of a new named\n`send()` function. The first argument should be a string which is the name, the\nsecond argument is a boolean `callOnError` which can be set to `true` to call\nthe `onError` hook istead of a provided callback. It then returns a\n`send(actionName, data?)` function.\n\nHooks should be used with care, as they're the most powerful interface into\nthe state. For application level code it's generally recommended to delegate to\nactions inside models using the `send()` call, and only shape the actions\ninside the hooks.\n\n### html = app.toString(route, state?)\nRender the application to a string of HTML. Useful for rendering on the server.\nFirst argument is a path that's passed to the router. Second argument is an\noptional state object. When calling `.toString()` instead of `.start()`, all\ncalls to `send()` are disabled, and `subscriptions`, `effects` and `reducers`\naren't loaded.\n\n### tree = app.start()\nStart the application. Returns a tree of DOM nodes that can be mounted using\n`document.body.appendChild()`.\n\n### view = require('choo/html')\\`html\\`\nTagged template string HTML builder. Built on top of [yo-yo], [bel], and\n[hyperx]. To register a view on the `router` it should be wrapped in a function\nwith the signature of `(state, prev, send)` where `state` is the current\n`state`, `prev` is the last state, `state.location.params` is URI partials and\n`send()` can be called to trigger actions.\n\nTo create listeners for events, create interpolated attributes on elements.\n```js\nvar html = require('choo/html')\nhtml`\n  <button onclick=${log}>click for bananas</button>\n`\n\nfunction log (e) {\n  console.log(e)\n}\n```\nExample listeners include: `onclick`, `onsubmit`, `oninput`, `onkeydown`,\n`onkeyup`. A full list can be found [at the yo-yo\nrepo](https://github.com/maxogden/yo-yo/blob/master/update-events.js). When\ncreating listeners always remember to call `e.preventDefault()` and\n`e.stopPropagation()` on the event so it doesn't bubble up and do stuff like\nrefreshing the full page or the like.\n\nTo trigger lifecycle events on any part of a view, set the `onload=${(el) =>\n{}}` and `onunload=${(el) => {}}` attributes. These parameters are useful when\ncreating self-contained widgets that take care of their own state and lifecycle\n(e.g. a maps widget) or to trigger animations. Most elements shouldn't have a\nneed for these hooks though.\n\n### mount('selector', html)\nUse `choo/mount` to mount a tree of DOMNodes at a given selector. This is\nespecially useful to mount a `<body>` tag on the document body after rendering\nfrom the server. It makes sure all `<script>` tags and similar are persisted so\nno duplicate download calls are triggered.\n\n## FAQ\n### Why is it called choo?\nBecause I thought it sounded cute. All these programs talk about being\n_\"performant\"_, _\"rigid\"_, _\"robust\"_ - I like programming to be light, fun and\nnon-scary. `choo` embraces that.\n\nAlso imagine telling some business people you chose to rewrite something\ncritical to the company using `choo`.\n:steam_locomotive::train::train::train:\n\n### Why is it a framework, and not a library?\nI love small libraries that do one thing well, but when working in a team,\nhaving an undocumented combination of packages often isn't great. `choo()` is a\nsmall set of packages that work well together, wrapped in an an architectural\npattern. This means you get all the benefits of small packages, but get to be\nproductive right from the start without needing to plough through layers of\nboilerplate.\n\n### Is it called choo, choo.js or...?\nIt's called \"choo\", though we're fine if you call it \"choo-choo\" or\n\"chugga-chugga-choo-choo\" too. The only time \"choo.js\" is tolerated is if /\nwhen you shimmy like you're a locomotive.\n\n### How does choo compare to X?\nAh, so this is where I get to rant. `choo` (_chugga-chugga-chugga-choo-choo!_)\nwas built because other options didn't quite cut it for me, so instead of\npresenting some faux-objective chart with skewed benchmarks and checklists I'll\ngive you my opinions directly. Ready?  Here goes:\n- __react:__ despite being at the root of a giant paradigm shift for frontend\n  (thank you forever!), `react` is kind of big (`155kb` was it?). They also\n  like classes a lot, and enforce a _lot_ of abstractions. It also encourages\n  the use of `JSX` and `babel` which break _JavaScript, The Language™_. And all\n  that without making clear how code should flow, which is crucial in a team\n  setting. I don't like complicated things and in my view `react` is one of\n  them. `react` is not for me.\n- __mithril:__ never used it, never will. I didn't like the API, but if you\n  like it maybe it's worth a shot - the API seems small enough. I wouldn't know\n  how pleasant it is past face value.\n- __preact:__ a pretty cool idea; seems to fix most of what is wrong with\n  `react`. However it doesn't fix the large dependencies `react` seems to use\n  (e.g. `react-router` and friends) and doesn't help at all with architecture.\n  If `react` is your jam, and you will not budge, sitting at `3kb` this is\n  probably a welcome gift.\n- __angular:__ definitely not for me. I like small things with a clear mental\n  model; `angular` doesn't tick any box in my book of nice things.\n- __angular2:__ I'm not sure what's exactly changed, but I know the addition of\n  `TypeScript` and `RxJS` definitely hasn't made things simpler. Last I checked\n  it was `~200kb` in size before including some monstrous extra deps. I guess\n  `angular` and I will just never get along.\n- __mercury:__ ah, `mercury` is an interesting one. It seemed like a brilliant\n  idea until I started using it - the abstractions felt heavy, and it took team\n  members a long time to pick up. In the end I think using `mercury` helped\n  shaped `choo` greatly, despite not working out for me.\n- __deku:__ `deku` is fun. I even contributed a bit in the early days. It could\n  probably best be described as \"a functional version of `react`\". The\n  dependence on `JSX` isn't great, but give it a shot if you think it looks\n  neat.\n- __cycle:__ `cycle`'s pretty good - unlike most frameworks it lays out a clear\n  architecture which helps with reasoning about it. That said, it's built on\n  `virtual-dom` and `xstream` which are a bit heavy for my taste. `choo` works\n  pretty well for FRP style programming, but something like [inu] might be\n  an interesting alternative.\n- __vue:__ like `cycle`, `vue` is pretty good. But it also uses tech that\n  provides framework lock in, and additionally doesn't have a clean enough\n  architecture. I appreciate what it does, but don't think it's the answer.\n\n### Why can't send() be called on the server?\nIn Node, `reducers`, `effects` and `subscriptions` are disabled for performance\nreasons, so if `send()` was called to trigger an action it wouldn't work. Try\nfinding where in the DOM tree `send()` is called, and disable it when called\nfrom within Node.\n\n### Which packages was choo built on?\n- __views:__ [`yo-yo`][yo-yo], [`bel`][bel]\n- __models:__ [`barracks`](https://github.com/yoshuawuyts/barracks),\n  [`xtend`](https://github.com/raynos/xtend)\n- __routes:__ [`sheet-router`][sheet-router]\n- __http:__ [`xhr`](https://github.com/Raynos/xhr)\n\n### Does choo use a virtual-dom?\n`choo` uses [morphdom][morphdom], which diffs real DOM nodes instead of virtual\nnodes. It turns out that [browsers are actually ridiculously good at dealing\nwith DOM nodes][morphdom-bench], and it has the added benefit of working with\n_any_ library that produces valid DOM nodes. So to put a long answer short:\nwe're using something even better.\n\n### How can I optimize choo?\n`choo` really shines when coupled with `browserify` transforms. They can do\nthings like reduce file size, prune dependencies and clean up boilerplate code.\nConsider running some of the following:\n- [unassertify](https://github.com/twada/unassertify) - remove `assert()`\n  statements which reduces file size. Use as a `--global` transform\n- [es2020](https://github.com/yoshuawuyts/es2020) - backport `const`,\n  `arrow functions` and `template strings` to older browsers. Should be run as\n  a `--global` transform\n- [yo-yoify](https://github.com/shama/yo-yoify) - replace the internal `hyperx`\n  dependency with `document.createElement` calls; greatly speeds up performance\n  too\n- [uglifyify](https://github.com/hughsk/uglifyify) - minify your code using\n  UglifyJS2. Use as a `--global` transform\n- [bulkify](https://www.npmjs.com/package/bulkify) - transform inline\n  [bulk-require](https://www.npmjs.com/package/bulk-require) calls into\n  statically resolvable require maps\n- [envify](https://github.com/hughsk/envify) - replace `process.env` values\n  with plain strings\n\n### Choo + Internet Explorer &amp; Safari\nOut of the box `choo` only supports runtimes which support:\n* `const`\n* `arrow functions` (e.g. `() => {}`)\n* `template strings`\n\nThis does not include Safari 9 or any version of IE. If support for these\nplatforms is required you will have to provide some sort of transform that\nmakes this functionality available in older browsers.  The test suite uses\n[es2020](https://github.com/yoshuawuyts/es2020) as a global transform, but\nanything else which might satisfy this requirement is fair game.\n\nGenerally for production builds you'll want to run:\n```sh\n$ NODE_ENV=production browserify \\\n  -t envify \\\n  -g yo-yoify \\\n  -g unassertify \\\n  -g es2020 \\\n  -g uglifyify \\\n  | uglifyjs\n```\n\n## Hey, doesn't this look a lot like Elm?\nYup, it's greatly inspired by the `elm` architecture. But contrary to `elm`,\n`choo` doesn't introduce a completely new language to build web applications.\n\n### Is it production ready?\nSure.\n\n## Browser Test Status\n<a href=\"https://saucelabs.com/u/yoshuawuyts\">\n  <img\n    src=\"https://saucelabs.com/browser-matrix/yoshuawuyts.svg\"\n    alt=\"Sauce Test Status\"/>\n</a>\n\n## Installation\n```sh\n$ npm install choo\n```\n\n## See Also\n- [choo-handbook](https://github.com/yoshuawuyts/choo-handbook) - the little\n  `choo` guide\n- [awesome-choo](https://github.com/YerkoPalma/awesome-choo) - Awesome things\n  related with choo framework\n- [kaktus](https://github.com/kaktus/kaktus) - A new minimalistic web browser\n- [budo](https://github.com/mattdesl/budo) - quick prototyping tool for\n  `browserify`\n- [stack.gl](http://stack.gl/) - open software ecosystem for WebGL\n- [yo-yo](https://github.com/maxogden/yo-yo) - tiny library for modular UI\n- [bel](https://github.com/shama/bel) - composable DOM elements using template\n  strings\n- [tachyons](https://github.com/tachyons-css/tachyons) - functional CSS for\n  humans\n- [sheetify](https://github.com/stackcss/sheetify) - modular CSS bundler for\n  `browserify`\n- [pull-stream](https://github.com/pull-stream/pull-stream) - minimal streams\n- [es2020](https://github.com/yoshuawuyts/es2020) - because in hindsight we\n  don't need most of ES6\n\n## Support\nCreating a quality framework takes a lot of time. Unlike others frameworks,\nChoo is completely independently funded. We fight for our users. This does mean\nhowever that we also have to spend time working contracts to pay the bills.\nThis is where you can help: by chipping in you can ensure more time is spent\nimproving Choo rather than dealing with distractions.\n\n### Sponsors\nBecome a sponsor and help ensure the development of independent quality\nsoftware. You can help us keep the lights on, bellies full and work days sharp\nand focused on improving the state of the web. [Become a\nsponsor](https://opencollective.com/choo#sponsor)\n\n<a href=\"https://opencollective.com/choo/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/sponsor/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/sponsor/29/avatar.svg\"></a>\n\n### Backers\nBecome a backer, and buy us a coffee (or perhaps lunch?) every month or so.\n[Become a backer](https://opencollective.com/choo#backer)\n\n<a href=\"https://opencollective.com/choo/backer/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/choo/backer/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/choo/backer/29/avatar.svg\"></a>\n\n## License\n[MIT](https://tldrlegal.com/license/mit-license)\n\n[bankai]: https://github.com/yoshuawuyts/bankai\n[bel]: https://github.com/shama/bel\n[browserify]: https://github.com/substack/node-browserify\n[budo]: https://github.com/mattdesl/budo\n[es2020]: https://github.com/yoshuawuyts/es2020\n[handbook]: https://github.com/yoshuawuyts/choo-handbook\n[hyperx]: https://github.com/substack/hyperx\n[inu]: https://github.com/ahdinosaur/inu\n[morphdom-bench]: https://github.com/patrick-steele-idem/morphdom#benchmarks\n[morphdom]: https://github.com/patrick-steele-idem/morphdom\n[sheet-router]: https://github.com/yoshuawuyts/sheet-router\n[yo-yo]: https://github.com/maxogden/yo-yo\n","maintainers":[{"name":"arve.knudsen","email":"arve.knudsen@gmail.com"}],"time":{"modified":"2022-06-12T14:49:02.278Z","created":"2017-02-22T11:10:13.937Z","4.1.0":"2017-02-22T11:10:13.937Z","4.1.1":"2017-03-02T17:35:02.411Z"},"homepage":"https://github.com/aknuds1/choo#readme","keywords":["client","frontend","framework","minimal","composable","tiny"],"repository":{"type":"git","url":"git+https://github.com/aknuds1/choo.git"},"bugs":{"url":"https://github.com/aknuds1/choo/issues"},"license":"MIT","readmeFilename":"README.md"}