[
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\nnpm-debug.log\ntest/coverage\n"
  },
  {
    "path": ".jshintignore",
    "content": "node_modules\nfastdom.js\nstrict.js\n"
  },
  {
    "path": ".jshintrc",
    "content": "{\n  \"camelcase\": false,\n  \"forin\": false,\n  \"latedef\": \"nofunc\",\n  \"newcap\": false,\n  \"noarg\": true,\n  \"node\": true,\n  \"nonew\": true,\n  \"quotmark\": \"single\",\n  \"undef\": true,\n  \"unused\": \"vars\",\n  \"trailing\": true,\n  \"maxlen\": 80,\n  \"laxbreak\": true,\n  \"sub\": true,\n\n  \"eqnull\": true,\n  \"expr\": true,\n\n  \"maxerr\": 1000,\n  \"regexdash\": true,\n  \"laxcomma\": true,\n  \"proto\": true,\n  \"boss\": true,\n\n  \"esnext\": true,\n\n  \"browser\": true,\n  \"devel\": true,\n  \"nonstandard\": true,\n  \"worker\": true,\n\n  \"-W078\": true,\n\n  \"predef\": [\n    \"define\"\n  ]\n}\n"
  },
  {
    "path": ".npmignore",
    "content": "**/*.\nbower.json\nwebpack.config.js\nnode_modules\nexamples\ntest\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: required\ndist: trusty\n\nlanguage: node_js\n\nnode_js:\n  - 5.1.0\n\naddons:\n  firefox: latest\n  apt:\n    sources:\n      - google-chrome\n    packages:\n      - google-chrome-stable\n\nbefore_script:\n  - export CHROME_BIN=$(which google-chrome-stable)\n  - export DISPLAY=:99.0\n  - sh -e /etc/init.d/xvfb start\n\nafter_script:\n  - npm run coveralls\n"
  },
  {
    "path": "README.md",
    "content": "# fastdom [![Twitter Follow](https://img.shields.io/twitter/follow/wilsonpage?style=social)](https://twitter.com/wilsonpage)\n\n[![Build Status](https://travis-ci.org/wilsonpage/fastdom.svg?branch=master)](https://travis-ci.org/wilsonpage/fastdom) [![NPM version](https://badge.fury.io/js/fastdom.svg)](http://badge.fury.io/js/fastdom) [![npm](https://img.shields.io/npm/dm/fastdom.svg?maxAge=2592000)]() [![Coverage Status](https://coveralls.io/repos/wilsonpage/fastdom/badge.svg?branch=master&service=github)](https://coveralls.io/github/wilsonpage/fastdom?branch=master) ![gzip size](http://img.badgesize.io/https://unpkg.com/fastdom/fastdom.min.js?compression=gzip)\n\n\nEliminates layout thrashing by batching DOM read/write operations (~600 bytes minified gzipped).\n\n```js\nfastdom.measure(() => {\n  console.log('measure');\n});\n\nfastdom.mutate(() => {\n  console.log('mutate');\n});\n\nfastdom.measure(() => {\n  console.log('measure');\n});\n\nfastdom.mutate(() => {\n  console.log('mutate');\n});\n```\n\nOutputs:\n\n```\nmeasure\nmeasure\nmutate\nmutate\n```\n\n## Examples\n\n- [Animation example](http://wilsonpage.github.io/fastdom/examples/animation.html)\n- [Aspect ratio example](http://wilsonpage.github.io/fastdom/examples/aspect-ratio.html)\n\n## Installation\n\nFastDom is CommonJS and AMD compatible, you can install it in one of the following ways:\n\n```sh\n$ npm install fastdom --save\n```\n\nor [download](http://github.com/wilsonpage/fastdom/raw/master/fastdom.js).\n\n## How it works\n\nFastDom works as a regulatory layer between your app/library and the DOM. By batching DOM access we **avoid unnecessary document reflows** and dramatically **speed up layout performance**.\n\nEach measure/mutate job is added to a corresponding measure/mutate queue. The queues are emptied (reads, then writes) at the turn of the next frame using [`window.requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame).\n\nFastDom aims to behave like a singleton across *all* modules in your app. When any module requires `'fastdom'` they  get the same instance back, meaning FastDom can harmonize DOM access app-wide.\n\nPotentially a third-party library could depend on FastDom, and better integrate within an app that itself uses it.\n\n## API\n\n### FastDom#measure(callback[, context])\n\nSchedules a job for the 'measure' queue. Returns a unique ID that can be used to clear the scheduled job.\n\n```js\nfastdom.measure(() => {\n  const width = element.clientWidth;\n});\n```\n\n### FastDom#mutate(callback[, context])\n\nSchedules a job for the 'mutate' queue. Returns a unique ID that can be used to clear the scheduled job.\n\n```js\nfastdom.mutate(() => {\n  element.style.width = width + 'px';\n});\n```\n\n### FastDom#clear(id)\n\nClears **any** scheduled job.\n\n```js\nconst read = fastdom.measure(() => {});\nconst write = fastdom.mutate(() => {});\n\nfastdom.clear(read);\nfastdom.clear(write);\n```\n\n## Strict mode\n\nIt's very important that all DOM mutations or measurements go through `fastdom` to ensure good performance; to help you with this we wrote `fastdom-strict`. When `fastdom-strict.js` is loaded, it will throw errors when sensitive DOM APIs are called at the wrong time.\n\nThis is useful when working with a large team who might not all be aware of `fastdom` or its benefits. It can also prove useful for catching 'un-fastdom-ed' code when migrating an app to `fastdom`.\n\n```html\n<script src=\"fastdom.js\"></script>\n<script src=\"fastdom-strict.js\"></script>\n```\n\n```js\nelement.clientWidth; // throws\nfastdom.mutate(function() { element.clientWidth; }); // throws\nfastdom.measure(function() { element.clientWidth; }); // does not throw\n```\n\n```js\n\"Error: Can only get .clientWidth during 'measure' phase\"\n```\n\n- `fastdom-strict` will not throw if nodes are not attached to the document.\n- You should use `fastdom-strict` in development to catch rendering performance issues before they hit production.\n- It is not advisable to use `fastdom-strict` in production.\n\n## Exceptions\n\nFastDom is async, this can therefore mean that when a job comes around to being executed, the node you were working with may no longer be there. These errors are usually not critical, but they can cripple your app.\n\nFastDom allows you to register a `catch` handler. If `fastdom.catch` has been registered, FastDom will catch any errors that occur in your jobs, and run the handler instead.\n\n```js\nfastdom.catch = (error) => {\n  // Do something if you want\n};\n\n```\n\n## Extensions\n\nThe core `fastdom` library is designed to be as light as possible. Additional functionality can be bolted on in the form of 'extensions'. It's worth noting that `fastdom` is a 'singleton' by design, so all tasks (even those scheduled by extensions) will reach the same global task queue.\n\n**Fastdom ships with some extensions:**\n\n- [`fastdom-promised`](extensions/fastdom-promised.js) - Adds Promise based API\n- [`fastdom-sandbox`](extensions/fastdom-sandbox.js) - Adds task grouping concepts\n\n### Using an extension\n\nUse the `.extend()` method to extend the current `fastdom` to create a new object.\n\n```html\n<script src=\"fastdom.js\"></script>\n<script src=\"extensions/fastdom-promised.js\"></script>\n```\n\n```js\n// extend fastdom\nconst myFastdom = fastdom.extend(fastdomPromised);\n\n// use new api\nmyFastdom.mutate(...).then(...);\n```\n\nExtensions can be chained to construct a fully customised `fastdom`.\n\n```js\nconst myFastdom = fastdom\n  .extend(fastdomPromised)\n  .extend(fastdomSandbox);\n```\n\n### Writing an extension\n\n```js\nconst myFastdom = fastdom.extend({\n  measure(fn, ctx) {\n    // do custom stuff ...\n\n    // then call the parent method\n    return this.fastdom.measure(fn, ctx);\n  },\n\n  mutate: ...\n});\n```\n\nYou'll notice `this.fastdom` references the parent `fastdom`. If you're extending a core API and aren't calling the parent method, you're doing something wrong.\n\nWhen distributing an extension only export a plain object to allow users to compose their own `fastdom`.\n\n```js\nmodule.exports = {\n  measure: ...,\n  mutate: ...,\n  clear: ...\n};\n```\n\n## Tests\n\n```sh\n$ npm install\n$ npm test\n```\n\n## Author\n\n- **Wilson Page** - [@wilsonpage](http://twitter.com/wilsonpage)\n\n## Contributors\n\n- **Wilson Page** - [@wilsonpage](http://twitter.com/wilsonpage)\n- **Paul Irish** - [@paulirish](http://github.com/paulirish)\n- **Kornel Lesinski** - [@pornel](http://github.com/pornel)\n- **George Crawford** - [@georgecrawford](http://github.com/georgecrawford)\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2016 Wilson Page <wilsonpage@me.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": "bower.json",
    "content": "{\n  \"name\": \"fastdom\",\n  \"description\": \"Eliminates layout thrashing by batching DOM read/write operations\",\n  \"main\": \"fastdom.js\",\n  \"scripts\": [\n    \"fastdom.js\"\n  ],\n  \"ignore\": [\n    \"**/*.\",\n    \"webpack.config.js\",\n    \"examples/\",\n    \"test/\",\n    \"README.md\"\n  ],\n  \"license\": \"MIT\",\n  \"_source\": \"git@github.com/wilsonpage/fastdom.git\"\n}\n"
  },
  {
    "path": "examples/animation.html",
    "content": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>FastDom: Animation Example</title>\n\t\t<script type=\"text/javascript\" src=\"../fastdom.min.js\"></script>\n\t</head>\n\t<body>\n\n\t\t<style>\n\n\t\t\t.mover {\n\t\t\t\t/* Stolen shamelessly from https://developers.google.com/chrome-developer-tools/docs/demos/too-much-layout/ */\n\t\t\t\tbackground: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAZFElEQVR42u2da4wdxZXH61T3PHBMjM3YOCweXsYwY/NYbAMRYCCwdkwMBkKyL0R2N1+ASBHkoUhZaS2vlJWiPFhFiskXhECJsgrLw8DGwYFABrK8TBYb2wO2Ae+YEDDjB8GMPTO3q/Z2dz1OVVdV930NZMVIre57Zwx2/+Z//uecOtUXyBR//csLf4D0DPUv9DZUPNvX9nvc8T3uuC47E17/Ss//uvQv+FTeH/gQQbjOvutG4DQCwXetzlMNBqYChEMNIQjQAKQyhVS5+bzC95VqOg0GpghEFQC+g3he+/4NPADEB8J3ONXTSTAwRTBCIGgABm0QSlUYLACBlYDpKBSYAhCkBACtcO1TThWFVLnxLACEhVTTbjBtA7Jm01vUE55cNz90phXAkYCf+Mzbd6OZdR06+5RD1i45nn1kgFgwoAIM6nlNK0BzKdCVZfmAMA8Q5oDDKkDh7YQCHfKKEIRGDls1UOIlpMS4WQmIKkdQMa2GMGgDDHxjaEUYUYVrWhLCqigkFKLwkVS4DkFh+BehFSjQBhhVVRE5zlHge1WgVFWID0YSOPu+V0ktzUKBDsAIgbCvXYcLTCh0VVGIfQN9AFyHD5ALTstQoE0w7JvmU0N6xCWvXQBpibmHFOJSRxKAUSt57VONUy2NQoE2wXCpQt7M2HHzfWd57QTy7p79R2/f8c5Jh2ts+t4jtZPEP8H6N+S9pzm98e6jYnpocMFxu2fPm/V+AEjNcfN9Z3lt/zeCamkECrQZBv7ttm9ybF3HjvcNpex4aWTutjffW/T2RLLwICODE4T0mX/rkt6iOHUTMnoMJdvndkfbFp4wY+uCc/rfDiij5jgS6xr/fMhfGoYCbYYRedQgjy4PEPWzKYTfjxy4YM8Ev3SMk/78/wbibwrlFQhxtgXlbcnO04CMzOuGJ8/tn/msgBOCkR6THkAuv2kJSikQUfQ1AsP+re9yACmA2fS7XfNfePvQqr2MLDMgYBg2lCp1uoRhQZHnOZQMLZ07/ZElF87fFQAx6XjPpZpSKGXFIzRQgdMSGCFFdPmuf/v48NkvHhj/4vucDOT/B8GcSgiAFOGB4l0NsWFIi+H5rcrez6+PBjK8eGbPLy65fGCzBcJ3HVJMKD0OVvTQQKjCQKIAjC4PDON4d2TfjP98YeTLexksK4CAHAQAer8AJVvsChLhzIIhAQgwnBfBzKF86Pql/XfO7j/2PQTBPlzqcUFJXBlYKHRBA75R5hdlELrl9c/Xb1792iT7QkJgWn7jLRAUKSP9ovlfwQCAv+/0D24nXnVAzPy+ODgTYMRrSvjYqV303r9dffZ6BGGiApwyXyn1E6joG/K1Sxl2iCoAkNd1VRzz8+dHvnqQwxIJILv5CgDVqsAeIqCAgmP/K8C48XYWnL2bcP0zCAjHcFJg2Zln6poJfNPfnNf/o7paDjqgTDjA1BxgpFIKdYordEGJOnwFX+xQhgtGt7ze9PTOBY/98f1vTVLap244peqmK1VEoMMRBfOGC0hgg3BAwGrhnJvvM45UI64TBCgDk8e8LsZGr/jU0d9dctFpOxCIiYBqbF/xFpAulUCDvmGHKRyiuj0wuuswTtv49qG1CdBpUg1YGThEFUDI92nFcBUKWxwBwGAkNIZCmFIKJxHnY8vnTl+z5KL5OxEQG8qEx1fs8BX0Ex8QGvANqQ4fDON48OEty18eZ7eoG001AAXCeG2BAFoEgJQRFImlFO0b6YmZ4YuZILS3cAVrUQ9dd81VZ220oEwEoISyrwyMF4hHHb46owxGj4SxNYUhQSgoNLULK2TRoiIsH4EqyggohVv+YShGQlBekocunphqWWhCGa8ApVZm8hgKVFCHL5vq8qgig/Hohq0Xbfqg9k0jNEUSBlXKME1d3nQLBA5XTZi6Hm0IgJFQDHUwASJXUwan/nrxJ+LvrVi56GkPlImApyQuPykACajD9g2fMnrw+cXf7Tr9scwzYFoGQSogg4FCFzh8BKe/qk1CxXVrClGmTZAa5PcTt3/k72ml8ITVbwQfu+K46WsWXzj/VQvKeEn48kFRKoGAOuxGYVwBRk89tZ159wsjP5wA2pdDyJUhVQGWj6RZFQCChrMplPLqVgk01KbmWDXMbJtwy9wzX5GekeRANCCmPaX+vW7ORm9cOu9r9ZT4gABRBqXmaUgaKoGK6rBDVbcLRnrccf9L3z5I6JI8POGQlKsjhwOmbxhqscKWDUH5SRmIYgrMcfiyw5WEwLWRcxWyTCDyvRmEbbr52nP+DQEZd4SxqqErUwk46g5fvdHlMW913Pvwlmtfq/EvgagxJBQZqpRiXEqRYLBPIA+BUMs9NGot2yjY3BlShjgrKAoGClvqOslfJwJQ/edOjeHu66866wELyrjHU4L1CQZSZuRdHnWoY+dLI/PWv3Hg+5lvpDc0whCEd0TaL9L3japcwkFAQFbuRPewmhoCyITgAsO0inB44vn3uJX+kgSHrSQDQhkfW33yzG+cdk7/ngCUSQeUxAGEAWqT+GqOuAxGetz54Obb9hFYZighEmfxGiuCRggErjVAq0R5iAtE5ZhlgxFwGG4y4vZJ7iUKRsKNsCWzLp7o944lfOifrjn7dgeQKqHLSIMlEFevCht5twdIb3p+6jevLH7mvfE12W+9gEAjDEEYeowUAjp8yewKewe4FEHNtntpsc4dqS+R3fdw6ivDVmb0KMOScPR1DufTM7rXXvSZM14UEI54gEwEDD4z9xRI5Mis4orqyICse3DLd8YIGcjCFFKFNHFVe3j9g6BMyzZtKPawquEoqsNh8Ng77BYKs0w8N3ZmAsnOjEzjZPjma876ZweQkEpsL+ESCA5XccA7CjCerqvj2T9NrElBgExjpUpSCPL97FoDwXWHVkb9zzha7BhOc5N93FyzYhYYlWkx/X2pBOUvGgBHJq/S4/r753/Sq5LxgJfUcNjCQOzMqssKVzLF7UVAeu9av+XWAyRdZEpDEvYMmoctK82FyCoIUZii1Epvy0BANXEUwFh9Lma3UcS1qktQ+qvUocAwBWkW50P/sPqsfxcwjiAwMhXGYWvSlXGlQOKScGWnuQpImlk9tPvgOhqJkCQLwFiEKxBqUVBoftNBt1LAKgJtGMU9P6R6tsVdbJheTZRhy26nYA+xWikM+UgOpX7UNLRVJ864RWRcRyyl2GmwM2xJIC4zL/OO3gceefm63Qm5MfeO/ObjDAtUiMoVk4cxVCziPlUWrvI2ib7hDteABm2Eu4TDDV/hghDH/S7b3BNmFIy5SvR19vM1Rk6MyD3XrjrzfkslVTKuDEoKpCuQ6uJwZcBIjzseevn2cYB+CYRilciQRcEIU9SxKAWqb4XMG7fYK9x8KI9WdqmoBKOhmH6SWQpjRgs+NXpeQxmWBaeH8ZGbrj7zNgTEhuJqqSRYIV0VCkEbyFG7Nu+Z91//e/DHqt6IaFZbAI1QUQhmha7UQXWIorjuMG+vqziHJuf1OXclXmYrhaGlXgyAcNPQdY0iQlgiqvgkT4E/d+IxX5l/9rw0bB1uwNwTqZDuCm0SDOSoFMovN2xdsXOS35wauQ5VdSgxBkB170pAANS3AlQI6hY7FKrzlvZNBOtFUSaKUGV7CReFIUeVvFKEUSCKcwYkIfNjuOPKlYseFTAOVwhbytwlkCqVeS8Gcs/DW249CHRZHpZolmEBRWFLQDLqjwgMz5DqUCuFhJo3HvyKqNzt9Zm9BYbLVcT0lSwEZZ8LdYCZUa0zox5hmcEzMpOzoRuuUtnWYY+5Oyt3DASnu8FwlfnHwy//pEZpH0S5V8j+lQIUFdNcwL5B9TqHLgbDmRS02D3h3gwsv2KJtW4ii0BuZluZr9RyOHm2lWiF1N+LGBu9adWZNyEgZWFLLfWmQHoq+odSyOie/X3/8dJbdwHOrqQiIt1IpMg7ZIaVj/roZVrArRLLxF0d3mZDF3fkw2ZHJX+POZZ3mVwPSRAQ6S81hkJXkqfAdTB/fc7x/9g3b9aoQyFBH8FA4gpAMoX89xOvnvs/H0zmvSvpIagWyVQi1JA1EetGr+oSuSIow5WYUDTqjTJ1QPM0/CrJq3TGUKhCWRcXLXeG1kYYClfS0LMucP37fzmta+2nLzv990ghZUAMhVQxdAXkice2Xzw8zr4OUaTDUkyRiVPVw6KysRjhkIVAUGrkVHYdCK3uMiIlT6RhZsbFGapLGCmELGY0GBMNKsHGzshAD/3BpVcMPBUA4jT2FEhvQCG4XaKA3P/LrTe8w+HzmSoEiEwJhdBFVJNR9qnUGjtY4arCHDVAa7YemoFQUFgxbMl2vMqy0j+TpbzS3PNQpcEwchzh91175aKfWkDsNopTIb0VK3QF5IEUCNDPA0XZVJdQg0h99Sqh8I70fWuIWq8EAgFnZlW+ft5wO8uu2I2MS2ZbaBBbeYgGwlQbBZ1ricqy0p87jrD7rllZAFJasVcFYijkwQ1b//4dIoBkHhIREIUhobJA1CuGytSt+oPawwwAfu+ANoUsHvIS7SN44YpZQw95CEtUD0uBqelUOAWyeuWinzkU0hIQZ8hav2HbDe8QuE6aOY2pCSLOK/b0RlORcSlTNzIsamRYlq+35BtV/YRbPsLx0APnhodwtMbOVA+LITDivTqYOYTfv3rlwlDIai+QvRJIrGsPWaVnkKx2Cdh1iFr/IOYMlt0/9BQbLRWGxF6s0j/NuCPD4jjl1UAyH2G6/sAKmcP5/Vd3AIgzZK2vh6x3Uw9BCtEgRIGIQ1WEWifSQ6i+BkQCoFhzuLy8YSCO1JcXVhNNhXBOjEWqgnfIwlH4Bsuajkl2ns3ZfVd3IGQ5Tf2hDVtv0ECiPFRFVvuEIk9BS7bUXrKVA9XE3A7iW/OANoWqYrhCIYvpQWyGQhdLkDrQ2ogMVQxlWrNZct9VbTZ1b9qbAhmtA8lXBBEQ2YaXIYxa7RPpKaL+kCGrStoLbaoMC+0UK+3lDGVZXEDg2Ed0+FJhC1XrrJbXJrN5ct+qlc2lvQ0Xhk89/srFuyb513FBSFUbJVK9LT1CSkQIE7UJMne9bAuV015oh5EX0l6RZ6GBbM4QIFmd4+XcmjByVSTqAvHUGH5w8eVnNFUYNtw6ee7JV88dHk+y1onKsGLd3U2zLIrqEFWriBClQphMdZV3eMy9TS14208K6pAVuWid4LV25RfIxHmCsq1EhK5a3joZ6I3WnndJ862ThpuLj2x7+y4qsyxKVadXrRKmfhFHKkxRNOxAjT0gVKzm+opDPwgoafdyzv1guH0tMiwcrqxxIMa40cNiiV4xzNTC9JrIlYNzm24uNtV+/9mj23+SUNpHI91clF6iAAl1UDEeRNFMFkVbDrLQZoeowNbntvSy8CiQ3ceS6sDhKtFdX7mMy6SnqNCVX1PGRv9uxWDT7femFqge+NW2Ww9RuixVgWHkka5D5IJUfk1UsZh5h5zhwgMO1tZnr0pa7fbyopeo6pzgVNf0D1mVq+ua7vrKRiOrn6cnbOiazy5saYGq4SXcJzZuX/EHAjerBao6GJlVqQIxC1tUjf8Yq4a4KESrhwWVgP8pGk15CLcf9GB3eREc3CoRS7k4TDG0fKtT34QcT/gdly0fbHoJt6khh9e37Jn3zB8P/TjPtKJcBXGuFFmly3ktqhasUJORiul2aqlEpMH+pdwGN+x4G4k6WDG8po6qdFVvYA9JZLaFMyuOMixGLpg7/SunnNX8kEPTY0D3Pjp8+2RE+yNj1TBXhTZ61GgEAQkslRQWq7Q8gplWA+O93DlxoqtxmQRIOIahG8qQmZXZMslrEk6iGhu5fsVAS2NATQ/KPbZx+3XvUnojlY3FLPWNtJlHehaLRnpQThWNxkKVfnyG3oXg2I4A5dU7D89co0FrYuzQ1QtReYVueoYebNDZVA6HidHS9NzH2D2XLx9saVCu6VHS1zfvmff83kPrqBqUi1QLhaKZLGX0VrYFaNjBmOulJhRwEIAqA1q8mPpya75XXjO0LRp7Bi+EKj2pyBIEQ4SwJbOn33JKPpPV9ChpS8PWjzy67daxOF4GwjPkgHWmijjSi1QynFGtGsPM0z9DrMlFqSCfbzS4OsXwCCl6EA0TG3i4GAHCUBjOsMSGT+wXuDA8KkmGPrd8sOVh65a2I2z67Y7Fr0+yNeqGRw4QEa7cdbORoq0JShkEzLEg4yFy0NBCFcd+gatzFLIyxSRMZ1oou8I+kqazRIUojtJdDebkLrp28bIFbdmO0NKGnfUbh79TN/cBqjIuPTAXUdR0RJt4ZGGYKSr9n4qzhEHVQ8yKT3Aw7R48MFix9rBA4L0isoeVpq1ylVCBQYMMDIUrDCWuseGrlw+0ZcNOy1vaXhzasXh3XSXKL1CmlReNUR6BItQBVgMQ2j+osS0a+Yf9RAeoaOrWljbONCysFCaNXClCj4gyLv2D6ExLZVa6Yj+pC9ae61ZHw1va2rLpc8PG7bcdjqNstDRS+wxlxgUIht43ouBID8G+AeJ5KMjYDR+nFccWOR505+jBctwahJMeguoObvatGOMobOkl3J7JZOizywfbs+mzXdui36hnXJv3jX2/fsOn5RAi7Sm4FsEgshk61HCkVNcl6XvWtjZoZNMO93mIHl7IQg4hxpS7UktiFoRMjosKc2diS0L9jbFFs6Z94+Q8s2p9W3Q7Hxzw5K+3X/teHH1JeYUIW6ouwaNBkV6wUm0WMKcb1XSKK2xV3R0iQTCmWiN61IcYLRKmFqSEcbsyrQSvgXDyyVrt7kv+arDtDw5o26M1fvXr7d+e7IqXGM1F1EJR1TyAUSyClXEpc5cbfGQlb3UeoaT1zoll5vI6YUarRNUesu7geqLdqENQhR7XaptWXDHY3kdrpH+5dj58ZnRk/8znd+79IY/EZDzVy7pAkSJEoYizLgUhyv8alJqVunpYZmlHy1yy1Xs+iIKgOrwkD08yvdUpLwLAitkVJGx06fzZX+vrn9Xeh89YQNryeKbtz752+u4jydr6HZxGIxymtMljg8f9LaCOESEj8yJoYw9UWJjCwwrFUR+OVgaz9XAuu7pmhzcPYTkYYHysvzdeM3jBKZ15PFNAJU0/wOz5J165aB/Qb6q9h5CbO0XGblTtEg7V041A9EC22lkFxUajBFNok1iPG8/9Qae99gAc5442iVQJajAey9j3ll52RuceYFaikqYf8ffMY8PL3+uKbqE4REV63lcpA0xvyX8tqK5LCHqoMliFIZQs32IDx91d3MnF6W1h7YMboapu4usuuHyg84/4K1FJ0w/BfPbx4eV/iuNbdJiiRoiiaLKRqr3sePYXdYMRjGq7p7SZM2OaXQLRyuHicUuqX2UXiCmMydq68zWMzj4EM6CSlh8TO/zc66e9NV73FJo+uomaECKqhuWwuWcKiPIWijElbz9g2Zf4clR7EPT8KzF7leVYiS4KGdqPrq/VgMPY8T10zRnnnzK1j4l1QGnbg5Rfee71BW8dqX2rXsb35ZYCqHWi09t8tTEt3MFsNtqhK7TH0C4CLWOXasiYML0fXc5gZSaeU0vHekY/1Rt/tw5j6h+kLL869ajxfXv2H7Nt196vJlmdggpCZOh4KNsYqLMeqOyeZHRMKHLsG2ghiuubr5qJCapB6mc6MblpcP6cHx07b9aH96hxT+hq68P4n/vNK6vHu+MvpCHMXrSSW+Ao3keC2vGAnsMIvv6JUoaes1L1B9frHszYbsB0CpzwsZ6J2r3nfeaMj8bD+Cv6SUsfV1FXy4xXd7375aQnXkZlliUqdDwipJRCUEuFFB+/4Wos4gcB6DTXqtATc7iBjk8OLTh19p11VXx0Pq7CCl2EdPADXbY+vfPs9zn5Io+jAUDb3KhcY4/A8A5Aw9muxSpu9d+lL8iRn/zGmy2TNEzRWjJ8NCW/WHjhaR/ND3QJ+ElHPvJoxwtvzD9weHIV74qXqWcyijUSIPpBZ4WHmQUWQzhaIVR1iFCErEFgIhk65qj4kQVLT/7of+RRwE869qFgIy+/OXd0/wcX1I3/Uk6hH/DGHvRpO1C1uWhswFGbb0biidqTx876xLP9Z57w5/WhYE1AadvH5o1sfXPugX0fLEqiaCHvigbrcPqMv3iFzw8Rs7qjZDLZHjG2beasaVv7F53w5/uxeU1A6dgHS+5/c//R74zsP6meCU2vcXKSa51KloMxkN315ODQcf2zds864f/ZB0tWhPLxR69O5UevVoDy8YcTT/WHEzcA5eOP756qj+/2QCHk4w+4//A+4N4BhTSolqpHKFQ1ohBf6Grm8KpC0mgWRjv2wLgq+kZCGVRQRMjMyxTiM/cyxfAGIPAqFfiUAnFAqaIY39kXonzZVdnHE3PPDWUe1YTOBQjthNFWIIEQRgI31uc7Ic+wlRHaHhL6jWYVrl2vSTtDVEeBVPAWElBNSFGkxDvAA4N4biarCIr7/jvtBtFRIB4opAQMlBh3GQzSIJQqh8uPOgajo0A8YEjAmEMgSElm5Zsl5QGTJxUBoGX6zoGYMiAYjFj185ly2c2voo4ylVSFZKghPXcaxJQDCYAhFW5+GYTQs/irwiG2GqYShPz6P4ApMQgx8bbkAAAAAElFTkSuQmCC\");\n\t\t\t\theight: 100px;\n\t\t\t\twidth: 100px;\n\t\t\t\tposition: absolute;\n\t\t\t\t/*20% fps boost as described here https://developers.google.com/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas/ */\n\t\t\t\twill-change: transform;\n\t\t\t}\n\n\t\t\tbutton.active {\n\t\t\t\tcolor: red;\n\t\t\t}\n\n\t\t\t.intro {\n\t\t\t\tmargin: 10px;\n\t\t\t\tbackground: rgb(214, 213, 213);\n\t\t\t\tborder: 1px solid grey;\n\t\t\t\tpadding: 10px;\n\t\t\t}\n\n\t\t</style>\n\n\t\t<div class=\"intro\">An adaptation of the demo from the Google Developers article <a href=\"https://developers.google.com/chrome-developer-tools/docs/demos/too-much-layout/\">Diagnosing forced synchronous layouts</a>. In the article, forced synchronous layouts are fixed by simply <em>not doing any reads at all</em>. Rather than this extreme solution, which will not be appropriate for many use cases, we instead use <strong>fastdom</strong> to intelligently defer and batch the DOM reads and writes, and get similar performance gains as a result.</div>\n\t\t<label>Number of elements <input id=\"count\" type=\"text\" value=\"400\" /></label>\n\t\t<button id=\"sync\" class=\"active\">Forced synchronous layout</button>\n\t\t<button id=\"async\">Run with FastDom</button>\n\t\t<button id=\"noread\">No DOM reads</button>\n\t\t<button id=\"toggle\">Start</button>\n\n\t\t<div id='test'></div>\n\n\t\t<script>\n\n\t\t\tvar moveMethod = 'sync',\n\t\t\t\tcount      = document.getElementById('count'),\n\t\t\t\ttest       = document.getElementById('test'),\n\t\t\t\ttimestamp, raf, movers;\n\n\t\t\tvar mover = {\n\t\t\t\tsync: function(m) {\n\n\t\t\t\t\t// Read the top offset, and use that for the left position\n\t\t\t\t\tmover.setLeft(movers[m], movers[m].offsetTop);\n\t\t\t\t},\n\t\t\t\tasync: function(m) {\n\n\t\t\t\t\t// Use fastdom to batch the reads\n\t\t\t\t\t// and writes with exactly the same\n\t\t\t\t\t// code as the 'sync' routine\n\t\t\t\t\tfastdom.measure(function() {\n\t\t\t\t\t\tvar top = movers[m].offsetTop;\n\t\t\t\t\t\tfastdom.mutate(function() {\n\t\t\t\t\t\t\tmover.setLeft(movers[m], top);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tnoread: function(m) {\n\n\t\t\t\t\t// Simply use the array index\n\t\t\t\t\t// as the top value, so no DOM\n\t\t\t\t\t// read is required\n\t\t\t\t\tmover.setLeft(movers[m], m);\n\t\t\t\t},\n\t\t\t\tsetLeft: function(mover, top) {\n\t\t\t\t\tmover.style.transform = 'translateX( ' +((Math.sin(top + timestamp/1000) + 1) * 500) + 'px)';\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tfunction update(thisTimestamp) {\n\t\t\t\ttimestamp = thisTimestamp;\n\t\t\t\tfor (var m = 0; m < movers.length; m++) {\n\t\t\t\t\tmover[moveMethod](m);\n\t\t\t\t}\n\t\t\t\traf = window.requestAnimationFrame(update);\n\t\t\t}\n\n\t\t\tfunction toggleAnim(e) {\n\n\t\t\t\tvar html, num;\n\n\t\t\t\tif (raf) {\n\n\t\t\t\t\twindow.cancelAnimationFrame(raf);\n\t\t\t\t\traf = false;\n\t\t\t\t\te.currentTarget.innerHTML = 'Start';\n\t\t\t\t\tcount.disabled = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\thtml = '';\n\t\t\t\t\tnum = count.value;\n\n\t\t\t\t\tfor (i = 0; i < num; i++) {\n\t\t\t\t\t\thtml += '<div class=\"mover\"></div>';\n\t\t\t\t\t}\n\t\t\t\t\ttest.innerHTML = html;\n\n\t\t\t\t\tmovers = test.querySelectorAll('.mover');\n\t\t\t\t\tmovers[0].style.top = '150px';\n\t\t\t\t\tfor (var m = 1; m < movers.length; m++) {\n\t\t\t\t\t\tmovers[m].style.top = (m * 20) + 150 + 'px';\n\t\t\t\t\t}\n\n\t\t\t\t\traf = window.requestAnimationFrame(update);\n\t\t\t\t\te.currentTarget.innerHTML = 'Stop';\n\t\t\t\t\tcount.disabled = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction setMethod(method) {\n\t\t\t\tdocument.getElementById(moveMethod).classList.remove('active');\n\t\t\t\tdocument.getElementById(method).classList.add('active');\n\t\t\t\tmoveMethod = method;\n\t\t\t}\n\n\t\t\tdocument.getElementById('toggle').addEventListener('click', toggleAnim);\n\t\t\tdocument.getElementById('sync').addEventListener('click', function() {\n\t\t\t\tsetMethod('sync');\n\t\t\t});\n\t\t\tdocument.getElementById('async').addEventListener('click', function() {\n\t\t\t\tsetMethod('async');\n\t\t\t});\n\t\t\tdocument.getElementById('noread').addEventListener('click', function() {\n\t\t\t\tsetMethod('noread');\n\t\t\t});\n\n\t\t</script>\n\n\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/aspect-ratio.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>FastDom: Aspect Ratio Example</title>\n<style>\n\n  * {\n    box-sizing: border-box;\n  }\n\n  div {\n    float: left;\n    background: silver;\n    border: solid 2px white;\n  }\n\n</style>\n</head>\n<body>\n  <label>Number of elements <input id=\"input\" type=\"text\" value=\"100\" /></label>\n  <button id=\"withoutFastDom\">Run without FastDom</button>\n  <button id=\"withRequestAnimationFrame\">Run with requestAnimationFrame</button>\n  <button id=\"withFastDom\">Run with FastDom</button>\n  <button id=\"resetbtn\">reset</button>\n  <section id=\"perf\"></section>\n  <section id=\"container\"></section>\n  <script src=\"../fastdom.js\"></script>\n  <script>\n    var n;\n    var start;\n    var divs;\n\n    // Setup\n    function reset(done) {\n      n = input.value;\n      divs = [];\n\n      fastdom.measure(function() {\n        var winWidth = window.innerWidth;\n\n        fastdom.mutate(function() {\n          container.innerHTML = '';\n\n          for (var i = 0; i < n; i++) {\n            var div = document.createElement('div');\n            div.style.width = Math.round(Math.random() * winWidth) + 'px';\n            container.appendChild(div);\n            divs.push(div);\n          }\n\n          if (done) done();\n        });\n      });\n    }\n\n    function setAspect(div, i) {\n      var aspect = 9 / 16;\n      var isLast = i === (n - 1);\n      var h = div.clientWidth * aspect;\n\n      div.style.height = h + 'px';\n\n      if (isLast) {\n        displayPerf(performance.now() - start);\n      }\n    }\n\n    function setAspectRequestAnimationFrame(div, i) {\n      var aspect = 9 / 16;\n      var isLast = i === (n - 1);\n\n      // READ\n      requestAnimationFrame(function() {\n        var h = div.clientWidth * aspect;\n\n        // WRITE\n        requestAnimationFrame(function() {\n          div.style.height = h + 'px';\n\n          if (isLast) {\n            displayPerf(performance.now() - start);\n          }\n        });\n      });\n    }\n\n    function setAspectFastDom(div, i) {\n      var aspect = 9 / 16;\n      var isLast = i === (n - 1);\n\n      // READ\n      fastdom.measure(function() {\n        var h = div.clientWidth * aspect;\n\n        // WRITE\n        fastdom.mutate(function() {\n          div.style.height = h + 'px';\n\n          if (isLast) {\n            displayPerf(performance.now() - start);\n          }\n        });\n      });\n    }\n\n    function displayPerf(ms) {\n      perf.textContent = ms + 'ms';\n    }\n\n    withoutFastDom.onclick = function() {\n      reset(function() {\n        start = performance.now();\n        divs.forEach(setAspect);\n      });\n    };\n\n    withFastDom.onclick = function() {\n      reset(function() {\n        start = performance.now();\n        divs.forEach(setAspectFastDom);\n      });\n    };\n\n    withRequestAnimationFrame.onclick = function() {\n      reset(function() {\n        start = performance.now();\n        divs.forEach(setAspectRequestAnimationFrame);\n      });\n    };\n\n    resetbtn.onclick = function() {\n      reset();\n    };\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "extensions/fastdom-promised.d.ts",
    "content": "declare namespace FastdomPromised {\n  export function clear<T extends Promise<any>>(task: T): void;\n  export function initialize(): void;\n  export function measure<T extends () => void>(task: T, context?: any): Promise<ReturnType<T>>;\n  export function mutate<T extends () => void>(task: T, context?: any): Promise<ReturnType<T>>;\n}\n\nexport = FastdomPromised;\n"
  },
  {
    "path": "extensions/fastdom-promised.js",
    "content": "!(function() {\n\n/**\n * Wraps fastdom in a Promise API\n * for improved control-flow.\n *\n * @example\n *\n * // returning a result\n * fastdom.measure(() => el.clientWidth)\n *   .then(result => ...);\n *\n * // returning promises from tasks\n * fastdom.measure(() => {\n *   var w = el1.clientWidth;\n *   return fastdom.mutate(() => el2.style.width = w + 'px');\n * }).then(() => console.log('all done'));\n *\n * // clearing pending tasks\n * var promise = fastdom.measure(...)\n * fastdom.clear(promise);\n *\n * @type {Object}\n */\nvar exports = {\n  initialize: function() {\n    this._tasks = new Map();\n  },\n\n  mutate: function(fn, ctx) {\n    return create(this, 'mutate', fn, ctx);\n  },\n\n  measure: function(fn, ctx) {\n    return create(this, 'measure', fn, ctx);\n  },\n\n  clear: function(promise) {\n    var tasks = this._tasks;\n    var task = tasks.get(promise);\n    this.fastdom.clear(task);\n    tasks.delete(promise);\n  }\n};\n\n/**\n * Create a fastdom task wrapped in\n * a 'cancellable' Promise.\n *\n * @param  {FastDom}  fastdom\n * @param  {String}   type - 'measure'|'mutate'\n * @param  {Function} fn\n * @return {Promise}\n */\nfunction create(promised, type, fn, ctx) {\n  var tasks = promised._tasks;\n  var fastdom = promised.fastdom;\n  var task;\n\n  var promise = new Promise(function(resolve, reject) {\n    task = fastdom[type](function() {\n      tasks.delete(promise);\n      try { resolve(ctx ? fn.call(ctx) : fn()); }\n      catch (e) { reject(e); }\n    }, ctx);\n  });\n\n  tasks.set(promise, task);\n  return promise;\n}\n\n// Expose to CJS, AMD or global\nif ((typeof define)[0] == 'f') define(function() { return exports; });\nelse if ((typeof module)[0] == 'o') module.exports = exports;\nelse window.fastdomPromised = exports;\n\n})();"
  },
  {
    "path": "extensions/fastdom-sandbox.js",
    "content": "(function(exports) {\n\n/**\n * Mini logger\n *\n * @return {Function}\n */\nvar debug = 0 ? console.log.bind(console, '[fastdom-sandbox]') : function() {};\n\n/**\n * Exports\n */\n\n/**\n * Create a new `Sandbox`.\n *\n * Scheduling tasks via a sandbox is\n * useful because you can clear all\n * sandboxed tasks in one go.\n *\n * This is handy when working with view\n * components. You can create one sandbox\n * per component and call `.clear()` when\n * tearing down.\n *\n * @example\n *\n * var sandbox = fastdom.sandbox();\n *\n * sandbox.measure(function() { console.log(1); });\n * sandbox.measure(function() { console.log(2); });\n *\n * fastdom.measure(function() { console.log(3); });\n * fastdom.measure(function() { console.log(4); });\n *\n * sandbox.clear();\n *\n * // => 3\n * // => 4\n *\n * @return {Sandbox}\n * @public\n */\nexports.sandbox = function() {\n  return new Sandbox(this.fastdom);\n};\n\n/**\n * Initialize a new `Sandbox`\n *\n * @param {FastDom} fastdom\n */\n\nfunction Sandbox(fastdom) {\n  this.fastdom = fastdom;\n  this.tasks = [];\n  debug('initialized');\n}\n\n/**\n * Schedule a 'measure' task.\n *\n * @param  {Function} fn\n * @param  {Object}   ctx\n * @return {Object} can be passed to .clear()\n */\nSandbox.prototype.measure = function(fn, ctx) {\n  var tasks = this.tasks;\n  var task = this.fastdom.measure(function() {\n    tasks.splice(tasks.indexOf(task));\n    return fn.call(ctx);\n  });\n\n  tasks.push(task);\n  return task;\n};\n\n/**\n * Schedule a 'mutate' task.\n *\n * @param  {Function} fn\n * @param  {Object}   ctx\n * @return {Object} can be passed to .clear()\n */\nSandbox.prototype.mutate = function(fn, ctx) {\n  var tasks = this.tasks;\n  var task = this.fastdom.mutate(function() {\n    tasks.splice(tasks.indexOf(task));\n    return fn.call(ctx);\n  });\n\n  this.tasks.push(task);\n  return task;\n};\n\n/**\n * Clear a single task or is no task is\n * passsed, all tasks in the `Sandbox`.\n *\n * @param  {Object} task (optional)\n */\n\nSandbox.prototype.clear = function(task) {\n  if (!arguments.length) clearAll(this.fastdom, this.tasks);\n  remove(this.tasks, task);\n  return this.fastdom.clear(task);\n};\n\n/**\n * Clears all the given tasks from\n * the given `FastDom`.\n *\n * @param  {FastDom} fastdom\n * @param  {Array} tasks\n * @private\n */\n\nfunction clearAll(fastdom, tasks) {\n  debug('clear all', fastdom, tasks);\n  var i = tasks.length;\n  while (i--) {\n    fastdom.clear(tasks[i]);\n    tasks.splice(i, 1);\n  }\n}\n\n/**\n * Remove an item from an Array.\n *\n * @param  {Array} array\n * @param  {*} item\n * @return {Boolean}\n */\nfunction remove(array, item) {\n  var index = array.indexOf(item);\n  return !!~index && !!array.splice(index, 1);\n}\n\n/**\n * Expose\n */\n\nif ((typeof define)[0] == 'f') define(function() { return exports; });\nelse if ((typeof module)[0] == 'o') module.exports = exports;\nelse window.fastdomSandbox = exports;\n\n})({});\n"
  },
  {
    "path": "fastdom-strict.js",
    "content": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"fastdom\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"fastdom\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"fastdom\"] = factory(require(\"fastdom\"));\n\telse\n\t\troot[\"fastdom\"] = factory(root[\"fastdom\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tvar strictdom = __webpack_require__(1);\n\tvar fastdom = __webpack_require__(2);\n\n\t/**\n\t * Mini logger\n\t *\n\t * @return {Function}\n\t */\n\tvar debug = 0 ? console.log.bind(console, '[fastdom-strict]') : function() {};\n\n\t/**\n\t * Enabled state\n\t *\n\t * @type {Boolean}\n\t */\n\tvar enabled = false;\n\n\twindow.fastdom = module.exports = fastdom.extend({\n\t  measure: function(fn, ctx) {\n\t    debug('measure');\n\t    var task = !ctx ? fn : fn.bind(ctx);\n\t    return this.fastdom.measure(function() {\n\t      if (!enabled) return task();\n\t      return strictdom.phase('measure', task);\n\t    }, ctx);\n\t  },\n\n\t  mutate: function(fn, ctx) {\n\t    debug('mutate');\n\t    var task = !ctx ? fn : fn.bind(ctx);\n\t    return this.fastdom.mutate(function() {\n\t      if (!enabled) return task();\n\t      return strictdom.phase('mutate', task);\n\t    }, ctx);\n\t  },\n\n\t  strict: function(value) {\n\t    if (value) {\n\t      enabled = true;\n\t      strictdom.enable();\n\t    } else {\n\t      enabled = false;\n\t      strictdom.disable();\n\t    }\n\t  }\n\t});\n\n\t// turn on strict-mode\n\twindow.fastdom.strict(true);\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tvar __WEBPACK_AMD_DEFINE_RESULT__;!(function() {\n\t'use strict';\n\n\tvar debug = 0 ? console.log.bind(console, '[strictdom]') : function() {};\n\n\t/**\n\t * Crude webkit test.\n\t *\n\t * @type {Boolean}\n\t */\n\t// var isWebkit = !!window.webkitURL;\n\n\t/**\n\t * List of properties observed.\n\t *\n\t * @type {Object}\n\t */\n\tvar properties = {\n\t  prototype: {\n\t    Document: {\n\t      execCommand: Mutate,\n\t      elementFromPoint: Measure,\n\t      elementsFromPoint: Measure,\n\t      scrollingElement: Measure\n\t    },\n\n\t    Node: {\n\t      appendChild: {\n\t        type: Mutate,\n\t        test: function(dom, parent, args) {\n\t          var attached = isAttached(parent) || isAttached(args[0]);\n\t          if (attached && dom.not('mutate')) throw error(3, this.name);\n\t        }\n\t      },\n\n\t      insertBefore: {\n\t        type: Mutate,\n\t        test: function(dom, parent, args) {\n\t          var attached = isAttached(parent) || isAttached(args[0]);\n\t          if (attached && dom.not('mutate')) throw error(3, this.name);\n\t        }\n\t      },\n\n\t      removeChild: {\n\t        type: Mutate,\n\t        test: function(dom, parent, args) {\n\t          var attached = isAttached(parent) || isAttached(args[0]);\n\t          if (attached && dom.not('mutate')) throw error(3, this.name);\n\t        }\n\t      },\n\n\t      textContent: Mutate\n\t    },\n\n\t    Element: {\n\t      scrollIntoView: Mutate,\n\t      scrollBy: Mutate,\n\t      scrollTo: Mutate,\n\t      getClientRects: Measure,\n\t      getBoundingClientRect: Measure,\n\t      clientLeft: Measure,\n\t      clientWidth: Measure,\n\t      clientHeight: Measure,\n\t      scrollLeft: Accessor,\n\t      scrollTop: Accessor,\n\t      scrollWidth: Measure,\n\t      scrollHeight: Measure,\n\t      innerHTML: Mutate,\n\t      outerHTML: Mutate,\n\t      insertAdjacentHTML: Mutate,\n\t      remove: Mutate,\n\t      setAttribute: Mutate,\n\t      removeAttribute: Mutate,\n\t      className: Mutate,\n\t      classList: ClassList\n\t    },\n\n\t    HTMLElement: {\n\t      offsetLeft: Measure,\n\t      offsetTop: Measure,\n\t      offsetWidth: Measure,\n\t      offsetHeight: Measure,\n\t      offsetParent: Measure,\n\t      innerText: Accessor,\n\t      outerText: Accessor,\n\t      focus: Measure,\n\t      blur: Measure,\n\t      style: Style,\n\n\t      // `element.dataset` is hard to wrap.\n\t      // We could use `Proxy` but it's not\n\t      // supported in Chrome yet. Not too\n\t      // concerned as `data-` attributes are\n\t      // not often associated with render.\n\t      // dataset: DATASET\n\t    },\n\n\t    CharacterData: {\n\t      remove: Mutate,\n\t      data: Mutate\n\t    },\n\n\t    Range: {\n\t      getClientRects: Measure,\n\t      getBoundingClientRect: Measure\n\t    },\n\n\t    MouseEvent: {\n\t      layerX: Measure,\n\t      layerY: Measure,\n\t      offsetX: Measure,\n\t      offsetY: Measure\n\t    },\n\n\t    HTMLButtonElement: {\n\t      reportValidity: Measure\n\t    },\n\n\t    HTMLDialogElement: {\n\t      showModal: Mutate\n\t    },\n\n\t    HTMLFieldSetElement: {\n\t      reportValidity: Measure\n\t    },\n\n\t    HTMLImageElement: {\n\t      width: Accessor,\n\t      height: Accessor,\n\t      x: Measure,\n\t      y: Measure\n\t    },\n\n\t    HTMLInputElement: {\n\t      reportValidity: Measure\n\t    },\n\n\t    HTMLKeygenElement: {\n\t      reportValidity: Measure\n\t    },\n\n\t    SVGSVGElement: {\n\t      currentScale: Accessor\n\t    }\n\t  },\n\n\t  instance: {\n\t    window: {\n\t      getComputedStyle: {\n\t        type: Measure,\n\n\t        /**\n\t         * Throws when the Element is in attached\n\t         * and strictdom is not in the 'measure' phase.\n\t         *\n\t         * @param  {StrictDom} strictdom\n\t         * @param  {Window} win\n\t         * @param  {Object} args\n\t         */\n\t        test: function(strictdom, win, args) {\n\t          if (isAttached(args[0]) && strictdom.not('measure')) {\n\t            throw error(2, 'getComputedStyle');\n\t          }\n\t        }\n\t      },\n\n\t      // innerWidth: {\n\t      //   type: isWebkit ? Value : Measure,\n\t      //\n\t      //   /**\n\t      //    * Throws when the window is nested (in <iframe>)\n\t      //    * and StrictDom is not in the 'measure' phase.\n\t      //    *\n\t      //    * @param  {StrictDom} strictdom\n\t      //    */\n\t      //   test: function(strictdom) {\n\t      //     var inIframe = window !== window.top;\n\t      //     if (inIframe && strictdom.not('measure')) {\n\t      //       throw error(2, '`.innerWidth` (in iframe)');\n\t      //     }\n\t      //   }\n\t      // },\n\t      //\n\t      // innerHeight: {\n\t      //   type: isWebkit ? Value : Measure,\n\t      //\n\t      //   /**\n\t      //    * Throws when the window is nested (in <iframe>)\n\t      //    * and StrictDom is not in the 'measure' phase.\n\t      //    *\n\t      //    * @param  {StrictDom} strictdom\n\t      //    */\n\t      //   test: function(strictdom) {\n\t      //     var inIframe = window !== window.top;\n\t      //     if (inIframe && strictdom.not('measure')) {\n\t      //       throw error(2, '`.innerHeight` (in iframe)');\n\t      //     }\n\t      //   }\n\t      // },\n\t      //\n\t      // scrollX: isWebkit ? Value : Measure,\n\t      // scrollY: isWebkit ? Value : Measure,\n\t      scrollBy: Mutate,\n\t      scrollTo: Mutate,\n\t      scroll: Mutate,\n\t    }\n\t  }\n\t};\n\n\t/**\n\t * The master controller for all properties.\n\t *\n\t * @param {Window} win\n\t */\n\tfunction StrictDom(win) {\n\t  this.properties = [];\n\t  this._phase = null;\n\t  this.win = win;\n\n\t  this.createPrototypeProperties();\n\t  this.createInstanceProperties();\n\t}\n\n\tStrictDom.prototype = {\n\n\t  /**\n\t   * Set the current phase.\n\t   * @param  {[type]} value [description]\n\t   * @return {[type]}       [description]\n\t   */\n\t  phase: function(type, task) {\n\t    if (!arguments.length) return this._phase;\n\t    if (!this.knownPhase(type)) throw error(4, type);\n\n\t    var previous = this._phase;\n\t    this._phase = type;\n\n\t    if (typeof task != 'function') return;\n\n\t    var result = task();\n\t    this._phase = previous;\n\t    return result;\n\t  },\n\n\t  knownPhase: function(value) {\n\t    return !!~['measure', 'mutate', null].indexOf(value);\n\t  },\n\n\t  is: function(value) {\n\t    return this._phase === value;\n\t  },\n\n\t  not: function(value) {\n\t    return !this.is(value);\n\t  },\n\n\t  /**\n\t   * Enable strict mode.\n\t   *\n\t   * @public\n\t   */\n\t  enable: function() {\n\t    if (this.enabled) return;\n\t    debug('enable');\n\t    var i = this.properties.length;\n\t    while (i--) this.properties[i].enable();\n\t    this.enabled = true;\n\t  },\n\n\t  /**\n\t   * Disable strict mode.\n\t   *\n\t   * @public\n\t   */\n\t  disable: function() {\n\t    if (!this.enabled) return;\n\t    debug('disable');\n\t    var i = this.properties.length;\n\t    while (i--) this.properties[i].disable();\n\t    this.enabled = false;\n\t    this.phase(null);\n\t  },\n\n\t  /**\n\t   * Create wrappers for each of\n\t   * of the prototype properties.\n\t   *\n\t   * @private\n\t   */\n\t  createPrototypeProperties: function() {\n\t    debug('create prototype properties');\n\t    var props = properties.prototype;\n\t    for (var key in props) {\n\t      for (var name in props[key]) {\n\t        var object = this.win[key] && this.win[key].prototype;\n\t        if (!object || !object.hasOwnProperty(name)) continue;\n\t        this.properties.push(this.create(object, name, props[key][name]));\n\t      }\n\t    }\n\t  },\n\n\t  /**\n\t   * Create wrappers for each of\n\t   * of the instance properties.\n\t   *\n\t   * @private\n\t   */\n\t  createInstanceProperties: function() {\n\t    debug('create instance properties');\n\t    var props = properties.instance;\n\t    for (var key in props) {\n\t      for (var name in props[key]) {\n\t        var object = this.win[key];\n\t        if (!object || !object.hasOwnProperty(name)) continue;\n\t        this.properties.push(this.create(object, name, props[key][name]));\n\t      }\n\t    }\n\t  },\n\n\t  /**\n\t   * Create a wrapped `Property` that\n\t   * can be individually enabled/disabled.\n\t   *\n\t   * @param  {Object} object - the parent object (eg. Node.prototype)\n\t   * @param  {String} name - the property name (eg. 'appendChild')\n\t   * @param  {(constructor|Object)} config - from the above property definition\n\t   * @return {Property}\n\t   */\n\t  create: function(object, name, config) {\n\t    debug('create', name);\n\t    var Constructor = config.type || config;\n\t    return new Constructor(object, name, config, this);\n\t  }\n\t};\n\n\t/**\n\t * Create a new `Property`.\n\t *\n\t * A wrapper around a property that observes\n\t * usage, throwing errors when used in the\n\t * incorrect phase.\n\t *\n\t * @param {Object} object - the parent object (eg. Node.prototype)\n\t * @param {[type]} name - the property name (eg. 'appendChild')\n\t * @param {(constructor|Object)} config - from the above definition\n\t * @param {StrictDom} strictdom - injected as a dependency\n\t */\n\tfunction Property(object, name, config, strictdom) {\n\t  debug('Property', name, config);\n\n\t  this.strictdom = strictdom;\n\t  this.object = object;\n\t  this.name = name;\n\n\t  var descriptor = this.getDescriptor();\n\n\t  // defaults can be overriden from config\n\t  if (typeof config == 'object') Object.assign(this, config);\n\n\t  this.descriptors = {\n\t    unwrapped: descriptor,\n\t    wrapped: this.wrap(descriptor)\n\t  };\n\t}\n\n\tProperty.prototype = {\n\n\t  /**\n\t   * Get the property's descriptor.\n\t   *\n\t   * @return {Object}\n\t   * @private\n\t   */\n\t  getDescriptor: function() {\n\t    debug('get descriptor', this.name);\n\t    return Object.getOwnPropertyDescriptor(this.object, this.name);\n\t  },\n\n\t  /**\n\t   * Enable observation by replacing the\n\t   * current descriptor with the wrapped one.\n\t   *\n\t   * @private\n\t   */\n\t  enable: function() {\n\t    debug('enable', this.name);\n\t    Object.defineProperty(this.object, this.name, this.descriptors.wrapped);\n\t  },\n\n\t  /**\n\t   * Disable observation by replacing the\n\t   * current descriptor with the original one.\n\t   *\n\t   * @private\n\t   */\n\t  disable: function() {\n\t    debug('disable', this.name);\n\t    Object.defineProperty(this.object, this.name, this.descriptors.unwrapped);\n\t  },\n\n\t  // to be overwritten by subclass\n\t  wrap: function() {}\n\t};\n\n\t/**\n\t * A wrapper for properties that measure\n\t * geometry data from the DOM.\n\t *\n\t * Once a `Measure` property is enabled\n\t * it can only be used when StrictDom\n\t * is in the 'measure' phase, else it\n\t * will throw.\n\t *\n\t * @constructor\n\t * @extends Property\n\t */\n\tfunction Measure() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tMeasure.prototype = extend(Property, {\n\n\t  /**\n\t   * Return a wrapped descriptor.\n\t   *\n\t   * @param  {Object} descriptor\n\t   * @return {Object}\n\t   */\n\t  wrap: function(descriptor) {\n\t    debug('wrap measure', this.name);\n\n\t    var clone = Object.assign({}, descriptor);\n\t    var value = descriptor.value;\n\t    var get = descriptor.get;\n\t    var self = this;\n\n\t    if (typeof value == 'function') {\n\t      clone.value = function() {\n\t        debug('measure', self.name);\n\t        self.test(self.strictdom, this, arguments);\n\t        return value.apply(this, arguments);\n\t      };\n\t    } else if (get) {\n\t      clone.get = function() {\n\t        debug('measure', self.name);\n\t        self.test(self.strictdom, this, arguments);\n\t        return get.apply(this, arguments);\n\t      };\n\t    }\n\n\t    return clone;\n\t  },\n\n\t  /**\n\t   * Throws an Error if the element is attached\n\t   * and StrictDOM is not in the 'measure' phase.\n\t   *\n\t   * If methods/properties are used without\n\t   * a context (eg. `getComputedStyle()` instead\n\t   * of `window.getComputedStyle()`) we infer\n\t   * a `window` context.\n\t   *\n\t   * @param  {StrictDom} strictdom\n\t   * @param  {Node} ctx\n\t   */\n\t  test: function(strictdom, ctx) {\n\t    if (isAttached(ctx || window) && strictdom.not('measure')) {\n\t      throw error(2, this.name);\n\t    }\n\t  }\n\t});\n\n\t/**\n\t * A wrapper for properties that mutate\n\t * to the DOM, triggering style/reflow\n\t * operations.\n\t *\n\t * Once a `Mutate` property is enabled\n\t * it can only be used when StrictDom\n\t * is in the 'measure' phase, else it\n\t * will throw.\n\t *\n\t * @constructor\n\t * @extends Property\n\t */\n\tfunction Mutate() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tMutate.prototype = extend(Property, {\n\n\t  /**\n\t   * Return a wrapped descriptor.\n\t   *\n\t   * @param  {Object} descriptor\n\t   * @return {Object}\n\t   */\n\t  wrap: function(descriptor) {\n\t    debug('wrap mutate', this.name);\n\n\t    var clone = Object.assign({}, descriptor);\n\t    var value = descriptor.value;\n\t    var self = this;\n\n\t    if (typeof value == 'function') {\n\t      clone.value = function() {\n\t        self.test(self.strictdom, this, arguments);\n\t        return value.apply(this, arguments);\n\t      };\n\t    } else if (descriptor.set) {\n\t      clone.set = function() {\n\t        self.test(self.strictdom, this, arguments);\n\t        return descriptor.set.apply(this, arguments);\n\t      };\n\t    }\n\n\t    return clone;\n\t  },\n\n\t  /**\n\t   * Throws an Error if the element is attached\n\t   * and StrictDOM is not in the 'mutate' phase.\n\t   *\n\t   * If methods/properties are used without\n\t   * a context (eg. `getComputedStyle()` instead\n\t   * of `window.getComputedStyle()`) we infer\n\t   * a `window` context.\n\t   *\n\t   * @param  {StrictDom} strictdom\n\t   * @param  {Node} ctx\n\t   */\n\t  test: function(strictdom, ctx) {\n\t    if (isAttached(ctx || window) && strictdom.not('mutate')) {\n\t      throw error(3, this.name);\n\t    }\n\t  }\n\t});\n\n\t/**\n\t * A wrapper for 'accessor' (get/set) properties.\n\t *\n\t * An `Accessor` should be used to wrap\n\t * properties that can both measure and mutate\n\t * the DOM (eg. `element.scrollTop`).\n\t *\n\t * @constructor\n\t * @extends Property\n\t */\n\tfunction Accessor() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tAccessor.prototype = extend(Property, {\n\n\t  /**\n\t   * Return a wrapped descriptor.\n\t   *\n\t   * @param  {Object} descriptor\n\t   * @return {Object}\n\t   */\n\t  wrap: function(descriptor) {\n\t    debug('wrap accessor', this.name);\n\n\t    var clone = Object.assign({}, descriptor);\n\t    var get = descriptor.get;\n\t    var set = descriptor.set;\n\t    var self = this;\n\n\t    if (get) {\n\t      clone.get = function() {\n\t        self.testRead(self.strictdom, this, arguments);\n\t        return get.apply(this, arguments);\n\t      };\n\t    }\n\n\t    if (descriptor.set) {\n\t      clone.set = function() {\n\t        self.testWrite(self.strictdom, this, arguments);\n\t        return set.apply(this, arguments);\n\t      };\n\t    }\n\n\t    return clone;\n\t  },\n\n\t  testRead: Measure.prototype.test,\n\t  testWrite: Mutate.prototype.test\n\t});\n\n\t/**\n\t * A wrapper for 'value' properties.\n\t *\n\t * A `Value` should be used to wrap special\n\t * values that like `window.innerWidth`, which\n\t * in Chrome (not Gecko) are not normal 'getter'\n\t * functions, but magical flat getters.\n\t *\n\t * Value wrappers are a for very special cases.\n\t *\n\t * @constructor\n\t * @extends Property\n\t */\n\tfunction Value() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tValue.prototype = extend(Property, {\n\n\t  /**\n\t   * Calling `Object.getOwnDescriptor()` can\n\t   * trigger a reflow as it returns the `value`\n\t   * of the property. So here we just\n\t   * return an empty object instead.\n\t   *\n\t   * @return {Object}\n\t   * @private\n\t   */\n\t  getDescriptor: function() {\n\t    return {};\n\t  },\n\n\t  /**\n\t   * Value wrappers are disabled by simply\n\t   * deleting them from the instance,\n\t   * revealing the original descriptor.\n\t   *\n\t   * @private\n\t   */\n\t  disable: function() {\n\t    delete this.object[this.name];\n\t  },\n\n\t  /**\n\t   * Return a wrapped descriptor.\n\t   *\n\t   * `Value` properties are actually on the\n\t   * instance of objects. To wrap them we need\n\t   * to replace them with a getter which\n\t   * deletes itself on access, call into the v8\n\t   * interceptor, and then add themselves back.\n\t   *\n\t   * This won't be fast, but these are rarely\n\t   * accessed so it should be fine.\n\t   *\n\t   * @param  {Object} descriptor\n\t   * @return {Object}\n\t   */\n\t  wrap: function(descriptor) {\n\t    debug('wrap value');\n\t    var name = this.name;\n\t    var self = this;\n\n\t    descriptor.get = function() {\n\t      debug('get value', name);\n\t      self.test(self.strictdom, this, arguments);\n\t      self.disable();\n\t      var result = this[name];\n\t      self.enable();\n\t      return result;\n\t    };\n\n\t    return descriptor;\n\t  },\n\n\t  test: Measure.prototype.test\n\t});\n\n\tfunction Style() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tStyle.prototype = extend(Property, {\n\t  wrap: function(descriptor) {\n\t    debug('wrap style');\n\t    var strictdom = this.strictdom;\n\t    var clone = Object.assign({}, descriptor);\n\t    clone.get = function() { return new StrictStyle(this, strictdom); };\n\t    return clone;\n\t  }\n\t});\n\n\tfunction ClassList() {\n\t  Property.apply(this, arguments);\n\t}\n\n\tClassList.prototype = extend(Property, {\n\t  wrap: function(descriptor) {\n\t    debug('wrap style');\n\t    var strictdom = this.strictdom;\n\t    var clone = Object.assign({}, descriptor);\n\t    clone.get = function() { return new StrictClassList(this, strictdom); };\n\t    return clone;\n\t  }\n\t});\n\n\tfunction StrictStyle(el, strictdom) {\n\t  this.strictdom = strictdom;\n\t  this.el = el;\n\t}\n\n\tStrictStyle.prototype = {\n\t  _getter: getDescriptor(HTMLElement.prototype, 'style').get,\n\t  _get: function() {\n\t    return this._getter.call(this.el);\n\t  },\n\n\t  setProperty: function(key, value) {\n\t    var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t    if (illegal) throw error(1, 'style.' + key);\n\t    return this._get()[key] = value;\n\t  },\n\n\t  removeProperty: function(key) {\n\t    var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t    if (illegal) throw error(1, 'style.' + key);\n\t    return this._get().removeProperty(key);\n\t  }\n\t};\n\n\t// dynamically construct prototype\n\t// from real element.style\n\t(function() {\n\t  var styles = document.createElement('div').style;\n\t  var proto = {};\n\n\t  for (var key in styles) {\n\t    if (styles[key] === '') {\n\t      Object.defineProperty(StrictStyle.prototype, key, {\n\t        get: getter(key),\n\t        set: setter(key)\n\t      });\n\t    }\n\t  }\n\n\t  [\n\t    'item',\n\t    'getPropertyValue',\n\t    'getPropertyCSSValue',\n\t    'getPropertyPriority'\n\t  ].forEach(function(method) {\n\t    StrictStyle.prototype[method] = caller(method);\n\t  });\n\n\t  function getter(key) {\n\t    return function() {\n\t      return this._get()[key];\n\t    };\n\t  }\n\n\t  function setter(key) {\n\t    return function(value) {\n\t      var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t      if (illegal) throw error(1, 'style.' + key);\n\t      return this.setProperty(key, value);\n\t    };\n\t  }\n\n\t  function caller(key) {\n\t    return function() {\n\t      var style = this._get();\n\t      return style[key].apply(style, arguments);\n\t    };\n\t  }\n\n\t  return proto;\n\t})();\n\n\tfunction StrictClassList(el, strictdom) {\n\t  this.strictdom = strictdom;\n\t  this.el = el;\n\t}\n\n\tStrictClassList.prototype = {\n\t  _getter: getDescriptor(Element.prototype, 'classList').get,\n\t  _get: function() { return this._getter.call(this.el); },\n\n\t  add: function(className) {\n\t    var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t    if (illegal) throw error(1, 'class names');\n\t    this._get().add(className);\n\t  },\n\n\t  contains: function(className) {\n\t    return this._get().contains(className);\n\t  },\n\n\t  remove: function(className) {\n\t    var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t    if (illegal) throw error(1, 'class names');\n\t    this._get().remove(className);\n\t  },\n\n\t  toggle: function() {\n\t    var illegal = isAttached(this.el) && this.strictdom.not('mutate');\n\t    if (illegal) throw error(1, 'class names');\n\t    var classList = this._get();\n\t    return classList.toggle.apply(classList, arguments);\n\t  }\n\t};\n\n\t/**\n\t * Utils\n\t */\n\n\tfunction error(type) {\n\t  return new Error({\n\t    1: 'Can only set ' + arguments[1] + ' during \\'mutate\\' phase',\n\t    2: 'Can only get ' + arguments[1] + ' during \\'measure\\' phase',\n\t    3: 'Can only call `.' + arguments[1] + '()` during \\'mutate\\' phase',\n\t    4: 'Invalid phase: ' + arguments[1]\n\t  }[type]);\n\t}\n\n\tfunction getDescriptor(object, prop) {\n\t  return Object.getOwnPropertyDescriptor(object, prop);\n\t}\n\n\tfunction extend(parent, props) {\n\t  return Object.assign(Object.create(parent.prototype), props);\n\t}\n\n\tfunction isAttached(el) {\n\t  return el === window || document.contains(el);\n\t}\n\n\t/**\n\t * Exports\n\t */\n\n\t// Only ever allow one `StrictDom` per document\n\tvar exports = window['strictdom'] = (window['strictdom'] || new StrictDom(window)); // jshint ignore:line\n\n\t// CJS & AMD support\n\tif ((\"function\")[0] == 'f') !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { return exports; }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\telse if ((typeof module)[0] == 'o') module.exports = exports;\n\n\t})();\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\n\tmodule.exports = __WEBPACK_EXTERNAL_MODULE_2__;\n\n/***/ })\n/******/ ])\n});\n;"
  },
  {
    "path": "fastdom.d.ts",
    "content": "type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;\n\ndeclare class Fastdom {\n  clear<T extends () => void>(task: T): boolean;\n  extend<T extends object>(props: T): Omit<this, keyof T & keyof this> & T;\n  measure<T extends () => void>(task: T, context?: any): T;\n  mutate<T extends () => void>(task: T, context?: any): T;\n  catch: null | ((e: unknown) => any);\n}\n\ndeclare const fastdom: Fastdom\n\nexport default fastdom;\n"
  },
  {
    "path": "fastdom.js",
    "content": "!(function(win) {\n\n/**\n * FastDom\n *\n * Eliminates layout thrashing\n * by batching DOM read/write\n * interactions.\n *\n * @author Wilson Page <wilsonpage@me.com>\n * @author Kornel Lesinski <kornel.lesinski@ft.com>\n */\n\n'use strict';\n\n/**\n * Mini logger\n *\n * @return {Function}\n */\nvar debug = 0 ? console.log.bind(console, '[fastdom]') : function() {};\n\n/**\n * Normalized rAF\n *\n * @type {Function}\n */\nvar raf = win.requestAnimationFrame\n  || win.webkitRequestAnimationFrame\n  || win.mozRequestAnimationFrame\n  || win.msRequestAnimationFrame\n  || function(cb) { return setTimeout(cb, 16); };\n\n/**\n * Initialize a `FastDom`.\n *\n * @constructor\n */\nfunction FastDom() {\n  var self = this;\n  self.reads = [];\n  self.writes = [];\n  self.raf = raf.bind(win); // test hook\n  debug('initialized', self);\n}\n\nFastDom.prototype = {\n  constructor: FastDom,\n\n  /**\n   * We run this inside a try catch\n   * so that if any jobs error, we\n   * are able to recover and continue\n   * to flush the batch until it's empty.\n   *\n   * @param {Array} tasks\n   */\n  runTasks: function(tasks) {\n    debug('run tasks');\n    var task; while (task = tasks.shift()) task();\n  },\n\n  /**\n   * Adds a job to the read batch and\n   * schedules a new frame if need be.\n   *\n   * @param  {Function} fn\n   * @param  {Object} ctx the context to be bound to `fn` (optional).\n   * @public\n   */\n  measure: function(fn, ctx) {\n    debug('measure');\n    var task = !ctx ? fn : fn.bind(ctx);\n    this.reads.push(task);\n    scheduleFlush(this);\n    return task;\n  },\n\n  /**\n   * Adds a job to the\n   * write batch and schedules\n   * a new frame if need be.\n   *\n   * @param  {Function} fn\n   * @param  {Object} ctx the context to be bound to `fn` (optional).\n   * @public\n   */\n  mutate: function(fn, ctx) {\n    debug('mutate');\n    var task = !ctx ? fn : fn.bind(ctx);\n    this.writes.push(task);\n    scheduleFlush(this);\n    return task;\n  },\n\n  /**\n   * Clears a scheduled 'read' or 'write' task.\n   *\n   * @param {Object} task\n   * @return {Boolean} success\n   * @public\n   */\n  clear: function(task) {\n    debug('clear', task);\n    return remove(this.reads, task) || remove(this.writes, task);\n  },\n\n  /**\n   * Extend this FastDom with some\n   * custom functionality.\n   *\n   * Because fastdom must *always* be a\n   * singleton, we're actually extending\n   * the fastdom instance. This means tasks\n   * scheduled by an extension still enter\n   * fastdom's global task queue.\n   *\n   * The 'super' instance can be accessed\n   * from `this.fastdom`.\n   *\n   * @example\n   *\n   * var myFastdom = fastdom.extend({\n   *   initialize: function() {\n   *     // runs on creation\n   *   },\n   *\n   *   // override a method\n   *   measure: function(fn) {\n   *     // do extra stuff ...\n   *\n   *     // then call the original\n   *     return this.fastdom.measure(fn);\n   *   },\n   *\n   *   ...\n   * });\n   *\n   * @param  {Object} props  properties to mixin\n   * @return {FastDom}\n   */\n  extend: function(props) {\n    debug('extend', props);\n    if (typeof props != 'object') throw new Error('expected object');\n\n    var child = Object.create(this);\n    mixin(child, props);\n    child.fastdom = this;\n\n    // run optional creation hook\n    if (child.initialize) child.initialize();\n\n    return child;\n  },\n\n  // override this with a function\n  // to prevent Errors in console\n  // when tasks throw\n  catch: null\n};\n\n/**\n * Schedules a new read/write\n * batch if one isn't pending.\n *\n * @private\n */\nfunction scheduleFlush(fastdom) {\n  if (!fastdom.scheduled) {\n    fastdom.scheduled = true;\n    fastdom.raf(flush.bind(null, fastdom));\n    debug('flush scheduled');\n  }\n}\n\n/**\n * Runs queued `read` and `write` tasks.\n *\n * Errors are caught and thrown by default.\n * If a `.catch` function has been defined\n * it is called instead.\n *\n * @private\n */\nfunction flush(fastdom) {\n  debug('flush');\n\n  var writes = fastdom.writes;\n  var reads = fastdom.reads;\n  var error;\n\n  try {\n    debug('flushing reads', reads.length);\n    fastdom.runTasks(reads);\n    debug('flushing writes', writes.length);\n    fastdom.runTasks(writes);\n  } catch (e) { error = e; }\n\n  fastdom.scheduled = false;\n\n  // If the batch errored we may still have tasks queued\n  if (reads.length || writes.length) scheduleFlush(fastdom);\n\n  if (error) {\n    debug('task errored', error.message);\n    if (fastdom.catch) fastdom.catch(error);\n    else throw error;\n  }\n}\n\n/**\n * Remove an item from an Array.\n *\n * @param  {Array} array\n * @param  {*} item\n * @return {Boolean}\n */\nfunction remove(array, item) {\n  var index = array.indexOf(item);\n  return !!~index && !!array.splice(index, 1);\n}\n\n/**\n * Mixin own properties of source\n * object into the target.\n *\n * @param  {Object} target\n * @param  {Object} source\n */\nfunction mixin(target, source) {\n  for (var key in source) {\n    if (source.hasOwnProperty(key)) target[key] = source[key];\n  }\n}\n\n// There should never be more than\n// one instance of `FastDom` in an app\nvar exports = win.fastdom = (win.fastdom || new FastDom()); // jshint ignore:line\n\n// Expose to CJS & AMD\nif ((typeof define) == 'function') define(function() { return exports; });\nelse if ((typeof module) == 'object') module.exports = exports;\n\n})( typeof window !== 'undefined' ? window : typeof this != 'undefined' ? this : globalThis);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"fastdom\",\n  \"description\": \"Eliminates layout thrashing by batching DOM read/write operations\",\n  \"version\": \"1.0.11\",\n  \"main\": \"fastdom.js\",\n  \"types\": \"fastdom.d.ts\",\n  \"scripts\": {\n    \"lint\": \"jshint src/*\",\n    \"unit\": \"karma start test/karma.conf.js --single-run\",\n    \"test\": \"npm run -s unit && npm run -s lint\",\n    \"test-dev\": \"karma start test/karma.conf.js --browsers Firefox\",\n    \"coveralls\": \"cat test/coverage/lcov.info | coveralls\",\n    \"compress\": \"uglifyjs fastdom.js --compress='drop_console,sequences,dead_code,booleans,conditionals,unused,if_return,join_vars,pure_funcs=\\\"debug\\\"' --mangle --reserved='require,define,module,exports' > fastdom.min.js\",\n    \"build\": \"webpack && npm run -s compress\",\n    \"watch\": \"webpack -w\"\n  },\n  \"homepage\": \"https://github.com/wilsonpage/fastdom\",\n  \"author\": {\n    \"name\": \"Wilson Page\",\n    \"email\": \"wilsonpage@me.com\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/wilsonpage/fastdom.git\"\n  },\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"chai\": \"^3.4.1\",\n    \"coveralls\": \"^2.11.6\",\n    \"jshint\": \"^2.8.0\",\n    \"karma\": \"^0.13.15\",\n    \"karma-chai-sinon\": \"^0.1.5\",\n    \"karma-chrome-launcher\": \"^0.2.2\",\n    \"karma-coverage\": \"^0.5.3\",\n    \"karma-firefox-launcher\": \"^0.1.3\",\n    \"karma-mocha\": \"^0.2.1\",\n    \"karma-mocha-reporter\": \"^1.1.3\",\n    \"mocha\": \"^2.3.4\",\n    \"sinon\": \"^1.17.2\",\n    \"sinon-chai\": \"^2.8.0\",\n    \"uglify-js\": \"^2.4.23\",\n    \"webpack\": \"^1.12.9\"\n  },\n  \"dependencies\": {\n    \"strictdom\": \"^1.0.1\"\n  }\n}\n"
  },
  {
    "path": "src/fastdom-strict.js",
    "content": "'use strict';\n\nvar strictdom = require('strictdom');\nvar fastdom = require('../fastdom');\n\n/**\n * Mini logger\n *\n * @return {Function}\n */\nvar debug = 0 ? console.log.bind(console, '[fastdom-strict]') : function() {};\n\n/**\n * Enabled state\n *\n * @type {Boolean}\n */\nvar enabled = false;\n\nwindow.fastdom = module.exports = fastdom.extend({\n  measure: function(fn, ctx) {\n    debug('measure');\n    var task = !ctx ? fn : fn.bind(ctx);\n    return this.fastdom.measure(function() {\n      if (!enabled) return task();\n      return strictdom.phase('measure', task);\n    }, ctx);\n  },\n\n  mutate: function(fn, ctx) {\n    debug('mutate');\n    var task = !ctx ? fn : fn.bind(ctx);\n    return this.fastdom.mutate(function() {\n      if (!enabled) return task();\n      return strictdom.phase('mutate', task);\n    }, ctx);\n  },\n\n  strict: function(value) {\n    if (value) {\n      enabled = true;\n      strictdom.enable();\n    } else {\n      enabled = false;\n      strictdom.disable();\n    }\n  }\n});\n\n// turn on strict-mode\nwindow.fastdom.strict(true);\n"
  },
  {
    "path": "test/fastdom-promised-test.js",
    "content": "/*global suite, setup, test, assert, sinon, fastdomPromised*/\n/*jshint maxlen:false*/\n\nsuite('fastdom-promised', function() {\n  var fastdom;\n\n  setup(function() {\n    fastdom = window.fastdom.extend(fastdomPromised);\n  });\n\n  test('it returns a Promise that resolves after the task is run', function(done) {\n    var spy = sinon.spy();\n\n    fastdom.measure(spy)\n      .then(function() {\n        sinon.assert.calledOnce(spy);\n        done();\n      });\n  });\n\n  test('promises can be returned from tasks', function() {\n    var spy1 = sinon.spy();\n    var spy2 = sinon.spy();\n\n    return fastdom.measure(function() {\n        spy1();\n        return fastdom.mutate(spy2);\n      })\n\n      .then(function() {\n        sinon.assert.calledOnce(spy1);\n        sinon.assert.calledOnce(spy2);\n        assert.isTrue(spy1.calledBefore(spy2));\n      });\n  });\n\n  test('calling `fastdom.clear(promise)` works', function(done) {\n    var spy = sinon.spy();\n    var task = fastdom.measure(spy);\n\n    fastdom.clear(task);\n\n    requestAnimationFrame(function() {\n      sinon.assert.notCalled(spy);\n      done();\n    });\n  });\n\n  test('it calls callback with given context', function() {\n    var spy = sinon.spy();\n    var ctx = {};\n\n    return fastdom.measure(spy, ctx)\n      .then(function() {\n        sinon.assert.calledOn(spy, ctx);\n      });\n  });\n});\n"
  },
  {
    "path": "test/fastdom-sandbox-test.js",
    "content": "/*global suite, setup, test, assert, sinon, fastdomSandbox, fastdomPromised*/\n/* jshint maxlen:false */\n\nsuite('fastdom-sandbox', function() {\n  var raf = window.requestAnimationFrame;\n  var fastdom;\n\n  setup(function() {\n    fastdom = new window.fastdom.constructor();\n    fastdom = fastdom.extend(window.fastdomSandbox);\n  });\n\n  test('It works as normal', function(done) {\n    var sandbox = fastdom.sandbox();\n\n    sandbox.measure(function() {\n      sandbox.mutate(function() {\n        done();\n      });\n    });\n  });\n\n  test('Its possible to clear all sandbox jobs', function(done) {\n    var sandbox = fastdom.sandbox();\n    var spy = sinon.spy();\n\n    sandbox.measure(spy);\n    sandbox.mutate(spy);\n\n    fastdom.measure(function() {\n      fastdom.mutate(function() {\n        assert.isTrue(spy.notCalled);\n        done();\n      });\n    });\n\n    sandbox.clear();\n  });\n\n  test('It clears individual tasks', function(done) {\n    var sandbox = fastdom.sandbox();\n    var spy = sinon.spy();\n\n    var task = sandbox.measure(spy);\n    sandbox.clear(task);\n    sandbox.measure(function() {\n      assert.isTrue(spy.notCalled);\n      done();\n    });\n  });\n\n  test('it works with fastdom-promised', function(done) {\n    var myFastdom = fastdom\n      .extend(fastdomPromised)\n      .extend(fastdomSandbox);\n\n    var sandbox = myFastdom.sandbox();\n    var spy1 = sinon.spy();\n    var spy2 = sinon.spy();\n\n    sandbox.measure(spy1)\n      .then(function() {\n        return sandbox.mutate(spy2);\n      })\n\n      .then(function() {\n        sinon.assert.calledOnce(spy1);\n        sinon.assert.calledOnce(spy2);\n\n        spy1.reset();\n        spy2.reset();\n\n        sandbox.measure(spy1);\n        sandbox.measure(spy2);\n        sandbox.clear();\n\n        raf(function() {\n          console.log(3);\n          sinon.assert.notCalled(spy1);\n          sinon.assert.notCalled(spy2);\n          done();\n        });\n      })\n\n      .catch(done);\n  });\n});\n"
  },
  {
    "path": "test/fastdom-strict-test.js",
    "content": "/*global suite, setup, suiteSetup, suiteTeardown, teardown, test, assert, fastdomPromised*/\n/*jshint maxlen:false*/\n\nsuite('fastdom-strict', function() {\n  var raf = window.requestAnimationFrame;\n  var fastdom;\n  var el;\n\n  suiteSetup(function(done) {\n    var script = document.createElement('script');\n    script.src = '/base/fastdom-strict.js';\n    document.head.appendChild(script);\n    script.onload = function() {\n      fastdom = window.fastdom.extend(fastdomPromised);\n      done();\n    };\n  });\n\n  suiteTeardown(function() {\n    fastdom.strict(false);\n  });\n\n  setup(function() {\n    return fastdom.mutate(function() {\n      el = document.createElement('div');\n      el.style.height = '100px';\n      el.style.width = '100px';\n      document.body.appendChild(el);\n    });\n  });\n\n  teardown(function() {\n    return fastdom.mutate(function() {\n      el.remove();\n    });\n  });\n\n  test('measuring throws outside of fastdom', function() {\n    assert.throws(function() {\n      return el.clientWidth;\n    });\n  });\n\n  test('measuring does not throws inside `fastdom.measure()`', function() {\n    return fastdom.measure(function() {\n      return el.clientWidth;\n    });\n  });\n\n  test('mutating throws outside of fastdom', function() {\n    assert.throws(function() {\n      el.innerHTML = 'foo';\n    });\n  });\n\n  test('mutating does not throws inside `fastdom.mutate()`', function() {\n    return fastdom.mutate(function() {\n      el.innerHTML = 'foo';\n    });\n  });\n\n  test('it can be disabled and enabled', function(done) {\n    fastdom.strict(false);\n\n    assert.doesNotThrow(function() {\n      return el.clientWidth;\n    });\n\n    fastdom.strict(true);\n\n    assert.throws(function() {\n      return el.clientWidth;\n    });\n\n    fastdom.measure(function() {\n      el.clientWidth;\n    }).then(done);\n  });\n\n  test('callback is called with correct context when measuring and mutating', function(done) {\n    var ctx1 = { foo: 'bar' };\n    var ctx2 = { bar: 'baz' };\n\n    var spy1 = sinon.spy();\n    var spy2 = sinon.spy();\n\n    fastdom.measure(spy1, ctx1);\n    fastdom.mutate(spy2, ctx2);\n\n    raf(function() {\n      assert(spy1.calledOn(ctx1));\n      assert(spy2.calledOn(ctx2));\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "test/fastdom-test.js",
    "content": "/*jshint maxlen:false*/\n/*global suite, setup, teardown, test, assert, sinon, fastdomSandbox, fastdomPromised*/\n\nsuite('fastdom', function() {\n  var raf = window.requestAnimationFrame;\n  var fastdom;\n\n  setup(function() {\n    fastdom = new window.fastdom.constructor();\n  });\n\n  test('it runs reads before writes', function(done) {\n    var read = sinon.spy(function() {\n      assert(!write.called);\n    });\n\n    var write = sinon.spy(function() {\n      assert(read.called);\n      done();\n    });\n\n    fastdom.measure(read);\n    fastdom.mutate(write);\n  });\n\n  test('it calls all reads together, followed by all writes', function(done) {\n    var read1 = sinon.spy();\n    var read2 = sinon.spy();\n    var write1 = sinon.spy();\n    var write2 = sinon.spy();\n\n    // Assign unsorted\n    fastdom.measure(read1);\n    fastdom.mutate(write1);\n    fastdom.measure(read2);\n    fastdom.mutate(write2);\n\n    // After the queue has been emptied\n    // check the callbacks were called\n    // in the correct order.\n    raf(function() {\n      assert(read1.calledBefore(read2));\n      assert(read2.calledBefore(write1));\n      assert(write1.calledBefore(write2));\n      done();\n    });\n  });\n\n  test('it calls a read in the same frame if scheduled inside a read callback', function(done) {\n    var cb = sinon.spy();\n\n    fastdom.measure(function() {\n\n      // Schedule a callback for *next* frame\n      raf(cb);\n\n      // Schedule a read callback\n      // that should be run in the\n      // current frame checking that\n      // the RAF callback has not\n      // yet been fired.\n      fastdom.measure(function() {\n        assert(!cb.called);\n        done();\n      }, this);\n    }, this);\n  });\n\n  test('it calls a write in the same frame if scheduled inside a read callback', function(done) {\n    var cb = sinon.spy();\n\n    fastdom.measure(function() {\n\n      // Schedule a callback for *next* frame\n      raf(cb);\n\n      // Schedule a read callback\n      // that should be run in the\n      // current frame checking that\n      // the RAF callback has not\n      // yet been fired.\n      fastdom.mutate(function() {\n        assert(!cb.called);\n        done();\n      }, this);\n    }, this);\n  });\n\n  test('it calls a read in the *next* frame if scheduled inside a write callback', function(done) {\n    var cb = sinon.spy();\n\n    fastdom.mutate(function() {\n\n      // Schedule a callback for *next* frame\n      raf(cb);\n\n      // Schedule a read that should be\n      // called in the next frame, meaning\n      // the test callback should have already\n      // been called.\n      fastdom.measure(function() {\n        assert(cb.called);\n        done();\n      }, this);\n    }, this);\n  });\n\n  test('it does not request a new frame when a write is requested inside a nested read', function(done) {\n    var callback = sinon.spy();\n\n    fastdom.mutate(function() {\n      fastdom.measure(function() {\n\n        // Schedule a callback for *next* frame\n        raf(callback);\n\n        // Schedule a read callback\n        // that should be run in the\n        // current frame checking that\n        // the RAF callback has not\n        // yet been fired.\n        fastdom.mutate(function() {\n          assert(!callback.called);\n          done();\n        });\n      });\n    });\n  });\n\n  test('it schedules a new frame when a read is requested in a nested write', function(done) {\n    fastdom.raf = sinon.spy(fastdom, 'raf');\n\n    fastdom.measure(function() {\n      fastdom.mutate(function() {\n        fastdom.measure(function(){\n\n          // Should have scheduled a new frame\n          assert(fastdom.raf.calledTwice);\n          done();\n        });\n      });\n    });\n  });\n\n  test('it runs nested reads in the same frame', function(done) {\n    sinon.spy(fastdom, 'raf');\n\n    fastdom.measure(function() {\n      fastdom.measure(function() {\n        fastdom.measure(function() {\n          fastdom.measure(function() {\n\n            // Should not have scheduled a new frame\n            sinon.assert.calledOnce(fastdom.raf);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('it runs nested writes in the same frame', function(done) {\n    fastdom.raf = sinon.spy(fastdom, 'raf');\n\n    fastdom.mutate(function() {\n      fastdom.mutate(function() {\n        fastdom.mutate(function() {\n          fastdom.mutate(function() {\n\n            // Should not have scheduled a new frame\n            sinon.assert.calledOnce(fastdom.raf);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('it calls a \"read\" callback with the given context', function(done) {\n    fastdom.measure(function() {\n      assert.equal(this.foo, 'bar');\n      done();\n    }, { foo: 'bar' });\n  });\n\n  test('it calls a \"write\" callback with the given context', function(done) {\n    fastdom.mutate(function() {\n      assert.equal(this.foo, 'bar');\n      done();\n    }, { foo: 'bar' });\n  });\n\n  test('it has an empty job hash when batch complete', function(done) {\n    var ran = 0;\n\n    fastdom.measure(function(){ ran += 1; });\n    fastdom.measure(function(){ ran += 2; });\n    fastdom.mutate(function(){ ran += 4; });\n    fastdom.mutate(function(){ ran += 8; });\n\n    // Check there are four jobs stored\n    assert.equal(ran, 0);\n\n    raf(function() {\n      assert.equal(ran, 15);\n      done();\n    });\n  });\n\n  test('it maintains correct context if single method is registered twice', function(done) {\n    var ctx1 = { foo: 'bar' };\n    var ctx2 = { bar: 'baz' };\n\n    function shared() {}\n\n    var spy1 = sinon.spy(shared);\n    var spy2 = sinon.spy(shared);\n\n    fastdom.measure(spy1, ctx1);\n    fastdom.measure(spy2, ctx2);\n\n    raf(function() {\n      assert(spy1.calledOn(ctx1));\n      assert(spy2.calledOn(ctx2));\n      done();\n    });\n  });\n\n  test('it runs .catch() handler on error if one has been registered', function(done) {\n    fastdom.catch = sinon.spy();\n\n    fastdom.measure(function() { throw 'err1'; });\n    fastdom.mutate(function() { throw 'err2'; });\n\n    raf(function() {\n      raf(function() {\n        assert(fastdom.catch.calledTwice, 'twice');\n        assert(fastdom.catch.getCall(0).calledWith('err1'), 'bla');\n        assert(fastdom.catch.getCall(1).calledWith('err2'), 'bl2');\n        done();\n      });\n    });\n  });\n\n  suite('exceptions', function() {\n\n    // temporarily disable mocha error detection\n    setup(function() {\n      this.onerror = window.onerror;\n      window.onerror = null;\n    });\n\n    // re-enable mocha error detection\n    teardown(function() {\n      window.onerror = this.onerror;\n    });\n\n    test('it flushes remaining tasks in next frame if prior task throws', function(done) {\n      var spy = sinon.spy();\n\n      fastdom.measure(function() { throw new Error('error'); });\n      fastdom.measure(spy);\n\n      raf(function() {\n        sinon.assert.notCalled(spy);\n        raf(function() {\n          sinon.assert.calledOnce(spy);\n          done();\n        });\n      });\n    });\n  });\n\n  test('it stops rAF loop once frame queue is empty', function(done) {\n    var callback = sinon.spy();\n\n    sinon.spy(fastdom, 'raf');\n    fastdom.measure(callback);\n\n    raf(function() {\n      assert(callback.called);\n      assert(fastdom.raf.calledOnce);\n      done();\n    });\n  });\n\n  suite('clear', function() {\n    test('it does not run \"read\" job if cleared (sync)', function(done) {\n      var read = sinon.spy();\n      var id = fastdom.measure(read);\n      fastdom.clear(id);\n\n      raf(function() {\n        raf(function() {\n        assert(!read.called);\n        done();\n      });\n      });\n    });\n\n    test('it fails silently if job not found in queue', function(done) {\n      var read = sinon.spy();\n      var read2 = sinon.spy();\n\n      var id = fastdom.measure(read);\n      fastdom.clear(id);\n\n      raf(function() {\n        assert(!read2.called);\n        done();\n      });\n    });\n\n    test('it does not run \"write\" job if cleared (async)', function(done) {\n      var read = sinon.spy();\n      var write = sinon.spy();\n\n      var id = fastdom.mutate(write);\n      fastdom.measure(function() {\n        fastdom.clear(id);\n\n        raf(function() {\n          assert(!read.called);\n          done();\n        });\n      });\n    });\n\n    test('it does not run \"write\" job if cleared', function(done) {\n      var write = sinon.spy();\n      var id = fastdom.mutate(write);\n\n      fastdom.clear(id);\n\n      raf(function() {\n        assert(!write.called);\n        done();\n      });\n    });\n\n    test('it removes reference to the job if cleared', function(done) {\n      var write = sinon.spy();\n      var id = fastdom.mutate(write);\n\n      fastdom.clear(id);\n\n      raf(function() {\n        raf(function() {\n          raf(function() {\n            assert(!write.called);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  suite('FastDom#extend()', function() {\n    test('it has the properties of given object', function() {\n      var fastdom2 = fastdom.extend({ prop: 'foo' });\n      assert.equal(fastdom2.prop, 'foo');\n    });\n\n    test('it can extend an extension', function() {\n      var fastdom2 = fastdom.extend({ prop: 'foo' });\n      var fastdom3 = fastdom2.extend({ prop: 'bar' });\n\n      assert.equal(fastdom2.prop, 'foo');\n      assert.equal(fastdom3.prop, 'bar');\n\n      assert.equal(fastdom2.fastdom, fastdom);\n      assert.equal(fastdom3.fastdom, fastdom2);\n    });\n\n    test('it throws if argument is not object', function() {\n      assert.throws(function() {\n        fastdom.extend();\n      });\n\n      assert.throws(function() {\n        fastdom.extend('oopsie');\n      });\n\n      assert.throws(function() {\n        fastdom.extend(999);\n      });\n    });\n\n    test('it only mixes in own properties', function() {\n      var proto = { foo: 'foo' };\n      var extension = Object.create(proto);\n      var extended = fastdom.extend(extension);\n\n      assert.isUndefined(extended.foo);\n    });\n  });\n});\n"
  },
  {
    "path": "test/karma.conf.js",
    "content": "'use strict';\n\nmodule.exports = function(config) {\n  config.set({\n    basePath: '..',\n\n    browsers: [\n      'chrome',\n      'Firefox'\n    ],\n\n    frameworks: [\n      'mocha',\n      'chai-sinon'\n    ],\n\n    reporters: [\n      'mocha',\n      'coverage'\n    ],\n\n    coverageReporter: {\n       type : 'lcov',\n       dir : 'test/',\n       subdir: 'coverage'\n     },\n\n    preprocessors: {\n      'fastdom.js': ['coverage'],\n      'extensions/*.js': ['coverage']\n    },\n\n    client: {\n      captureConsole: true,\n      mocha: { ui: 'tdd' }\n    },\n\n    customLaunchers: {\n      chrome: {\n        base: 'Chrome',\n        flags: ['--no-sandbox']\n      }\n    },\n\n    files: [\n      'fastdom.js',\n      'extensions/fastdom-promised.js',\n      'extensions/fastdom-sandbox.js',\n      'test/fastdom-sandbox-test.js',\n      'test/fastdom-promised-test.js',\n      'test/fastdom-strict-test.js',\n      'test/fastdom-test.js',\n      { pattern: 'fastdom-strict.js', included: false }\n    ]\n  });\n};\n"
  },
  {
    "path": "webpack.config.js",
    "content": "module.exports = [\n  {\n    entry: './src/fastdom-strict.js',\n    output: {\n      filename: 'fastdom-strict.js',\n      library: 'fastdom',\n      libraryTarget: 'umd'\n    },\n\n    externals: {\n      '../fastdom': 'fastdom'\n    }\n  }\n];\n"
  }
]