[
  {
    "path": ".gitattributes",
    "content": "# so documentation files won't cause project language to be shown as HTML\nsite/* linguist-documentation\n"
  },
  {
    "path": ".gitignore",
    "content": "/.grunt\n/node_modules\n/site/bundle.js\n/site/spin.css\n/site/spin.js\n/site/spin.umd.js\n/spin.js\n/spin.d.ts\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [4.1.2] - 2024-07-19\n### Changed\n- Removed some dead code left over from version 3.x.\n\n## [4.1.1] - 2021-09-01\n### Changed\n- Set package type to `module` to better support native ES module imports.\n- Improved website design.\n\n## [4.1.0] - 2019-10-22\n### Added\n- `spinner-line-shrink` animation preset.\n\n## [4.0.0] - 2018-05-06\n### Changed\n- Switched from `requestAnimationFrame` back to CSS keyframe animations\nfor better performance.\n- In order to preserve compatibility with the\n`style-src 'self';` Content Security Policy, animations are now defined\nvia an external CSS file rather than inserted dynamically.\n\nAdd the following to your page to use one of the preset animations:\n\n```html\n<link rel=\"stylesheet\" href=\"node_modules/spin.js/spin.css\"/>\n```\n\nYou can also define custom opacity animations in your own CSS file and\nselect them via the `animation` option.\n\n### Fixed\n- A transparent shadow is now set by default to resolve aliased lines in\ncertain browsers (issue [#355]).\n\n### Removed\n- `opacity` and `trail` options (define a custom opacity animation instead).\n- Support for Internet Explorer 9 (it doesn't support keyframe animations).\n- `fps` option (only used for IE 9).\n\n## [3.1.0] - 2017-11-26\n### Added\n- Support for custom box-shadows with corrected positioning (issue [#35]).\n- `fadeColor` option to customize the color that lines fade to (issue [#30]).\n\n## [3.0.0] - 2017-11-09\n### Added\n- Support for Content Security Policy `style-src 'self';` option\n(issue [#115] and issue [#229]).\n- [CONTRIBUTING.md](CONTRIBUTING.md) file.\n\n### Changed\n- Rewritten in TypeScript.\n- Replaced dynamic CSS keyframe animations with `requestAnimationFrame`.\n- Unified animation logic in all browsers.\n- Moved internal functions out of Spinner instance.\n- Website now uses native range inputs rather than a polyfill, and doesn't\ndepend on jQuery.\n- Distributed as a standard ES6 module (closes [#341]).\n\n### Fixed\n- Janky animation appearance in Microsoft Edge (issue [#342]).\n- Missing line with trail set to 100 in Internet Explorer (issue [#327]).\n- Spinner is not defined error in Angular (issue [#340]).\n\n### Removed\n- Useless `hwaccel` option.\n- IE 6-8 support and VML fallback since it isn't needed for IE 9+.\n- Minified files from bundle.\n- jQuery plugin (closes [#325]).\n- Bower/composer/component/spm support. Install from npm instead\n(recommended), or save spin.js file in your repo.\n\n\nNote: version 3.0 does not change the public Spinner API, so if you are\nalready using a module bundler such as Webpack or Rollup, upgrading should\nbe as easy as adding the following ES6 module import:\n\n```javascript\nimport {Spinner} from 'spin.js';\n```\n\n## [2.3.2] - 2015-07-24\n### Fixed\n- Updated UMD header to protect against HTMLElement global pollution\n(PR [#300]).\n\n## [2.3.1] - 2015-06-15\n### Changed\n- There were multiple tagging issues that produced 2.1.3, 2.2.0, and 2.3.0.\nIn the spirit of SemVer, this release is now 2.3.1.\n- The minified spin.min.js is now distributed in the repo, making Bower\nusage easier (issue [#250]).\n\n### Fixed\n- Incorrect syntax in the example at the top of spin.js (PR [#294]).\n\n### Removed\n* Moot `version` property from Bower manifest (PR [#295]).\n\n## [2.1.2] - 2015-05-28\n### Changed\n- Version 2.1.1 had a packaging error, so this release is now 2.1.2.\n- Standard CSS attributes are now preferred over vendor ones if supported.\n- Unified internal coding style across all files.\n- Website now uses the latest version of jQuery from its 1.x branch.\n- Updated documentation to note that the container element must use\nrelative positioning (issue [#292]).\n\n### Added\n- spm support (PR [#232]).\n\n### Fixed\n- All broken examples\n- Bug on demo page where the direction setting wasn't reflected in the\noption object.\n\n## [2.1.0] - 2015-04-16\n### Added\n- `scale` option for resizing the spinner (PR [#287]).\n- Support for importing on server without DOM (PR [#283]).\n\n## [2.0.2] - 2015-01-02\n### Fixed\n- Use correct `require` call in jQuery plugin\n\n### Removed\n- Cleaned up unused code\n\n## [2.0.1] - 2014-04-24\n### Fixed\n- Position offsets are now applied when instantiating spinner without\na target (issue [#218]).\n\n## [2.0.0] - 2014-03-13\n### Changed\n- Spinner is now absolutely positioned at `top: 50%, left: 50%` by default.\n- `top` and `left` options now require CSS units. For example, `top: 100`\nmust instead be written as `top: '100px'`.\n- Spinner must now always be invoked as constructor.\n\n## [1.3.3] - 2013-12-24\n### Changed\n - Created master branch and Grunt-based build process (issue [#189]).\n\n## [1.3.2] - 2013-08-26\n### Fixed\n- SyntaxError in Chrome Canary (issue [#168]).\n\n## [1.3.1] - 2013-08-19\n### Added\n- Support for multi-colored spinners (PR [#167]).\n\n## [1.3.0] - 2013-04-02\n### Added\n- `direction` option to control the spinning direction (PR [#126]).\n- jQuery plugin\n\n### Changed\n- Implemented UMD pattern to support AMD and CommonJS module loaders\n- Use strict mode\n\n## [1.2.8] - 2013-02-07\n### Fixed\n- 'Spinner' is undefined error in Internet Explorer 7 and 8 (issue [#78]).\n\n## [1.2.7] - 2012-10-02\n### Added\n- `position` option to control the corresponding CSS property (issue [#98]).\n- Trailing semicolon to support concatenation tools that don't know about\nASI (issue [#96] and issue [#99]).\n\n## [1.2.6] - 2012-08-30\n### Added\n- `corners` option to control the border-radius (issue [#93]).\n\n### Fixed\n- Scroll bar appearing in wide target elements (issue [#74]).\n- Invalid Argument error in Internet Explorer (issue [#77]).\n- Broken spinner in Opera 12 (issue [#87]).\n- Unexpected positioning when specifying `top` and `left` options as a\nstring (issue [#81] and issue [#90]).\n\n## [1.2.5] - 2012-03-22\n### Added\n- `rotate` option (issue [#60]).\n\n### Fixed\n- Bug that prevented the VML from being displayed when Modernizr's\nhtml5shiv was used (issue [#58]).\n- The `constructor` property is now preserved (issue [#61]).\n\n## [1.2.4] - 2012-02-28\n### Added\n- New config options: `top`, `left`, `zIndex`, and `className`.\n\n## [1.2.3] - 2012-01-30\n### Changed\n- Disabled hardware acceleration by default to prevent disappearing\nobjects and flashing colors in Chrome and Safari (issue [#41] and\nissue [#47]).\n\n## [1.2.2] - 2011-11-08\n### Fixed\n- Cross-domain issue with the dynamically created stylesheet (issue [#36]).\n\n## [1.2.1] - 2011-10-05\n### Fixed\n- Error when loading spinner in Internet Explorer 9 (issue [#31]).\n\n## [1.2.0] - 2011-09-16\n### Changed\n- Calling `spin()` now invokes `stop()` first (issue [#28]).\n- The `new` operator is now optional (issue [#14]).\n- Improved accessibility by adding `role=\"progressbar\"`.\n\n### Fixed\n- Implemented workaround for negative margin bug in Internet Explorer\n(issue [#27]).\n\n## [1.1.0] - 2011-09-06\n### Changed\n- Optimized the code for gzip compression. While the minified version\ngot slightly larger, the zipped version now only weighs 1.7K.\n\n### Fixed\n- Animation occasionally got out of sync in mobile Safari and Android's\nbuilt-in WebKit (issue [#12]).\n- Spinner was misplaced when the target element had a non-zero padding\n(issue [#23]).\n\n## [1.0.0] - 2011-08-16\n- Initial release\n\n[4.1.2]: https://github.com/fgnass/spin.js/compare/4.1.1...4.1.2\n[4.1.1]: https://github.com/fgnass/spin.js/compare/4.1.0...4.1.1\n[4.1.0]: https://github.com/fgnass/spin.js/compare/4.0.0...4.1.0\n[4.0.0]: https://github.com/fgnass/spin.js/compare/3.1.0...4.0.0\n[3.1.0]: https://github.com/fgnass/spin.js/compare/3.0.0...3.1.0\n[3.0.0]: https://github.com/fgnass/spin.js/compare/2.3.2...3.0.0\n[2.3.2]: https://github.com/fgnass/spin.js/compare/2.3.1...2.3.2\n[2.3.1]: https://github.com/fgnass/spin.js/compare/2.1.2...2.3.1\n[2.1.2]: https://github.com/fgnass/spin.js/compare/2.1.0...2.1.2\n[2.1.0]: https://github.com/fgnass/spin.js/compare/2.0.2...2.1.0\n[2.0.2]: https://github.com/fgnass/spin.js/compare/2.0.1...2.0.2\n[2.0.1]: https://github.com/fgnass/spin.js/compare/2.0.0...2.0.1\n[2.0.0]: https://github.com/fgnass/spin.js/compare/1.3.3...2.0.0\n[1.3.3]: https://github.com/fgnass/spin.js/compare/1.3.2...1.3.3\n[1.3.2]: https://github.com/fgnass/spin.js/compare/1.3.1...1.3.2\n[1.3.1]: https://github.com/fgnass/spin.js/compare/1.3.0...1.3.1\n[1.3.0]: https://github.com/fgnass/spin.js/compare/1.2.8...1.3.0\n[1.2.8]: https://github.com/fgnass/spin.js/compare/1.2.7...1.2.8\n[1.2.7]: https://github.com/fgnass/spin.js/compare/1.2.6...1.2.7\n[1.2.6]: https://github.com/fgnass/spin.js/compare/1.2.5...1.2.6\n[1.2.5]: https://github.com/fgnass/spin.js/compare/1.2.4...1.2.5\n[1.2.4]: https://github.com/fgnass/spin.js/compare/1.2.3...1.2.4\n[1.2.3]: https://github.com/fgnass/spin.js/compare/1.2.2...1.2.3\n[1.2.2]: https://github.com/fgnass/spin.js/compare/1.2.1...1.2.2\n[1.2.1]: https://github.com/fgnass/spin.js/compare/1.2.0...1.2.1\n[1.2.0]: https://github.com/fgnass/spin.js/compare/1.1.0...1.2.0\n[1.1.0]: https://github.com/fgnass/spin.js/compare/1.0.0...1.1.0\n[1.0.0]: https://github.com/fgnass/spin.js/tree/1.0.0\n\n[#355]: https://github.com/fgnass/spin.js/issues/355\n[#342]: https://github.com/fgnass/spin.js/issues/342\n[#341]: https://github.com/fgnass/spin.js/issues/341\n[#340]: https://github.com/fgnass/spin.js/issues/340\n[#327]: https://github.com/fgnass/spin.js/issues/327\n[#325]: https://github.com/fgnass/spin.js/issues/325\n[#300]: https://github.com/fgnass/spin.js/pull/300\n[#295]: https://github.com/fgnass/spin.js/pull/295\n[#294]: https://github.com/fgnass/spin.js/pull/294\n[#292]: https://github.com/fgnass/spin.js/issues/292\n[#287]: https://github.com/fgnass/spin.js/pull/287\n[#283]: https://github.com/fgnass/spin.js/pull/283\n[#250]: https://github.com/fgnass/spin.js/issues/250\n[#232]: https://github.com/fgnass/spin.js/pull/232\n[#229]: https://github.com/fgnass/spin.js/issues/229\n[#218]: https://github.com/fgnass/spin.js/issues/218\n[#189]: https://github.com/fgnass/spin.js/issues/189\n[#168]: https://github.com/fgnass/spin.js/issues/168\n[#167]: https://github.com/fgnass/spin.js/pull/167\n[#126]: https://github.com/fgnass/spin.js/pull/126\n[#115]: https://github.com/fgnass/spin.js/issues/115\n[#99]: https://github.com/fgnass/spin.js/issues/99\n[#98]: https://github.com/fgnass/spin.js/issues/98\n[#96]: https://github.com/fgnass/spin.js/issues/96\n[#93]: https://github.com/fgnass/spin.js/issues/93\n[#90]: https://github.com/fgnass/spin.js/issues/90\n[#87]: https://github.com/fgnass/spin.js/issues/87\n[#81]: https://github.com/fgnass/spin.js/issues/81\n[#78]: https://github.com/fgnass/spin.js/issues/78\n[#77]: https://github.com/fgnass/spin.js/issues/77\n[#74]: https://github.com/fgnass/spin.js/issues/74\n[#61]: https://github.com/fgnass/spin.js/issues/61\n[#60]: https://github.com/fgnass/spin.js/issues/60\n[#58]: https://github.com/fgnass/spin.js/issues/58\n[#47]: https://github.com/fgnass/spin.js/issues/47\n[#41]: https://github.com/fgnass/spin.js/issues/41\n[#36]: https://github.com/fgnass/spin.js/issues/36\n[#35]: https://github.com/fgnass/spin.js/issues/35\n[#31]: https://github.com/fgnass/spin.js/issues/31\n[#30]: https://github.com/fgnass/spin.js/issues/30\n[#28]: https://github.com/fgnass/spin.js/issues/28\n[#27]: https://github.com/fgnass/spin.js/issues/27\n[#23]: https://github.com/fgnass/spin.js/issues/23\n[#14]: https://github.com/fgnass/spin.js/issues/14\n[#12]: https://github.com/fgnass/spin.js/issues/12\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nAfter cloning the repository, run `npm install` to install development dependencies and compile the project.\nThen run `npm start` to start a static file server for viewing the site.\n\nAfter editing any TypeScript files, run `npm run prepare` to compile TypeScript and create a new bundle for the site.\n\n## Workflow to release a new version\n\nRun `npm version [<newversion> | major | minor | patch]` to bump the package version and create a new version commit and tag.\n\nThen run `npm publish` to build and publish the new version.\n\nFinally, run `npm run gh-pages` and `git push --tags` to update the website and repository.\n"
  },
  {
    "path": "Gruntfile.cjs",
    "content": "module.exports = function(grunt) {\n\n  grunt.initConfig({\n\n    copy: {\n      js: {\n        files: [\n          { src: ['spin.js', 'spin.css'], dest: 'site/' }\n        ]\n      }\n    },\n\n    'gh-pages': {\n      release: {\n        options: {\n          base: 'site',\n          message: 'automatic commit'\n        },\n        src: '**/*'\n      }\n    }\n\n  });\n\n  grunt.loadNpmTasks('grunt-contrib-copy');\n  grunt.loadNpmTasks('grunt-gh-pages');\n\n  grunt.registerTask('default', ['copy']);\n\n};\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License\n===============\n\nCopyright (c) 2011-2018 Felix Gnass [fgnass at gmail dot com]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# spin.js [![JS.ORG](https://img.shields.io/badge/js.org-spin-ffb400.svg?style=flat-square)](http://js.org)\n\nAn animated loading spinner\n\n * No images\n * No dependencies\n * Highly configurable\n * Resolution independent\n * Uses CSS keyframe animations\n * Works in all major browsers\n * Includes TypeScript definitions\n * Distributed as a native ES6 module\n * MIT License\n\n## Installation\n\n`npm install spin.js`\n\n## Usage\n\n### CSS\n\n```html\n<link rel=\"stylesheet\" href=\"node_modules/spin.js/spin.css\">\n```\n\n### TypeScript or JavaScript\n\n```javascript\nimport {Spinner} from 'spin.js';\n\nvar target = document.getElementById('foo');\nnew Spinner({color:'#fff', lines: 12}).spin(target);\n```\n\nFor an interactive demo and a list of all supported options please refer to the [project's homepage](https://spin.js.org).\n"
  },
  {
    "path": "SpinnerOptions.d.ts",
    "content": "export interface SpinnerOptions {\n    /**\n     * The number of lines to draw\n     */\n    lines?: number;\n\n    /**\n     * The length of each line\n     */\n    length?: number;\n\n    /**\n     * The line thickness\n     */\n    width?: number;\n\n    /**\n     * The radius of the inner circle\n     */\n    radius?: number;\n\n    /**\n     * Scales overall size of the spinner\n     */\n    scale?: number;\n\n    /**\n     * Corner roundness (0..1)\n     */\n    corners?: number;\n\n    /**\n     * A CSS color string, or array of strings to set the line color\n     */\n    color?: string | string[];\n\n    /**\n     * A CSS color string, or array of strings to set the color that lines will fade to.\n     * Defaults to transparent.\n     */\n    fadeColor?: string | string[];\n\n    /**\n     * The animation name used for the spinner lines. Defaults to 'spinner-line-fade-default'.\n     */\n    animation?: string;\n\n    /**\n     * The rotation offset\n     */\n    rotate?: number;\n\n    /**\n     * 1: clockwise, -1: counterclockwise\n     */\n    direction?: number;\n\n    /**\n     * Rounds per second\n     */\n    speed?: number;\n\n    /**\n     * The z-index (defaults to 2000000000)\n     */\n    zIndex?: number;\n\n    /**\n     * The CSS class to assign to the spinner\n     */\n    className?: string;\n\n    /**\n     * Top position relative to parent (defaults to 50%)\n     */\n    top?: string;\n\n    /**\n     * Left position relative to parent (defaults to 50%)\n     */\n    left?: string;\n\n    /**\n     * Whether to render the default shadow (boolean).\n     * A string can be used to set a custom box-shadow value.\n     */\n    shadow?: boolean | string;\n\n    /**\n     * Element positioning\n     */\n    position?: string;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"spin.js\",\n  \"version\": \"4.1.2\",\n  \"description\": \"A spinning activity indicator\",\n  \"files\": [\n    \"spin.css\",\n    \"spin.d.ts\",\n    \"spin.js\",\n    \"SpinnerOptions.d.ts\"\n  ],\n  \"type\": \"module\",\n  \"main\": \"spin.js\",\n  \"types\": \"spin.d.ts\",\n  \"author\": \"Felix Gnass <fgnass@gmail.com>\",\n  \"contributors\": [\n    \"Theodore Brown (https://github.com/theodorejb)\",\n    \"Timothy Gu <timothygu99@gmail.com>\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/fgnass/spin.js.git\"\n  },\n  \"keywords\": [\n    \"css\",\n    \"progress indicator\",\n    \"spin\",\n    \"spinner\"\n  ],\n  \"scripts\": {\n    \"prepare\": \"tsc && grunt --gruntfile Gruntfile.cjs && rollup -c\",\n    \"gh-pages\": \"grunt gh-pages --gruntfile Gruntfile.cjs\",\n    \"start\": \"serve site/\"\n  },\n  \"devDependencies\": {\n    \"grunt\": \"^1.6.1\",\n    \"grunt-contrib-copy\": \"^1.0.0\",\n    \"grunt-gh-pages\": \"^4.0.0\",\n    \"rollup\": \"^4.18.1\",\n    \"serve\": \"^14.2.3\",\n    \"typescript\": \"^5.5.3\"\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "export default [\n    {\n        input: 'spin.js',\n        output: {\n            file: 'site/spin.umd.js',\n            format: 'umd',\n            name: 'Spin',\n        },\n    },\n    {\n        input: 'site/index.js',\n        output: {\n            file: 'site/bundle.js',\n            format: 'iife'\n        }\n    }\n];\n"
  },
  {
    "path": "site/CNAME",
    "content": "spin.js.org\n"
  },
  {
    "path": "site/assets/gh-fork-ribbon.css",
    "content": "/*!\n * \"Fork me on GitHub\" CSS ribbon v0.2.3 | MIT License\n * https://github.com/simonwhitaker/github-fork-ribbon-css\n*/\n\n.github-fork-ribbon {\n  width: 12.1em;\n  height: 12.1em;\n  position: absolute;\n  overflow: hidden;\n  top: 0;\n  right: 0;\n  z-index: 9999;\n  pointer-events: none;\n  font-size: 13px;\n  text-decoration: none;\n  text-indent: -999999px;\n}\n\n.github-fork-ribbon.fixed {\n  position: fixed;\n}\n\n.github-fork-ribbon:hover, .github-fork-ribbon:active {\n  background-color: rgba(0, 0, 0, 0.0);\n}\n\n.github-fork-ribbon:before, .github-fork-ribbon:after {\n  /* The right and left classes determine the side we attach our banner to */\n  position: absolute;\n  display: block;\n  width: 15.38em;\n  height: 1.54em;\n\n  top: 3.23em;\n  right: -3.23em;\n\n  box-sizing: content-box;\n  transform: rotate(45deg);\n}\n\n.github-fork-ribbon:before {\n  content: \"\";\n\n  /* Add a bit of padding to give some substance outside the \"stitching\" */\n  padding: .38em 0;\n\n  /* Set the base colour */\n  background-color: #39922c;\n\n  /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */\n  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));\n\n  /* Add a drop shadow */\n  box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.3);\n\n  pointer-events: auto;\n}\n\n.github-fork-ribbon:after {\n  /* Set the text from the data-ribbon attribute */\n  content: attr(data-ribbon);\n\n  /* Set the text properties */\n  color: #fff;\n  font: 700 1em \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  line-height: 1.54em;\n  text-decoration: none;\n  text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);\n  text-align: center;\n  text-indent: 0;\n\n  /* Set the layout properties */\n  padding: .15em 0;\n  margin: .15em 0;\n\n  /* Add \"stitching\" effect */\n  border-width: .08em 0;\n  border-style: dotted;\n  border-color: #fff;\n  border-color: rgba(255, 255, 255, 0.7);\n}\n\n.github-fork-ribbon.left-top, .github-fork-ribbon.left-bottom {\n  right: auto;\n  left: 0;\n}\n\n.github-fork-ribbon.left-bottom, .github-fork-ribbon.right-bottom {\n  top: auto;\n  bottom: 0;\n}\n\n.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after {\n  right: auto;\n  left: -3.23em;\n}\n\n.github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {\n  top: auto;\n  bottom: 3.23em;\n}\n\n.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {\n  transform: rotate(-45deg);\n}\n"
  },
  {
    "path": "site/assets/main.css",
    "content": "html, body {\n  margin: 0;\n}\n\nhtml {\n  background: url(bg.png);\n}\n\nbody {\n  color: #333;\n  font-family: Helvetica, Arial, sans-serif;\n  font-size: 16px;\n}\n\nul {\n  padding: 0 0 0 20px;\n}\n\n#content {\n  max-width: 800px;\n  line-height: 1.4em;\n  padding: 0 40px 40px;\n  text-shadow: 0px 1px 0px #fff;\n}\n\n#content img {\n  max-width: 100%;\n}\n\n#footer {\n  background: #202020;\n  overflow: hidden;\n  color: #888;\n  font-size: 12px;\n  padding: 20px 0 100px 50px;\n  position: relative;\n}\n\n#footer:before {\n  content: '';\n  display: block;\n  box-shadow: 0 0 10px #000;\n  height: 10px;\n  position: absolute;\n  left: 0;\n  top: -10px;\n  width: 100%;\n}\n\n#footer a.github {\n   background: url(github.svg) no-repeat;\n   background-size: 100%;\n   width: 144px;\n   height: 72px;\n   text-indent: -999em;\n   position: absolute;\n   bottom: 30px;\n   right: 30px;\n}\n\na {\n  color: #333;\n}\n\na:hover {\n  color: #000;\n}\n\nlabel {\n  font-size: 14px;\n  vertical-align: top;\n}\n\n#opts {\n  background: #fff;\n  padding: 10px;\n  margin-top: 20px;\n  box-sizing: border-box;\n}\n\n#opts label {\n  display: inline-block;\n  line-height: 25px;\n  width: 80px;\n}\n\nh1 {\n  font-size: 100px;\n}\n\nh1, h2, h3, #download a {\n  font-family: 'Amaranth', sans-serif;\n}\n\nh2 {\n  font-size: 28px;\n  margin: 30px 0 20px;\n}\n\nh3 {\n  margin: 30px 0 10px 0;\n}\n\n.mid_col {\n  width: 20px;\n}\n\n#opts, #preview {\n  width: 325px;\n  border-radius: 10px;\n}\n\n#preview {\n  position: relative;\n  background: #333;\n  height: 325px;\n}\n\n@media screen and (min-width: 545px) {\n  h1 {\n    font-size: 150px;\n  }\n}\n\n@media screen and (min-width: 745px) {\n  h1 {\n    font-size: 175px;\n  }\n\n  #opts, .mid_col, #preview {\n    display: table-cell;\n  }\n\n  #opts {\n    width: auto;\n  }\n\n  #preview {\n    height: 100%;\n  }\n}\n\n@media screen and (min-width: 800px) {\n  #preview {\n    width: 375px;\n  }\n}\n\n@media screen and (min-width: 900px) {\n  h1 {\n    font-size: 200px;\n  }\n\n  #content {\n    margin-left: 100px;\n  }\n}\n\n@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {\n  /* styling fixes for IE 10 and IE 11 only */\n\n  #opts input[type=\"range\"] {\n    padding: 7px;\n    width: 150px;\n  }\n\n  #opts, .mid_col, #preview {\n    display: inline-block;\n  }\n\n  #preview {\n    height: 400px;\n  }\n}\n\na.button {\n  display: inline-block;\n  background: #56ba4a;\n  border: 3px solid #59a24f;\n  color: #fff;\n  border-radius: 5px;\n  font-family: 'Amaranth', sans-serif;\n  font-size: 24px;\n  padding: 10px 30px;\n  text-decoration: none;\n  text-shadow: 1px 1px 1px #59a24f;\n  box-shadow: 2px 2px 4px rgba(0,0,0,0.2);\n  margin: 10px 20px 0 0;\n  transition: all 0.25s ease;\n}\n\na.button:hover {\n  background: #2f8325;\n  box-shadow: none;\n}\n\n.authors {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(275px, 1fr));\n  grid-gap: 50px;\n}\n\n.contact {\n  background-color: #e1e1e1;\n  padding: 24px;\n  text-align: center;\n  box-shadow: 2px 2px 10px #bbb;\n}\n\n.contact h3 {\n  margin: 20px 0;\n}\n\n.contact p {\n  margin-bottom: 0;\n}\n\n.contact img {\n  border-radius: 50%;\n}\n"
  },
  {
    "path": "site/assets/prism.css",
    "content": "/* PrismJS 1.20.0\nhttps://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript */\n/**\n * okaidia theme for JavaScript, CSS and HTML\n * Loosely based on Monokai textmate theme by http://www.monokai.nl/\n * @author ocodia\n */\n\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n\tcolor: #f8f8f2;\n\tbackground: none;\n\ttext-shadow: 0 1px rgba(0, 0, 0, 0.3);\n\tfont-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;\n\tfont-size: 1em;\n\ttext-align: left;\n\twhite-space: pre;\n\tword-spacing: normal;\n\tword-break: normal;\n\tword-wrap: normal;\n\tline-height: 1.5;\n\n\t-moz-tab-size: 4;\n\t-o-tab-size: 4;\n\ttab-size: 4;\n\n\t-webkit-hyphens: none;\n\t-moz-hyphens: none;\n\t-ms-hyphens: none;\n\thyphens: none;\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n\tpadding: 1em;\n\tmargin: .5em 0;\n\toverflow: auto;\n\tborder-radius: 0.3em;\n}\n\n:not(pre) > code[class*=\"language-\"],\npre[class*=\"language-\"] {\n\tbackground: #272822;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"language-\"] {\n\tpadding: .1em;\n\tborder-radius: .3em;\n\twhite-space: normal;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n\tcolor: #8292a2;\n}\n\n.token.punctuation {\n\tcolor: #f8f8f2;\n}\n\n.token.namespace {\n\topacity: .7;\n}\n\n.token.property,\n.token.tag,\n.token.constant,\n.token.symbol,\n.token.deleted {\n\tcolor: #f92672;\n}\n\n.token.boolean,\n.token.number {\n\tcolor: #ae81ff;\n}\n\n.token.selector,\n.token.attr-name,\n.token.string,\n.token.char,\n.token.builtin,\n.token.inserted {\n\tcolor: #a6e22e;\n}\n\n.token.operator,\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string,\n.token.variable {\n\tcolor: #f8f8f2;\n}\n\n.token.atrule,\n.token.attr-value,\n.token.function,\n.token.class-name {\n\tcolor: #e6db74;\n}\n\n.token.keyword {\n\tcolor: #66d9ef;\n}\n\n.token.regex,\n.token.important {\n\tcolor: #fd971f;\n}\n\n.token.important,\n.token.bold {\n\tfont-weight: bold;\n}\n.token.italic {\n\tfont-style: italic;\n}\n\n.token.entity {\n\tcursor: help;\n}\n\n"
  },
  {
    "path": "site/assets/prism.js",
    "content": "/* PrismJS 1.20.0\nhttps://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\\blang(?:uage)?-([\\w-]+)\\b/i,n=0,M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++n}),e.__id},clone:function t(e,r){var a,n;switch(r=r||{},M.util.type(e)){case\"Object\":if(n=M.util.objId(e),r[n])return r[n];for(var i in a={},r[n]=a,e)e.hasOwnProperty(i)&&(a[i]=t(e[i],r));return a;case\"Array\":return n=M.util.objId(e),r[n]?r[n]:(a=[],r[n]=a,e.forEach(function(e,n){a[n]=t(e,r)}),a);default:return e}},getLanguage:function(e){for(;e&&!c.test(e.className);)e=e.parentElement;return e?(e.className.match(c)||[,\"none\"])[1].toLowerCase():\"none\"},currentScript:function(){if(\"undefined\"==typeof document)return null;if(\"currentScript\"in document)return document.currentScript;try{throw new Error}catch(e){var n=(/at [^(\\r\\n]*\\((.*):.+:.+\\)$/i.exec(e.stack)||[])[1];if(n){var t=document.getElementsByTagName(\"script\");for(var r in t)if(t[r].src==n)return t[r]}return null}},isActive:function(e,n,t){for(var r=\"no-\"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{extend:function(e,n){var t=M.util.clone(M.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(t,e,n,r){var a=(r=r||M.languages)[t],i={};for(var l in a)if(a.hasOwnProperty(l)){if(l==e)for(var o in n)n.hasOwnProperty(o)&&(i[o]=n[o]);n.hasOwnProperty(l)||(i[l]=a[l])}var s=r[t];return r[t]=i,M.languages.DFS(M.languages,function(e,n){n===s&&e!=t&&(this[e]=i)}),i},DFS:function e(n,t,r,a){a=a||{};var i=M.util.objId;for(var l in n)if(n.hasOwnProperty(l)){t.call(n,l,n[l],r||l);var o=n[l],s=M.util.type(o);\"Object\"!==s||a[i(o)]?\"Array\"!==s||a[i(o)]||(a[i(o)]=!0,e(o,t,l,a)):(a[i(o)]=!0,e(o,t,null,a))}}},plugins:{},highlightAll:function(e,n){M.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};M.hooks.run(\"before-highlightall\",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),M.hooks.run(\"before-all-elements-highlight\",r);for(var a,i=0;a=r.elements[i++];)M.highlightElement(a,!0===n,r.callback)},highlightElement:function(e,n,t){var r=M.util.getLanguage(e),a=M.languages[r];e.className=e.className.replace(c,\"\").replace(/\\s+/g,\" \")+\" language-\"+r;var i=e.parentElement;i&&\"pre\"===i.nodeName.toLowerCase()&&(i.className=i.className.replace(c,\"\").replace(/\\s+/g,\" \")+\" language-\"+r);var l={element:e,language:r,grammar:a,code:e.textContent};function o(e){l.highlightedCode=e,M.hooks.run(\"before-insert\",l),l.element.innerHTML=l.highlightedCode,M.hooks.run(\"after-highlight\",l),M.hooks.run(\"complete\",l),t&&t.call(l.element)}if(M.hooks.run(\"before-sanity-check\",l),!l.code)return M.hooks.run(\"complete\",l),void(t&&t.call(l.element));if(M.hooks.run(\"before-highlight\",l),l.grammar)if(n&&u.Worker){var s=new Worker(M.filename);s.onmessage=function(e){o(e.data)},s.postMessage(JSON.stringify({language:l.language,code:l.code,immediateClose:!0}))}else o(M.highlight(l.code,l.grammar,l.language));else o(M.util.encode(l.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};return M.hooks.run(\"before-tokenize\",r),r.tokens=M.tokenize(r.code,r.grammar),M.hooks.run(\"after-tokenize\",r),W.stringify(M.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new i;return I(a,a.head,e),function e(n,t,r,a,i,l){for(var o in r)if(r.hasOwnProperty(o)&&r[o]){var s=r[o];s=Array.isArray(s)?s:[s];for(var u=0;u<s.length;++u){if(l&&l.cause==o+\",\"+u)return;var c=s[u],g=c.inside,f=!!c.lookbehind,h=!!c.greedy,d=0,v=c.alias;if(h&&!c.pattern.global){var p=c.pattern.toString().match(/[imsuy]*$/)[0];c.pattern=RegExp(c.pattern.source,p+\"g\")}for(var m=c.pattern||c,y=a.next,k=i;y!==t.tail&&!(l&&k>=l.reach);k+=y.value.length,y=y.next){var b=y.value;if(t.length>n.length)return;if(!(b instanceof W)){var x=1;if(h&&y!=t.tail.prev){m.lastIndex=k;var w=m.exec(n);if(!w)break;var A=w.index+(f&&w[1]?w[1].length:0),P=w.index+w[0].length,S=k;for(S+=y.value.length;S<=A;)y=y.next,S+=y.value.length;if(S-=y.value.length,k=S,y.value instanceof W)continue;for(var E=y;E!==t.tail&&(S<P||\"string\"==typeof E.value);E=E.next)x++,S+=E.value.length;x--,b=n.slice(k,S),w.index-=k}else{m.lastIndex=0;var w=m.exec(b)}if(w){f&&(d=w[1]?w[1].length:0);var A=w.index+d,O=w[0].slice(d),P=A+O.length,L=b.slice(0,A),N=b.slice(P),j=k+b.length;l&&j>l.reach&&(l.reach=j);var C=y.prev;L&&(C=I(t,C,L),k+=L.length),z(t,C,x);var _=new W(o,g?M.tokenize(O,g):O,v,O);y=I(t,C,_),N&&I(t,y,N),1<x&&e(n,t,r,y.prev,k,{cause:o+\",\"+u,reach:j})}}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=M.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=M.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:W};function W(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||\"\").length}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function I(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function z(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;(n.next=r).prev=n,e.length-=a}if(u.Prism=M,W.stringify=function n(e,t){if(\"string\"==typeof e)return e;if(Array.isArray(e)){var r=\"\";return e.forEach(function(e){r+=n(e,t)}),r}var a={type:e.type,content:n(e.content,t),tag:\"span\",classes:[\"token\",e.type],attributes:{},language:t},i=e.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),M.hooks.run(\"wrap\",a);var l=\"\";for(var o in a.attributes)l+=\" \"+o+'=\"'+(a.attributes[o]||\"\").replace(/\"/g,\"&quot;\")+'\"';return\"<\"+a.tag+' class=\"'+a.classes.join(\" \")+'\"'+l+\">\"+a.content+\"</\"+a.tag+\">\"},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener(\"message\",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var e=M.util.currentScript();function t(){M.manual||M.highlightAll()}if(e&&(M.filename=e.src,e.hasAttribute(\"data-manual\")&&(M.manual=!0)),!M.manual){var r=document.readyState;\"loading\"===r||\"interactive\"===r&&e&&e.defer?document.addEventListener(\"DOMContentLoaded\",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return M}(_self);\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:/<!--[\\s\\S]*?-->/,prolog:/<\\?[\\s\\S]+?\\?>/,doctype:{pattern:/<!DOCTYPE(?:[^>\"'[\\]]|\"[^\"]*\"|'[^']*')+(?:\\[(?:[^<\"'\\]]|\"[^\"]*\"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\\]\\s*)?>/i,greedy:!0,inside:{\"internal-subset\":{pattern:/(\\[)[\\s\\S]+(?=\\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\\]]/,\"doctype-tag\":/^DOCTYPE/,name:/[^\\s<>'\"]+/}},cdata:/<!\\[CDATA\\[[\\s\\S]*?]]>/i,tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s(?:\\s*[^\\s>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))|(?=[\\s/>])))+)?\\s*\\/?>/,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:[{pattern:/&[\\da-z]{1,8};/i,alias:\"named-entity\"},/&#x?[\\da-f]{1,8};/i]},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside[\"internal-subset\"].inside=Prism.languages.markup,Prism.hooks.add(\"wrap\",function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))}),Object.defineProperty(Prism.languages.markup.tag,\"addInlined\",{value:function(a,e){var s={};s[\"language-\"+e]={pattern:/(^<!\\[CDATA\\[)[\\s\\S]+?(?=\\]\\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\\[CDATA\\[|\\]\\]>$/i;var n={\"included-cdata\":{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,inside:s}};n[\"language-\"+e]={pattern:/[\\s\\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp(\"(<__[^]*?>)(?:<!\\\\[CDATA\\\\[(?:[^\\\\]]|\\\\](?!\\\\]>))*\\\\]\\\\]>|(?!<!\\\\[CDATA\\\\[)[^])*?(?=</__>)\".replace(/__/g,function(){return a}),\"i\"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore(\"markup\",\"cdata\",t)}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend(\"markup\",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;\n!function(e){var s=/(\"|')(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/;e.languages.css={comment:/\\/\\*[\\s\\S]*?\\*\\//,atrule:{pattern:/@[\\w-]+[\\s\\S]*?(?:;|(?=\\s*\\{))/,inside:{rule:/^@[\\w-]+/,\"selector-function-argument\":{pattern:/(\\bselector\\s*\\((?!\\s*\\))\\s*)(?:[^()]|\\((?:[^()]|\\([^()]*\\))*\\))+?(?=\\s*\\))/,lookbehind:!0,alias:\"selector\"},keyword:{pattern:/(^|[^\\w-])(?:and|not|only|or)(?![\\w-])/,lookbehind:!0}}},url:{pattern:RegExp(\"\\\\burl\\\\((?:\"+s.source+\"|(?:[^\\\\\\\\\\r\\n()\\\"']|\\\\\\\\[^])*)\\\\)\",\"i\"),greedy:!0,inside:{function:/^url/i,punctuation:/^\\(|\\)$/,string:{pattern:RegExp(\"^\"+s.source+\"$\"),alias:\"url\"}}},selector:RegExp(\"[^{}\\\\s](?:[^{};\\\"']|\"+s.source+\")*?(?=\\\\s*\\\\{)\"),string:{pattern:s,greedy:!0},property:/[-_a-z\\xA0-\\uFFFF][-\\w\\xA0-\\uFFFF]*(?=\\s*:)/i,important:/!important\\b/i,function:/[-a-z0-9]+(?=\\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined(\"style\",\"css\"),e.languages.insertBefore(\"inside\",\"attr-value\",{\"style-attr\":{pattern:/\\s*style=(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1/i,inside:{\"attr-name\":{pattern:/^\\s*style/i,inside:t.tag.inside},punctuation:/^\\s*=\\s*['\"]|['\"]\\s*$/,\"attr-value\":{pattern:/.+/i,inside:e.languages.css}},alias:\"language-css\"}},t.tag))}(Prism);\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/(\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,boolean:/\\b(?:true|false)\\b/,function:/\\w+(?=\\()/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{\"class-name\":[Prism.languages.clike[\"class-name\"],{pattern:/(^|[^$\\w\\xA0-\\uFFFF])[_$A-Z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\\s*)(?:catch|finally)\\b/,lookbehind:!0},{pattern:/(^|[^.]|\\.\\.\\.\\s*)\\b(?:as|async(?=\\s*(?:function\\b|\\(|[$\\w\\xA0-\\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\\s*[\\[$\\w\\xA0-\\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\\b/,lookbehind:!0}],number:/\\b(?:(?:0[xX](?:[\\dA-Fa-f](?:_[\\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\\d(?:_\\d)?)+n|NaN|Infinity)\\b|(?:\\b(?:\\d(?:_\\d)?)+\\.?(?:\\d(?:_\\d)?)*|\\B\\.(?:\\d(?:_\\d)?)+)(?:[Ee][+-]?(?:\\d(?:_\\d)?)+)?/,function:/#?[_$a-zA-Z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,operator:/--|\\+\\+|\\*\\*=?|=>|&&=?|\\|\\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\\.{3}|\\?\\?=?|\\?\\.?|[~:]/}),Prism.languages.javascript[\"class-name\"][0].pattern=/(\\b(?:class|interface|extends|implements|instanceof|new)\\s+)[\\w.\\\\]+/,Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:/((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)\\/(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[gimyus]{0,6}(?=(?:\\s|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*(?:$|[\\r\\n,.;:})\\]]|\\/\\/))/,lookbehind:!0,greedy:!0},\"function-variable\":{pattern:/#?[_$a-zA-Z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*[=:]\\s*(?:async\\s*)?(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|[_$a-zA-Z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*)\\s*=>))/,alias:\"function\"},parameter:[{pattern:/(function(?:\\s+[_$A-Za-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*)?\\s*\\(\\s*)(?!\\s)(?:[^()]|\\([^()]*\\))+?(?=\\s*\\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\\(\\s*)(?!\\s)(?:[^()]|\\([^()]*\\))+?(?=\\s*\\)\\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\\b|\\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\\w\\xA0-\\uFFFF]))(?:[_$A-Za-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*\\s*)\\(\\s*|\\]\\s*\\(\\s*)(?!\\s)(?:[^()]|\\([^()]*\\))+?(?=\\s*\\)\\s*\\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\\b[A-Z](?:[A-Z_]|\\dx?)*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\\${)[^\\\\`])*`/,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\${|}$/,alias:\"punctuation\"},rest:Prism.languages.javascript}},string:/[\\s\\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined(\"script\",\"javascript\"),Prism.languages.js=Prism.languages.javascript;\n"
  },
  {
    "path": "site/example/positioning.css",
    "content": "body {\n    font-family: Helvetica, Arial, sans-serif;\n    font-size: 16px;\n    padding: 0;\n    margin: 0;\n}\n\ndiv {\n    position: relative;\n    border-radius: 10px;\n}\n\n#target1 {\n    background: #aaa url(../assets/crosshair.gif) center center no-repeat;\n    width: 99px;\n    height: 99px;\n    padding: 15px;\n}\n\n#target2 {\n    background: #bbb url(../assets/crosshair.gif) center center no-repeat;\n    width: 99px;\n    height: 99px;\n    padding: 15px;\n}\n\n#target3 {\n    background: #ccc url(../assets/crosshair.gif) center center no-repeat;\n    width: 99px;\n    height: 99px;\n    padding: 15px;\n}\n\n#target4 {\n    background: #ddd;\n    padding: 15px;\n    width: 375px;\n    height: 66px;\n    padding: 66px 38px;\n}\n\n@keyframes spinner-line-fade-custom {\n  0%, 59%, 100% {\n    opacity: 0.25; /* minimum opacity */\n  }\n  60% {\n    opacity: 1;\n  }\n}\n"
  },
  {
    "path": "site/example/positioning.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title>spin.js</title>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"../spin.css\"/>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"positioning.css\"/>\n</head>\n<body>\n\n<div id=\"target1\"></div>\n<div id=\"target2\"></div>\n<div id=\"target3\"></div>\n<div id=\"target4\"><img src=\"../assets/browsers.png\"></div>\n\n<script type=\"module\" src=\"positioning.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "site/example/positioning.js",
    "content": "import { Spinner } from \"../spin.js\";\n\nnew Spinner({ radius: 10, length: 40, color: ['red', 'green', 'blue'] })\n    .spin(document.getElementById('target1'));\nnew Spinner({ radius: 40, length: 10 }).spin(document.getElementById('target2'));\nnew Spinner({ top: 0, left: 0 }).spin(document.getElementById('target3'));\nnew Spinner({ radius: 32, length: 0, width: 10, color: '#c13d3d', animation: 'spinner-line-fade-custom' })\n    .spin(document.getElementById('target4'));\n"
  },
  {
    "path": "site/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\"/>\n  <title>spin.js</title>\n  <meta name=\"title\" content=\"Animated activity indicator\">\n  <meta name=\"description\" content=\"A highly configurable JavaScript/CSS spinner that can be used as a resolution-independent loading indicator.\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <meta property=\"og:image\" content=\"https://spin.js.org/assets/preview.png\"/>\n  <link rel=\"shortcut icon\" href=\"assets/favicon.ico\">\n  <link href=\"spin.css\" rel=\"stylesheet\">\n  <link href=\"assets/gh-fork-ribbon.css\" rel=\"stylesheet\">\n  <link href=\"assets/main.css\" rel=\"stylesheet\">\n  <link href=\"https://fonts.googleapis.com/css?family=Amaranth:400,700\" rel=\"stylesheet\">\n  <link href=\"assets/prism.css\" rel=\"stylesheet\">\n</head>\n<body>\n\n<a class=\"github-fork-ribbon right-top\" href=\"https://github.com/fgnass/spin.js\" data-ribbon=\"Fork me on GitHub\" title=\"Fork me on GitHub\">Fork me on GitHub</a>\n\n<div id=\"content\">\n\n<h1>spin.js</h1>\n\n<div id=\"download\">\n  <a href=\"spin.js\" class=\"button\">spin.js (ESM)</a>\n  <a href=\"spin.umd.js\" class=\"button\">spin.umd.js</a>\n  <a href=\"spin.css\" class=\"button\">spin.css</a>\n</div>\n\n<h2>Example</h2>\n<div id=\"example\">\n  <div id=\"preview\"></div>\n  <div class=\"mid_col\"></div>\n  <form id=\"opts\">\n    <label>Lines:</label><input type=\"range\" name=\"lines\" min=\"5\" max=\"20\" step=\"1\" value=\"13\"><br>\n    <label>Length:</label><input type=\"range\" name=\"length\" min=\"0\" max=\"80\" value=\"38\"><br>\n    <label>Width:</label><input type=\"range\" name=\"width\" min=\"2\" max=\"52\" value=\"17\"><br>\n    <label>Radius:</label><input type=\"range\" name=\"radius\" min=\"0\" max=\"84\" value=\"45\"><br>\n    <label>Scale:</label><input type=\"range\" name=\"scale\" min=\"0.05\" max=\"4.0\" step=\"0.05\" value=\"1.0\"><br>\n    <label>Corners:</label><input type=\"range\" name=\"corners\" min=\"0\" max=\"1\" step=\"0.1\" value=\"1\"><br>\n    <label>Speed:</label><input type=\"range\" name=\"speed\" min=\"0.5\" max=\"2.2\" step=\"0.1\" value=\"1\"><br>\n    <label>Rotate:</label><input type=\"range\" name=\"rotate\" min=\"0\" max=\"90\" value=\"0\"><br>\n    <label>Animation:</label>\n    <select class=\"string\" name=\"animation\">\n      <option value=\"spinner-line-fade-default\">spinner-line-fade-default</option>\n      <option value=\"spinner-line-fade-quick\" selected>spinner-line-fade-quick</option>\n      <option value=\"spinner-line-fade-more\">spinner-line-fade-more</option>\n      <option value=\"spinner-line-shrink\">spinner-line-shrink</option>\n    </select>\n    <br>\n    <label>Direction:</label>\n    <select name=\"direction\">\n      <option value=\"1\">Clockwise</option>\n      <option value=\"-1\">Counterclockwise</option>\n    </select>\n    <br>\n    <label>Color:</label><input class=\"string\" type=\"color\" name=\"color\" value=\"#ffffff\"><br>\n    <label>Fade color:</label><input class=\"string\" type=\"text\" name=\"fadeColor\" value=\"transparent\"><br>\n    <label>↕:</label><input class=\"percent\" type=\"range\" name=\"top\" min=\"0\" max=\"100\" value=\"50\"><br>\n    <label>↔:</label><input class=\"percent\" type=\"range\" name=\"left\" min=\"0\" max=\"100\" value=\"50\"><br>\n    <label>Shadow:</label><input class=\"string\" type=\"text\" name=\"shadow\" value=\"0 0 1px transparent\"><br>\n  </form>\n</div>\n\n<p>\n  <input type=\"checkbox\" id=\"share\">\n  <label for=\"share\">\n    <b>Share it!</b> If checked, the option values will be stored in the URL so that you can easily share your settings.\n  </label>\n</p>\n\n<h2>Features</h2>\n<ul>\n  <li>No images</li>\n  <li>No dependencies</li>\n  <li>Highly configurable</li>\n  <li>Resolution independent</li>\n  <li>Uses CSS keyframe animations</li>\n  <li>Works in all major browsers</li>\n  <li>Includes TypeScript definitions</li>\n  <li>Distributed as a native ECMAScript module</li>\n  <li>MIT License</li>\n</ul>\n<p>\n  Spin.js dynamically creates spinning activity indicators that can be used as\n  a resolution-independent replacement for loading GIFs.\n</p>\n\n<h2>Installation</h2>\n<p>\n  Run <code>npm install spin.js</code>, or save the spin.js and spin.css files in your repository.\n</p>\n\n<h3>JS bundling</h3>\n<p>\n  For best performance and compatibility, it is recommended to use a module bundler such as\n  <a href=\"https://parceljs.org/\">Parcel</a>, <a href=\"https://rollupjs.org/\">Rollup</a>,\n  or <a href=\"https://webpack.js.org/\">Webpack</a> to create a production-ready code bundle.\n  However, in modern browsers it is also possible to directly load the module via a script tag:\n</p>\n<pre>\n<code class=\"language-html\">&lt;script type=\"module\" src=\"node_modules/spin.js/spin.js\">&lt;/script></code>\n</pre>\n<p>\n  If for some reason you can't use ECMAScript modules or a module bundler,\n  download <a href=\"spin.umd.js\">spin.umd.js</a> and save it in your repository.\n  The UMD script can be used as follows:\n</p>\n<pre>\n<code class=\"language-js\">var spinner = new Spin.Spinner(opts).spin(target);</code>\n</pre>\n<p>\n  Note that the UMD version is only available as a temporary workaround.\n  Longer term it is recommended to migrate to the standard ECMAScript module.\n</p>\n\n<h3>CSS</h3>\n<p>\n  Load the spin.css file to include the default animation presets.\n  You could alternatively create a custom CSS keyframe animation (in your own CSS file)\n  and set it using the <code>animation</code> property.\n</p>\n<p>\n  Note: do not use <code>&lt;script&gt;</code> or <code>&lt;link&gt;</code> tags directly referencing the files on this website.\n  Doing this is likely to break your app whenever a major new version is released.\n</p>\n\n<h2 id=\"usage\">Usage</h2>\n<p>\n  Run the following code when the document has loaded:\n</p>\n\n<!-- populated dynamically -->\n<pre>\n<code id=\"spinner-options\" class=\"language-js\"></code>\n</pre>\n\n<p>\n  The <code>spin()</code> method creates the necessary HTML elements and starts the animation. If a target\n  element is passed as argument, the spinner is added as first child and horizontally and vertically centered.\n</p>\n\n<h3>Manual insertion</h3>\n<p>\n  In order to manually insert the spinner into the DOM you can invoke the <code>spin()</code> method\n  without any arguments and use the <code>el</code> property to access the HTML element:\n</p>\n<pre>\n<code class=\"language-js\">var spinner = new Spinner().spin();\ntarget.appendChild(spinner.el);</code>\n</pre>\n\n<h3>Hiding the spinner</h3>\n<p>\n  To hide the spinner, invoke the\n  <code>stop()</code> method, which removes the UI elements from the DOM and stops the animation.\n  Stopped spinners may be reused by calling <code>spin()</code> again.\n</p>\n\n<h3>Positioning</h3>\n<p>\n  The spinner is absolutely positioned at 50% of its offset parent.\n  You may specify a <code>top</code> and <code>left</code> option to position the spinner manually.\n</p>\n<p>\n  <b>Note:</b> The spinner element is a 0&times;0 pixel div that represents the center of the spinner.\n  Hence, if you passed <code>{top:0, left:0}</code> only the lower right quarter of the spinner would\n  be inside the target's bounding box.\n</p>\n<p>\n  The spinner element must be surrounded by an element using relative positioning, or the spinner will be\n  outside of the parent element.\n</p>\n\n<h2>Supported browsers</h2>\n<img src=\"assets/browsers.svg\">\n<p>\n  Spin.js has been successfully tested in the following browsers:\n</p>\n<ul>\n  <li>Firefox</li>\n  <li>Microsoft Edge</li>\n  <li>Safari</li>\n  <li>Chrome</li>\n  <li>Internet Explorer 10+</li>\n</ul>\n\n<h2>Changes</h2>\n\n<p>\n   See <a href=\"https://github.com/fgnass/spin.js/blob/master/CHANGELOG.md\">CHANGELOG.md</a>\n</p>\n\n<h2>Support</h2>\n\n<p>\n  If you encounter any problems, please use the <a href=\"https://github.com/fgnass/spin.js/issues\">GitHub issue tracker</a>.\n</p>\n\n<h2>Authors</h2>\n\n<div class=\"authors\">\n  <div class=\"contact\">\n    <img src=\"https://www.gravatar.com/avatar/f1f2e1842f6ff681a6d1b0a2405d0117\"/>\n    <h3>Felix Gnass</h3>\n    <p>JS 💛 React ⚛️ NodeJS 💚</p>\n    <p>\n      Twitter: <a href=\"https://twitter.com/fgnass\">@fgnass</a>\n    </p>\n  </div>\n  \n  <div class=\"contact\">\n    <img src=\"https://www.gravatar.com/avatar/5f7e5be7427b4c706eb1ff85ceb98998\"/>\n    <h3>Theodore Brown</h3>\n    <p>PHP 🐘 TypeScript 📐 SQL 📊</p>\n    <p>\n      Website: <a href=\"https://theodorejb.me\">theodorejb.me</a><br/>\n      Twitter: <a href=\"https://twitter.com/theodorejb\">@theodorejb</a>\n    </p>\n  </div>\n</div>\n\n</div>\n<div id=\"footer\">\n  <a class=\"github\" href=\"https://github.com/fgnass/spin.js\">Hosted on GitHub</a>\n</div>\n\n<script src=\"assets/prism.js\"></script>\n<script src=\"bundle.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "site/index.js",
    "content": "import { Spinner } from \"../spin.js\";\n\nvar inputs = document.querySelectorAll('#opts input[type=\"range\"], #opts input[type=\"color\"], #opts input[type=\"text\"], #opts select');\nvar cbInputs = document.querySelectorAll('#opts input[type=\"checkbox\"]');\nvar spinnerEl = document.getElementById('preview');\nvar shareEl = document.getElementById('share');\nvar spinner;\nvar params = {};\nvar hash = /^#\\?(.*)/.exec(location.hash);\n\nif (hash) {\n    shareEl.checked = true;\n\n    hash[1].split(/&/).forEach(function (pair) {\n        var kv = pair.split(/=/);\n        params[kv[0]] = decodeURIComponent(kv[kv.length - 1]);\n    });\n}\n\nfor (var i = 0; i < inputs.length; i++) {\n    var input = inputs[i];\n    var val = params[input.name];\n\n    if (val !== undefined) {\n        input.value = val;\n    }\n\n    if (input.tagName === 'SELECT' || navigator.userAgent.indexOf('Trident') !== -1) {\n        // \"input\" event doesn't work on range inputs in Internet Explorer\n        var event = 'change';\n    } else {\n        event = 'input';\n    }\n\n    input.addEventListener(event, update);\n}\n\nfor (var i = 0; i < cbInputs.length; i++) {\n    var input = cbInputs[i];\n    input.checked = !!params[input.name];\n    input.addEventListener('click', update);\n}\n\nshareEl.addEventListener('click', function () {\n    var value = '#!';\n\n    if (shareEl.checked) {\n        var opts = getOptionsFromInputs();\n        value = '#?' + getParamStringFromOpts(opts);\n    }\n\n    window.location.replace(value);\n});\n\nupdate();\n\nfunction update() {\n    var opts = getOptionsFromInputs();\n\n    if (spinner) {\n        spinner.stop();\n    }\n    \n    spinner = new Spinner(opts).spin(spinnerEl);\n\n    if (shareEl.checked) {\n        window.location.replace('#?' + getParamStringFromOpts(opts));\n    }\n\n    let codeEl = document.getElementById('spinner-options');\n    codeEl.textContent = getOptionsCode(opts);\n    Prism.highlightElement(codeEl);\n}\n\nfunction getOptionsCode(options) {\n    var optDescriptions = {\n        lines: 'The number of lines to draw',\n        length: 'The length of each line',\n        width: 'The line thickness',\n        radius: 'The radius of the inner circle',\n        scale: 'Scales overall size of the spinner',\n        corners: 'Corner roundness (0..1)',\n        color: 'CSS color or array of colors',\n        fadeColor: 'CSS color or array of colors',\n        speed: 'Rounds per second',\n        rotate: 'The rotation offset',\n        animation: 'The CSS animation name for the lines',\n        direction: '1: clockwise, -1: counterclockwise',\n        zIndex: 'The z-index (defaults to 2e9)',\n        className: 'The CSS class to assign to the spinner',\n        top: 'Top position relative to parent',\n        left: 'Left position relative to parent',\n        shadow: 'Box-shadow for the lines',\n        position: 'Element positioning',\n    };\n\n    let code = \"import {Spinner} from 'spin.js';\\n\\n\";\n    code += \"var opts = {\\n\";\n\n    for (let opt in options) {\n        let value = options[opt];\n\n        if (typeof value === 'string') {\n            value = \"'\" + value + \"'\";\n        }\n\n        code += \"  \" + opt + \": \" + value + \", // \" + optDescriptions[opt] + \"\\n\";\n    }\n\n    code += \"};\\n\\n\";\n\n    code += \"var target = document.getElementById('foo');\\n\";\n    code += \"var spinner = new Spinner(opts).spin(target);\";\n\n    return code;\n}\n\nfunction getOptionsFromInputs() {\n    var opts = {};\n\n    for (var i = 0; i < inputs.length; i++) {\n        var input = inputs[i];\n        var val = input.value;\n\n        if (input.classList.contains('percent')) {\n            val += '%';\n        } else if (!input.classList.contains('string')) {\n            val = parseFloat(val);\n        }\n\n        opts[input.name] = val;\n    }\n\n    // set all options so they can be shown in code example\n    opts['zIndex'] = 2e9;\n    opts['className'] = 'spinner';\n    opts['position'] = 'absolute';\n\n    for (var i = 0; i < cbInputs.length; i++) {\n        var input = cbInputs[i];\n        opts[input.name] = input.checked;\n        document.getElementById('opt-' + input.name).textContent = input.checked;\n    }\n\n    return opts;\n}\n\nfunction getParamStringFromOpts(opts) {\n    var params = [];\n\n    for (var prop in opts) {\n        var val = opts[prop];\n\n        if (val !== false) {\n            if (typeof val === 'string' && val.slice(-1) === '%') {\n                val = val.slice(0, -1);\n            }\n\n            params.push(prop + '=' + encodeURIComponent(val));\n        }\n    }\n\n    return params.join('&');\n}\n"
  },
  {
    "path": "site/serve.json",
    "content": "{\n  \"headers\": [\n    {\n      \"source\" : \"index.html\",\n      \"headers\" : [{\n        \"key\" : \"Content-Security-Policy\",\n        \"value\" : \"default-src 'self'; style-src 'self' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; img-src 'self' www.gravatar.com;\"\n      }]\n    }\n  ]\n}\n"
  },
  {
    "path": "spin.css",
    "content": "@keyframes spinner-line-fade-more {\n  0%, 100% {\n    opacity: 0; /* minimum opacity */\n  }\n  1% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-line-fade-quick {\n  0%, 39%, 100% {\n    opacity: 0.25; /* minimum opacity */\n  }\n  40% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-line-fade-default {\n  0%, 100% {\n    opacity: 0.22; /* minimum opacity */\n  }\n  1% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-line-shrink {\n  0%, 25%, 100% {\n    /* minimum scale and opacity */\n    transform: scale(0.5);\n    opacity: 0.25;\n  }\n  26% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n"
  },
  {
    "path": "spin.ts",
    "content": "import { SpinnerOptions } from './SpinnerOptions.js';\nexport { SpinnerOptions } from './SpinnerOptions.js';\n\nconst defaults: Required<SpinnerOptions> = {\n    lines: 12,\n    length: 7,\n    width: 5,\n    radius: 10,\n    scale: 1.0,\n    corners: 1,\n    color: '#000',\n    fadeColor: 'transparent',\n    animation: 'spinner-line-fade-default',\n    rotate: 0,\n    direction: 1,\n    speed: 1,\n    zIndex: 2e9,\n    className: 'spinner',\n    top: '50%',\n    left: '50%',\n    shadow: '0 0 1px transparent', // prevent aliased lines\n    position: 'absolute',\n};\n\nexport class Spinner {\n    private opts: Required<SpinnerOptions>;\n\n    /**\n     * The Spinner's HTML element - can be used to manually insert the spinner into the DOM\n     */\n    public el: HTMLElement | undefined;\n\n    constructor(opts: SpinnerOptions = {}) {\n        this.opts = { ...defaults, ...opts };\n    }\n\n    /**\n     * Adds the spinner to the given target element. If this instance is already\n     * spinning, it is automatically removed from its previous target by calling\n     * stop() internally.\n     */\n    spin(target?: HTMLElement): this {\n        this.stop();\n\n        this.el = document.createElement('div');\n        this.el.className = this.opts.className;\n        this.el.setAttribute('role', 'progressbar');\n\n        this.el.style.position = this.opts.position;\n        this.el.style.width = \"0\";\n        this.el.style.zIndex = this.opts.zIndex.toString();\n        this.el.style.left = this.opts.left;\n        this.el.style.top = this.opts.top;\n        this.el.style.transform = `scale(${this.opts.scale})`;\n\n        if (target) {\n            target.insertBefore(this.el, target.firstChild || null);\n        }\n\n        drawLines(this.el, this.opts);\n\n        return this;\n    }\n\n    /**\n     * Stops and removes the Spinner.\n     * Stopped spinners may be reused by calling spin() again.\n     */\n    stop(): this {\n        if (this.el) {\n            if (this.el.parentNode) {\n                this.el.parentNode.removeChild(this.el);\n            }\n\n            this.el = undefined;\n        }\n\n        return this;\n    }\n}\n\n/**\n * Returns the line color from the given string or array.\n */\nfunction getColor(color: string | string[], idx: number): string {\n    return typeof color == 'string' ? color : color[idx % color.length];\n}\n\n/**\n * Internal method that draws the individual lines.\n */\nfunction drawLines(el: HTMLElement, opts: Required<SpinnerOptions>): void {\n    let borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) + 'px';\n    let shadow = 'none';\n\n    if (opts.shadow === true) {\n        shadow = '0 2px 4px #000'; // default shadow\n    } else if (typeof opts.shadow === 'string') {\n        shadow = opts.shadow;\n    }\n\n    let shadows = parseBoxShadow(shadow);\n\n    for (let i = 0; i < opts.lines; i++) {\n        let degrees = ~~(360 / opts.lines * i + opts.rotate);\n\n        let backgroundLine = document.createElement('div');\n        backgroundLine.style.position = 'absolute';\n        backgroundLine.style.top = `${-opts.width / 2}px`;\n        backgroundLine.style.width = (opts.length + opts.width) + 'px';\n        backgroundLine.style.height = opts.width + 'px';\n        backgroundLine.style.background = getColor(opts.fadeColor, i);\n        backgroundLine.style.borderRadius = borderRadius;\n        backgroundLine.style.transformOrigin = 'left';\n        backgroundLine.style.transform = `rotate(${degrees}deg) translateX(${opts.radius}px)`;\n\n        let delay = i * opts.direction / opts.lines / opts.speed;\n        delay -= 1 / opts.speed; // so initial animation state will include trail\n\n        let line = document.createElement('div');\n        line.style.width = '100%';\n        line.style.height = '100%';\n        line.style.background = getColor(opts.color, i);\n        line.style.borderRadius = borderRadius;\n        line.style.boxShadow = normalizeShadow(shadows, degrees);\n        line.style.animation = `${1 / opts.speed}s linear ${delay}s infinite ${opts.animation}`;\n\n        backgroundLine.appendChild(line);\n        el.appendChild(backgroundLine);\n    }\n}\n\ninterface ParsedShadow {\n    prefix: string,\n    x: number,\n    y: number,\n    xUnits: string,\n    yUnits: string,\n    end: string,\n}\n\nfunction parseBoxShadow(boxShadow: string): ParsedShadow[] {\n    let regex = /^\\s*([a-zA-Z]+\\s+)?(-?\\d+(\\.\\d+)?)([a-zA-Z]*)\\s+(-?\\d+(\\.\\d+)?)([a-zA-Z]*)(.*)$/;\n    let shadows: ParsedShadow[] = [];\n\n    for (let shadow of boxShadow.split(',')) {\n        let matches = shadow.match(regex);\n\n        if (matches === null) {\n            continue; // invalid syntax\n        }\n\n        let x = +matches[2];\n        let y = +matches[5];\n        let xUnits = matches[4];\n        let yUnits = matches[7];\n\n        if (x === 0 && !xUnits) {\n            xUnits = yUnits;\n        }\n\n        if (y === 0 && !yUnits) {\n            yUnits = xUnits;\n        }\n\n        if (xUnits !== yUnits) {\n            continue; // units must match to use as coordinates\n        }\n\n        shadows.push({\n            prefix: matches[1] || '', // could have value of 'inset' or undefined\n            x: x,\n            y: y,\n            xUnits: xUnits,\n            yUnits: yUnits,\n            end: matches[8],\n        });\n    }\n\n    return shadows;\n}\n\n/**\n * Modify box-shadow x/y offsets to counteract rotation\n */\nfunction normalizeShadow(shadows: ParsedShadow[], degrees: number): string {\n    let normalized: string[] = [];\n\n    for (let shadow of shadows) {\n        let xy = convertOffset(shadow.x, shadow.y, degrees);\n        normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] + shadow.yUnits + shadow.end);\n    }\n\n    return normalized.join(', ');\n}\n\nfunction convertOffset(x: number, y: number, degrees: number) {\n    let radians = degrees * Math.PI / 180;\n    let sin = Math.sin(radians);\n    let cos = Math.cos(radians);\n\n    return [\n        Math.round((x * cos + y * sin) * 1000) / 1000,\n        Math.round((-x * sin + y * cos) * 1000) / 1000,\n    ];\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"NodeNext\",\n        \"moduleResolution\": \"NodeNext\",\n        \"target\": \"ES5\",\n        \"forceConsistentCasingInFileNames\": true,\n        \"noUnusedLocals\": true,\n        \"strict\": true,\n        \"declaration\": true\n    },\n    \"files\": [\n        \"spin.ts\"\n    ]\n}\n"
  }
]