[
  {
    "path": ".eslintrc.js",
    "content": "/* eslint-env node */\n\nmodule.exports = {\n  plugins: [ 'metafizzy' ],\n  extends: 'plugin:metafizzy/browser',\n  env: {\n    browser: true,\n    commonjs: true,\n  },\n  parserOptions: {\n    ecmaVersion: 2018,\n  },\n  globals: {\n    Flickity: 'readonly',\n    QUnit: 'readonly',\n  },\n  rules: {\n    'prefer-object-spread': 'error',\n  },\n  ignorePatterns: [ 'bower_components' ],\n};\n"
  },
  {
    "path": ".github/contributing.md",
    "content": "## Submitting issues\n\n### Reduced test case required\n\nAll bug reports and problem issues require a [**reduced test case**](https://css-tricks.com/reduced-test-cases/). Create one by forking any one of the [CodePen demos](https://codepen.io/desandro/pens/tags/?grid_type=list&selected_tag=flickity-docs&sort_order=asc) from [the docs](https://flickity.metafizzy.co).\n\n**CodePens**\n\n+ [Basic](https://codepen.io/desandro/pen/azqbop)\n+ [imagesLoaded](https://codepen.io/desandro/pen/MYQWEe)\n+ [lazyLoad](https://codepen.io/desandro/pen/vOeGzL)\n+ [autoPlay](https://codepen.io/desandro/pen/RNQwaB)\n\n**Test cases**\n\n+ A reduced test case clearly demonstrates the bug or issue.\n+ It contains the bare minimum HTML, CSS, and JavaScript required to demonstrate the bug.\n+ A link to your production site is **not** a reduced test case.\n\nProviding a reduced test case is the best way to get your issue addressed. They help you point out the problem. They help me verify and debug the problem. They help others understand the problem. Without a reduced test case, your issue may be closed.\n\n## Pull requests\n\nContributions are welcome! \n\n+ **For typos and one-line fixes,** send those right in.\n+ **For larger features,** open an issue before starting any significant work. Let's discuss to see how your feature fits within Flickity's vision.\n+ **Follow the code style.** Spaces in brackets, semicolons, trailing commas.\n+ **Do not edit `dist/` files.** Make your edits to source files in `js/` and `css/`.\n+ **Do not run `gulp` to update `dist/` files.** I'll take care of this when I create a new release.\n\nYour code will be used as part of a commercial product if merged. By submitting a Pull Request, you are giving your consent for your code to be integrated into Flickity as part of a commercial product. \n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "<!-- Thanks for submitting an issue! All bug reports and problem issues require a **reduced test case**. Create one by forking any one of the CodePen examples from the docs. See guidelines link above. -->\n\n**Test case:** https://codepen.io/desandro/pen/azqbop\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [16.x]\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - run: npm ci\n    - run: npm run lint\n      env:\n        CI: true\n"
  },
  {
    "path": ".gitignore",
    "content": "bower_components/\nnode_modules/\n/**/browserify/bundle.js\nnotes.md\nsandbox/yoshi-parallax\n"
  },
  {
    "path": ".nvmrc",
    "content": "16"
  },
  {
    "path": "README.md",
    "content": "# Flickity\n\n_Touch, responsive, flickable carousels_\n\nSee [flickity.metafizzy.co](https://flickity.metafizzy.co) for complete docs and demos.\n\n## Install\n\n### Download\n\n+ CSS:\n  - [flickity.min.css](https://unpkg.com/flickity@2/dist/flickity.min.css) minified, or\n  - [flickity.css](https://unpkg.com/flickity@2/dist/flickity.css) un-minified\n+ JavaScript:\n  - [flickity.pkgd.min.js](https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js) minified, or\n  - [flickity.pkgd.js](https://unpkg.com/flickity@2/dist/flickity.pkgd.js) un-minified\n\n### CDN\n\nLink directly to Flickity files on [unpkg](https://unpkg.com).\n\n``` html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/flickity@2/dist/flickity.min.css\">\n```\n\n``` html\n<script src=\"https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js\"></script>\n```\n\n### Package managers\n\nBower: `bower install flickity --save`\n\nnpm: `npm install flickity --save`\n\n## License\n\n### Commercial license\n\nIf you want to use Flickity to develop commercial sites, themes, projects, and applications, the Commercial license is the appropriate license. With this option, your source code is kept proprietary. Purchase a Flickity Commercial License at [flickity.metafizzy.co](https://flickity.metafizzy.co/#commercial-license)\n\n### Open source license\n\nIf you are creating an open source application under a license compatible with the [GNU GPL license v3](https://www.gnu.org/licenses/gpl-3.0.html), you may use Flickity under the terms of the GPLv3.\n\n[Read more about Flickity's license](https://flickity.metafizzy.co/license.html).\n\n## Usage\n\nFlickity works with a container element and a set of child cell elements\n\n``` html\n<div class=\"carousel\">\n  <div class=\"carousel-cell\">...</div>\n  <div class=\"carousel-cell\">...</div>\n  <div class=\"carousel-cell\">...</div>\n  ...\n</div>\n```\n\n### Options\n\n``` js\nvar flky = new Flickity( '.gallery', {\n  // options, defaults listed\n\n  accessibility: true,\n  // enable keyboard navigation, pressing left & right keys\n\n  adaptiveHeight: false,\n  // set carousel height to the selected slide\n\n  autoPlay: false,\n  // advances to the next cell\n  // if true, default is 3 seconds\n  // or set time between advances in milliseconds\n  // i.e. `autoPlay: 1000` will advance every 1 second\n\n  cellAlign: 'center',\n  // alignment of cells, 'center', 'left', or 'right'\n  // or a decimal 0-1, 0 is beginning (left) of container, 1 is end (right)\n\n  cellSelector: undefined,\n  // specify selector for cell elements\n\n  contain: false,\n  // will contain cells to container\n  // so no excess scroll at beginning or end\n  // has no effect if wrapAround is enabled\n\n  draggable: '>1',\n  // enables dragging & flicking\n  // if at least 2 cells\n\n  dragThreshold: 3,\n  // number of pixels a user must scroll horizontally to start dragging\n  // increase to allow more room for vertical scroll for touch devices\n\n  freeScroll: false,\n  // enables content to be freely scrolled and flicked\n  // without aligning cells\n\n  friction: 0.2,\n  // smaller number = easier to flick farther\n\n  groupCells: false,\n  // group cells together in slides\n\n  initialIndex: 0,\n  // zero-based index of the initial selected cell\n\n  lazyLoad: true,\n  // enable lazy-loading images\n  // set img data-flickity-lazyload=\"src.jpg\"\n  // set to number to load images adjacent cells\n\n  percentPosition: true,\n  // sets positioning in percent values, rather than pixels\n  // Enable if items have percent widths\n  // Disable if items have pixel widths, like images\n\n  prevNextButtons: true,\n  // creates and enables buttons to click to previous & next cells\n\n  pageDots: true,\n  // create and enable page dots\n\n  resize: true,\n  // listens to window resize events to adjust size & positions\n\n  rightToLeft: false,\n  // enables right-to-left layout\n\n  setGallerySize: true,\n  // sets the height of gallery\n  // disable if gallery already has height set with CSS\n\n  watchCSS: false,\n  // watches the content of :after of the element\n  // activates if #element:after { content: 'flickity' }\n\n  wrapAround: false\n  // at end of cells, wraps-around to first for infinite scrolling\n\n});\n```\n\n---\n\nBy [Metafizzy 🌈🐻](https://metafizzy.co)\n"
  },
  {
    "path": "bin/.eslintrc.js",
    "content": "module.exports = {\n  plugins: [ 'metafizzy' ],\n  extends: 'plugin:metafizzy/node',\n};\n"
  },
  {
    "path": "bin/bundle-css.js",
    "content": "const CleanCss = require('clean-css');\nconst fs = require('fs');\n\nlet srcCss = fs.readFileSync( 'css/flickity.css', 'utf8' );\nlet minifiedCss = new CleanCss().minify( srcCss ).styles.replace( '*/', '*/\\n' );\nfs.writeFileSync( 'dist/flickity.min.css', minifiedCss );\n"
  },
  {
    "path": "bin/bundle-js.js",
    "content": "const fs = require('fs');\nconst { execSync } = require('child_process');\nconst { minify } = require('terser');\n\nconst indexPath = 'js/index.js';\nconst distPath = 'dist/flickity.pkgd.js';\nconst distMinPath = 'dist/flickity.pkgd.min.js';\n\nlet indexContent = fs.readFileSync( `./${indexPath}`, 'utf8' );\n// get file paths from index.js\nlet jsPaths = indexContent.match( /require\\('([.\\-/\\w]+)'\\)/gi )\n  .map( ( path ) => path.replace( \"require('.\", 'js' ).replace( \"')\", '.js' ) );\n\nlet paths = [\n  'node_modules/jquery-bridget/jquery-bridget.js',\n  'node_modules/ev-emitter/ev-emitter.js',\n  'node_modules/get-size/get-size.js',\n  'node_modules/fizzy-ui-utils/utils.js',\n  'node_modules/unidragger/unidragger.js',\n  'node_modules/imagesloaded/imagesloaded.js',\n  'js/cell.js',\n  'js/slide.js',\n  'js/animate.js',\n  ...jsPaths,\n];\n\n// concatenate files\nexecSync(`cat ${paths.join(' ')} > ${distPath}`);\n\n// add banner\nlet banner = indexContent.split(' */')[0] + ' */\\n\\n';\nbanner = banner.replace( 'Flickity', 'Flickity PACKAGED' );\nlet distJsContent = fs.readFileSync( distPath, 'utf8' );\ndistJsContent = banner + distJsContent;\nfs.writeFileSync( distPath, distJsContent );\n\n// minify\n( async function() {\n  let { code } = await minify( distJsContent, { mangle: true } );\n  fs.writeFileSync( distMinPath, code );\n} )();\n"
  },
  {
    "path": "bin/lint-json.js",
    "content": "require('../package.json');\nrequire('../bower.json');\n"
  },
  {
    "path": "bin/version.js",
    "content": "const fs = require('fs');\nconst version = require('../package.json').version;\n\n[ 'css/flickity.css', 'js/index.js' ].forEach( ( file ) => {\n  let src = fs.readFileSync( file, 'utf8' );\n  src = src.replace( /Flickity v\\d+\\.\\d+\\.\\d+/, `Flickity v${version}` );\n  fs.writeFileSync( file, src, 'utf8' );\n} );\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"flickity\",\n  \"description\": \"Touch, responsive, flickable carousels\",\n  \"main\": [\n    \"js/index.js\",\n    \"css/flickity.css\"\n  ],\n  \"dependencies\": {\n    \"ev-emitter\": \"^2.1.2\",\n    \"fizzy-ui-utils\": \"^3.0.0\",\n    \"get-size\": \"^3.0.0\",\n    \"unidragger\": \"^3.0.1\"\n  },\n  \"devDependencies\": {\n  },\n  \"keywords\": [\n    \"gallery\",\n    \"carousel\",\n    \"touch\"\n  ],\n  \"homepage\": \"https://flickity.metafizzy.co\",\n  \"authors\": [\n    \"Metafizzy\"\n  ],\n  \"license\": \"GPL-3.0\",\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\",\n    \"sandbox\",\n    \"package.json\",\n    \"gulpfile.js\",\n    \"notes.md\"\n  ]\n}\n"
  },
  {
    "path": "css/flickity.css",
    "content": "/*! Flickity v3.0.0\nhttps://flickity.metafizzy.co\n---------------------------------------------- */\n\n.flickity-enabled {\n  position: relative;\n}\n\n.flickity-enabled:focus { outline: none; }\n\n.flickity-viewport {\n  overflow: hidden;\n  position: relative;\n  height: 100%;\n  touch-action: pan-y;\n}\n\n.flickity-slider {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  left: 0;\n}\n\n.flickity-rtl .flickity-slider {\n  left: unset;\n  right: 0;\n}\n\n/* draggable */\n\n.flickity-enabled.is-draggable {\n  -webkit-tap-highlight-color: transparent;\n  user-select: none;\n}\n\n.flickity-enabled.is-draggable .flickity-viewport {\n  cursor: move;\n  cursor: grab;\n}\n\n.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down {\n  cursor: grabbing;\n}\n\n/* ---- flickity-cell ---- */\n\n.flickity-cell {\n  position: absolute;\n  left: 0;\n}\n\n.flickity-rtl .flickity-cell {\n  left: unset;\n  right: 0;\n}\n\n/* ---- flickity-button ---- */\n\n.flickity-button {\n  position: absolute;\n  background: hsla(0, 0%, 100%, 75%);\n  border: none;\n  color: hsl(0, 0%, 20%);\n}\n\n.flickity-button:hover {\n  background: white;\n  cursor: pointer;\n}\n\n.flickity-button:focus {\n  outline: none;\n  box-shadow: 0 0 0 5px #19F;\n}\n\n.flickity-button:active {\n  color: #19F;\n}\n\n.flickity-button:disabled {\n  opacity: 0.3;\n  cursor: auto;\n  /* prevent disabled button from capturing pointer up event. #716 */\n  pointer-events: none;\n}\n\n.flickity-button-icon {\n  fill: currentcolor;\n}\n\n/* ---- previous/next buttons ---- */\n\n.flickity-prev-next-button {\n  top: 50%;\n  width: 44px;\n  height: 44px;\n  z-index: 1; /* above viewport */\n  border-radius: 50%;\n  /* vertically center */\n  transform: translateY(-50%);\n}\n\n.flickity-prev-next-button.previous { left: 10px; }\n.flickity-prev-next-button.next { right: 10px; }\n/* right to left */\n.flickity-rtl .flickity-prev-next-button.previous {\n  left: auto;\n  right: 10px;\n}\n\n.flickity-rtl .flickity-prev-next-button.next {\n  right: auto;\n  left: 10px;\n}\n\n.flickity-prev-next-button .flickity-button-icon {\n  position: absolute;\n  left: 20%;\n  top: 20%;\n  width: 60%;\n  height: 60%;\n}\n\n/* ---- page dots ---- */\n\n.flickity-page-dots {\n  position: absolute;\n  width: 100%;\n  bottom: -25px;\n  z-index: 1; /* above viewport */\n  text-align: center;\n  display: flex;\n  justify-content: center;\n  flex-wrap: wrap;\n}\n\n.flickity-rtl .flickity-page-dots { direction: rtl; }\n\n.flickity-page-dot {\n  position: relative;\n  display: block;\n  width: 10px;\n  height: 10px;\n  padding: 0;\n  margin: 0 8px;\n  background: hsl(0, 0%, 20%, 25%);\n  border-radius: 50%;\n  cursor: pointer;\n  appearance: none;\n  border: none;\n  text-indent: -9999px;\n  overflow: hidden;\n}\n\n.flickity-rtl .flickity-page-dot {\n  text-indent: 9999px;\n}\n\n.flickity-page-dot:hover {\n  background: hsla(0, 0%, 20%, 75%);\n}\n\n.flickity-page-dot:active {\n  background: #19F;\n}\n\n.flickity-page-dot.is-selected {\n  background: hsl(0, 0%, 20%);\n}\n"
  },
  {
    "path": "dist/flickity.css",
    "content": "/*! Flickity v3.0.0\nhttps://flickity.metafizzy.co\n---------------------------------------------- */\n\n.flickity-enabled {\n  position: relative;\n}\n\n.flickity-enabled:focus { outline: none; }\n\n.flickity-viewport {\n  overflow: hidden;\n  position: relative;\n  height: 100%;\n  touch-action: pan-y;\n}\n\n.flickity-slider {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  left: 0;\n}\n\n.flickity-rtl .flickity-slider {\n  left: unset;\n  right: 0;\n}\n\n/* draggable */\n\n.flickity-enabled.is-draggable {\n  -webkit-tap-highlight-color: transparent;\n  user-select: none;\n}\n\n.flickity-enabled.is-draggable .flickity-viewport {\n  cursor: move;\n  cursor: grab;\n}\n\n.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down {\n  cursor: grabbing;\n}\n\n/* ---- flickity-cell ---- */\n\n.flickity-cell {\n  position: absolute;\n  left: 0;\n}\n\n.flickity-rtl .flickity-cell {\n  left: unset;\n  right: 0;\n}\n\n/* ---- flickity-button ---- */\n\n.flickity-button {\n  position: absolute;\n  background: hsl(0 0% 100% / 75%);\n  border: none;\n  color: #333;\n}\n\n.flickity-button:hover {\n  background: white;\n  cursor: pointer;\n}\n\n.flickity-button:focus {\n  outline: none;\n  box-shadow: 0 0 0 5px #19F;\n}\n\n.flickity-button:active {\n  opacity: 0.6;\n}\n\n.flickity-button:disabled {\n  opacity: 0.3;\n  cursor: auto;\n  /* prevent disabled button from capturing pointer up event. #716 */\n  pointer-events: none;\n}\n\n.flickity-button-icon {\n  fill: currentColor;\n}\n\n/* ---- previous/next buttons ---- */\n\n.flickity-prev-next-button {\n  top: 50%;\n  width: 44px;\n  height: 44px;\n  border-radius: 50%;\n  /* vertically center */\n  transform: translateY(-50%);\n}\n\n.flickity-prev-next-button.previous { left: 10px; }\n.flickity-prev-next-button.next { right: 10px; }\n/* right to left */\n.flickity-rtl .flickity-prev-next-button.previous {\n  left: auto;\n  right: 10px;\n}\n\n.flickity-rtl .flickity-prev-next-button.next {\n  right: auto;\n  left: 10px;\n}\n\n.flickity-prev-next-button .flickity-button-icon {\n  position: absolute;\n  left: 20%;\n  top: 20%;\n  width: 60%;\n  height: 60%;\n}\n\n/* ---- page dots ---- */\n\n.flickity-page-dots {\n  position: absolute;\n  width: 100%;\n  bottom: -25px;\n  text-align: center;\n  display: flex;\n  justify-content: center;\n  flex-wrap: wrap;\n}\n\n.flickity-rtl .flickity-page-dots { direction: rtl; }\n\n.flickity-page-dot {\n  display: block;\n  width: 10px;\n  height: 10px;\n  padding: 0;\n  margin: 0 8px;\n  background: hsl(0 0% 20% / 25%);\n  border-radius: 50%;\n  cursor: pointer;\n  appearance: none;\n  border: none;\n  text-indent: -9999px;\n  overflow: hidden;\n}\n\n.flickity-rtl .flickity-page-dot {\n  text-indent: 9999px;\n}\n\n.flickity-page-dot:focus {\n  outline: none;\n  box-shadow: 0 0 0 5px #19F;\n}\n\n.flickity-page-dot.is-selected {\n  background: hsl(0 0% 20% / 100%);\n}\n"
  },
  {
    "path": "dist/flickity.pkgd.js",
    "content": "/*!\n * Flickity PACKAGED v3.0.0\n * Touch, responsive, flickable carousels\n *\n * Licensed GPLv3 for open source use\n * or Flickity Commercial License for commercial use\n *\n * https://flickity.metafizzy.co\n * Copyright 2015-2022 Metafizzy\n */\n\n/**\n * Bridget makes jQuery widgets\n * v3.0.1\n * MIT license\n */\n\n( function( window, factory ) {\n  // module definition\n if ( typeof module == 'object' && module.exports ) {\n   // CommonJS\n   module.exports = factory(\n       window,\n       require('jquery'),\n   );\n } else {\n   // browser global\n   window.jQueryBridget = factory(\n       window,\n       window.jQuery,\n   );\n }\n\n}( window, function factory( window, jQuery ) {\n\n// ----- utils ----- //\n\n// helper function for logging errors\n// $.error breaks jQuery chaining\nlet console = window.console;\nlet logError = typeof console == 'undefined' ? function() {} :\n  function( message ) {\n    console.error( message );\n  };\n\n// ----- jQueryBridget ----- //\n\nfunction jQueryBridget( namespace, PluginClass, $ ) {\n  $ = $ || jQuery || window.jQuery;\n  if ( !$ ) {\n    return;\n  }\n\n  // add option method -> $().plugin('option', {...})\n  if ( !PluginClass.prototype.option ) {\n    // option setter\n    PluginClass.prototype.option = function( opts ) {\n      if ( !opts ) return;\n\n      this.options = Object.assign( this.options || {}, opts );\n    };\n  }\n\n  // make jQuery plugin\n  $.fn[ namespace ] = function( arg0, ...args ) {\n    if ( typeof arg0 == 'string' ) {\n      // method call $().plugin( 'methodName', { options } )\n      return methodCall( this, arg0, args );\n    }\n    // just $().plugin({ options })\n    plainCall( this, arg0 );\n    return this;\n  };\n\n  // $().plugin('methodName')\n  function methodCall( $elems, methodName, args ) {\n    let returnValue;\n    let pluginMethodStr = `$().${namespace}(\"${methodName}\")`;\n\n    $elems.each( function( i, elem ) {\n      // get instance\n      let instance = $.data( elem, namespace );\n      if ( !instance ) {\n        logError( `${namespace} not initialized.` +\n          ` Cannot call method ${pluginMethodStr}` );\n        return;\n      }\n\n      let method = instance[ methodName ];\n      if ( !method || methodName.charAt( 0 ) == '_' ) {\n        logError(`${pluginMethodStr} is not a valid method`);\n        return;\n      }\n\n      // apply method, get return value\n      let value = method.apply( instance, args );\n      // set return value if value is returned, use only first value\n      returnValue = returnValue === undefined ? value : returnValue;\n    } );\n\n    return returnValue !== undefined ? returnValue : $elems;\n  }\n\n  function plainCall( $elems, options ) {\n    $elems.each( function( i, elem ) {\n      let instance = $.data( elem, namespace );\n      if ( instance ) {\n        // set options & init\n        instance.option( options );\n        instance._init();\n      } else {\n        // initialize new instance\n        instance = new PluginClass( elem, options );\n        $.data( elem, namespace, instance );\n      }\n    } );\n  }\n\n}\n\n// -----  ----- //\n\nreturn jQueryBridget;\n\n} ) );\n/**\n * EvEmitter v2.1.1\n * Lil' event emitter\n * MIT License\n */\n\n( function( global, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS - Browserify, Webpack\n    module.exports = factory();\n  } else {\n    // Browser globals\n    global.EvEmitter = factory();\n  }\n\n}( typeof window != 'undefined' ? window : this, function() {\n\nfunction EvEmitter() {}\n\nlet proto = EvEmitter.prototype;\n\nproto.on = function( eventName, listener ) {\n  if ( !eventName || !listener ) return this;\n\n  // set events hash\n  let events = this._events = this._events || {};\n  // set listeners array\n  let listeners = events[ eventName ] = events[ eventName ] || [];\n  // only add once\n  if ( !listeners.includes( listener ) ) {\n    listeners.push( listener );\n  }\n\n  return this;\n};\n\nproto.once = function( eventName, listener ) {\n  if ( !eventName || !listener ) return this;\n\n  // add event\n  this.on( eventName, listener );\n  // set once flag\n  // set onceEvents hash\n  let onceEvents = this._onceEvents = this._onceEvents || {};\n  // set onceListeners object\n  let onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};\n  // set flag\n  onceListeners[ listener ] = true;\n\n  return this;\n};\n\nproto.off = function( eventName, listener ) {\n  let listeners = this._events && this._events[ eventName ];\n  if ( !listeners || !listeners.length ) return this;\n\n  let index = listeners.indexOf( listener );\n  if ( index != -1 ) {\n    listeners.splice( index, 1 );\n  }\n\n  return this;\n};\n\nproto.emitEvent = function( eventName, args ) {\n  let listeners = this._events && this._events[ eventName ];\n  if ( !listeners || !listeners.length ) return this;\n\n  // copy over to avoid interference if .off() in listener\n  listeners = listeners.slice( 0 );\n  args = args || [];\n  // once stuff\n  let onceListeners = this._onceEvents && this._onceEvents[ eventName ];\n\n  for ( let listener of listeners ) {\n    let isOnce = onceListeners && onceListeners[ listener ];\n    if ( isOnce ) {\n      // remove listener\n      // remove before trigger to prevent recursion\n      this.off( eventName, listener );\n      // unset once flag\n      delete onceListeners[ listener ];\n    }\n    // trigger listener\n    listener.apply( this, args );\n  }\n\n  return this;\n};\n\nproto.allOff = function() {\n  delete this._events;\n  delete this._onceEvents;\n  return this;\n};\n\nreturn EvEmitter;\n\n} ) );\n/*!\n * Infinite Scroll v2.0.4\n * measure size of elements\n * MIT license\n */\n\n( function( window, factory ) {\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory();\n  } else {\n    // browser global\n    window.getSize = factory();\n  }\n\n} )( window, function factory() {\n\n// -------------------------- helpers -------------------------- //\n\n// get a number from a string, not a percentage\nfunction getStyleSize( value ) {\n  let num = parseFloat( value );\n  // not a percent like '100%', and a number\n  let isValid = value.indexOf('%') == -1 && !isNaN( num );\n  return isValid && num;\n}\n\n// -------------------------- measurements -------------------------- //\n\nlet measurements = [\n  'paddingLeft',\n  'paddingRight',\n  'paddingTop',\n  'paddingBottom',\n  'marginLeft',\n  'marginRight',\n  'marginTop',\n  'marginBottom',\n  'borderLeftWidth',\n  'borderRightWidth',\n  'borderTopWidth',\n  'borderBottomWidth',\n];\n\nlet measurementsLength = measurements.length;\n\nfunction getZeroSize() {\n  let size = {\n    width: 0,\n    height: 0,\n    innerWidth: 0,\n    innerHeight: 0,\n    outerWidth: 0,\n    outerHeight: 0,\n  };\n  measurements.forEach( ( measurement ) => {\n    size[ measurement ] = 0;\n  } );\n  return size;\n}\n\n// -------------------------- getSize -------------------------- //\n\nfunction getSize( elem ) {\n  // use querySeletor if elem is string\n  if ( typeof elem == 'string' ) elem = document.querySelector( elem );\n\n  // do not proceed on non-objects\n  let isElement = elem && typeof elem == 'object' && elem.nodeType;\n  if ( !isElement ) return;\n\n  let style = getComputedStyle( elem );\n\n  // if hidden, everything is 0\n  if ( style.display == 'none' ) return getZeroSize();\n\n  let size = {};\n  size.width = elem.offsetWidth;\n  size.height = elem.offsetHeight;\n\n  let isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';\n\n  // get all measurements\n  measurements.forEach( ( measurement ) => {\n    let value = style[ measurement ];\n    let num = parseFloat( value );\n    // any 'auto', 'medium' value will be 0\n    size[ measurement ] = !isNaN( num ) ? num : 0;\n  } );\n\n  let paddingWidth = size.paddingLeft + size.paddingRight;\n  let paddingHeight = size.paddingTop + size.paddingBottom;\n  let marginWidth = size.marginLeft + size.marginRight;\n  let marginHeight = size.marginTop + size.marginBottom;\n  let borderWidth = size.borderLeftWidth + size.borderRightWidth;\n  let borderHeight = size.borderTopWidth + size.borderBottomWidth;\n\n  // overwrite width and height if we can get it from style\n  let styleWidth = getStyleSize( style.width );\n  if ( styleWidth !== false ) {\n    size.width = styleWidth +\n      // add padding and border unless it's already including it\n      ( isBorderBox ? 0 : paddingWidth + borderWidth );\n  }\n\n  let styleHeight = getStyleSize( style.height );\n  if ( styleHeight !== false ) {\n    size.height = styleHeight +\n      // add padding and border unless it's already including it\n      ( isBorderBox ? 0 : paddingHeight + borderHeight );\n  }\n\n  size.innerWidth = size.width - ( paddingWidth + borderWidth );\n  size.innerHeight = size.height - ( paddingHeight + borderHeight );\n\n  size.outerWidth = size.width + marginWidth;\n  size.outerHeight = size.height + marginHeight;\n\n  return size;\n}\n\nreturn getSize;\n\n} );\n/**\n * Fizzy UI utils v3.0.0\n * MIT license\n */\n\n( function( global, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( global );\n  } else {\n    // browser global\n    global.fizzyUIUtils = factory( global );\n  }\n\n}( this, function factory( global ) {\n\nlet utils = {};\n\n// ----- extend ----- //\n\n// extends objects\nutils.extend = function( a, b ) {\n  return Object.assign( a, b );\n};\n\n// ----- modulo ----- //\n\nutils.modulo = function( num, div ) {\n  return ( ( num % div ) + div ) % div;\n};\n\n// ----- makeArray ----- //\n\n// turn element or nodeList into an array\nutils.makeArray = function( obj ) {\n  // use object if already an array\n  if ( Array.isArray( obj ) ) return obj;\n\n  // return empty array if undefined or null. #6\n  if ( obj === null || obj === undefined ) return [];\n\n  let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';\n  // convert nodeList to array\n  if ( isArrayLike ) return [ ...obj ];\n\n  // array of single index\n  return [ obj ];\n};\n\n// ----- removeFrom ----- //\n\nutils.removeFrom = function( ary, obj ) {\n  let index = ary.indexOf( obj );\n  if ( index != -1 ) {\n    ary.splice( index, 1 );\n  }\n};\n\n// ----- getParent ----- //\n\nutils.getParent = function( elem, selector ) {\n  while ( elem.parentNode && elem != document.body ) {\n    elem = elem.parentNode;\n    if ( elem.matches( selector ) ) return elem;\n  }\n};\n\n// ----- getQueryElement ----- //\n\n// use element as selector string\nutils.getQueryElement = function( elem ) {\n  if ( typeof elem == 'string' ) {\n    return document.querySelector( elem );\n  }\n  return elem;\n};\n\n// ----- handleEvent ----- //\n\n// enable .ontype to trigger from .addEventListener( elem, 'type' )\nutils.handleEvent = function( event ) {\n  let method = 'on' + event.type;\n  if ( this[ method ] ) {\n    this[ method ]( event );\n  }\n};\n\n// ----- filterFindElements ----- //\n\nutils.filterFindElements = function( elems, selector ) {\n  // make array of elems\n  elems = utils.makeArray( elems );\n\n  return elems\n    // check that elem is an actual element\n    .filter( ( elem ) => elem instanceof HTMLElement )\n    .reduce( ( ffElems, elem ) => {\n      // add elem if no selector\n      if ( !selector ) {\n        ffElems.push( elem );\n        return ffElems;\n      }\n      // filter & find items if we have a selector\n      // filter\n      if ( elem.matches( selector ) ) {\n        ffElems.push( elem );\n      }\n      // find children\n      let childElems = elem.querySelectorAll( selector );\n      // concat childElems to filterFound array\n      ffElems = ffElems.concat( ...childElems );\n      return ffElems;\n    }, [] );\n};\n\n// ----- debounceMethod ----- //\n\nutils.debounceMethod = function( _class, methodName, threshold ) {\n  threshold = threshold || 100;\n  // original method\n  let method = _class.prototype[ methodName ];\n  let timeoutName = methodName + 'Timeout';\n\n  _class.prototype[ methodName ] = function() {\n    clearTimeout( this[ timeoutName ] );\n\n    let args = arguments;\n    this[ timeoutName ] = setTimeout( () => {\n      method.apply( this, args );\n      delete this[ timeoutName ];\n    }, threshold );\n  };\n};\n\n// ----- docReady ----- //\n\nutils.docReady = function( onDocReady ) {\n  let readyState = document.readyState;\n  if ( readyState == 'complete' || readyState == 'interactive' ) {\n    // do async to allow for other scripts to run. metafizzy/flickity#441\n    setTimeout( onDocReady );\n  } else {\n    document.addEventListener( 'DOMContentLoaded', onDocReady );\n  }\n};\n\n// ----- htmlInit ----- //\n\n// http://bit.ly/3oYLusc\nutils.toDashed = function( str ) {\n  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {\n    return $1 + '-' + $2;\n  } ).toLowerCase();\n};\n\nlet console = global.console;\n\n// allow user to initialize classes via [data-namespace] or .js-namespace class\n// htmlInit( Widget, 'widgetName' )\n// options are parsed from data-namespace-options\nutils.htmlInit = function( WidgetClass, namespace ) {\n  utils.docReady( function() {\n    let dashedNamespace = utils.toDashed( namespace );\n    let dataAttr = 'data-' + dashedNamespace;\n    let dataAttrElems = document.querySelectorAll( `[${dataAttr}]` );\n    let jQuery = global.jQuery;\n\n    [ ...dataAttrElems ].forEach( ( elem ) => {\n      let attr = elem.getAttribute( dataAttr );\n      let options;\n      try {\n        options = attr && JSON.parse( attr );\n      } catch ( error ) {\n        // log error, do not initialize\n        if ( console ) {\n          console.error( `Error parsing ${dataAttr} on ${elem.className}: ${error}` );\n        }\n        return;\n      }\n      // initialize\n      let instance = new WidgetClass( elem, options );\n      // make available via $().data('namespace')\n      if ( jQuery ) {\n        jQuery.data( elem, namespace, instance );\n      }\n    } );\n\n  } );\n};\n\n// -----  ----- //\n\nreturn utils;\n\n} ) );\n/*!\n * Unidragger v3.0.0\n * Draggable base class\n * MIT license\n */\n\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        window,\n        require('ev-emitter'),\n    );\n  } else {\n    // browser global\n    window.Unidragger = factory(\n        window,\n        window.EvEmitter,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( window, EvEmitter ) {\n\nfunction Unidragger() {}\n\n// inherit EvEmitter\nlet proto = Unidragger.prototype = Object.create( EvEmitter.prototype );\n\n// ----- bind start ----- //\n\n// trigger handler methods for events\nproto.handleEvent = function( event ) {\n  let method = 'on' + event.type;\n  if ( this[ method ] ) {\n    this[ method ]( event );\n  }\n};\n\nlet startEvent, activeEvents;\nif ( 'ontouchstart' in window ) {\n  // HACK prefer Touch Events as you can preventDefault on touchstart to\n  // disable scroll in iOS & mobile Chrome metafizzy/flickity#1177\n  startEvent = 'touchstart';\n  activeEvents = [ 'touchmove', 'touchend', 'touchcancel' ];\n} else if ( window.PointerEvent ) {\n  // Pointer Events\n  startEvent = 'pointerdown';\n  activeEvents = [ 'pointermove', 'pointerup', 'pointercancel' ];\n} else {\n  // mouse events\n  startEvent = 'mousedown';\n  activeEvents = [ 'mousemove', 'mouseup' ];\n}\n\n// prototype so it can be overwriteable by Flickity\nproto.touchActionValue = 'none';\n\nproto.bindHandles = function() {\n  this._bindHandles( 'addEventListener', this.touchActionValue );\n};\n\nproto.unbindHandles = function() {\n  this._bindHandles( 'removeEventListener', '' );\n};\n\n/**\n * Add or remove start event\n * @param {String} bindMethod - addEventListener or removeEventListener\n * @param {String} touchAction - value for touch-action CSS property\n */\nproto._bindHandles = function( bindMethod, touchAction ) {\n  this.handles.forEach( ( handle ) => {\n    handle[ bindMethod ]( startEvent, this );\n    handle[ bindMethod ]( 'click', this );\n    // touch-action: none to override browser touch gestures. metafizzy/flickity#540\n    if ( window.PointerEvent ) handle.style.touchAction = touchAction;\n  } );\n};\n\nproto.bindActivePointerEvents = function() {\n  activeEvents.forEach( ( eventName ) => {\n    window.addEventListener( eventName, this );\n  } );\n};\n\nproto.unbindActivePointerEvents = function() {\n  activeEvents.forEach( ( eventName ) => {\n    window.removeEventListener( eventName, this );\n  } );\n};\n\n// ----- event handler helpers ----- //\n\n// trigger method with matching pointer\nproto.withPointer = function( methodName, event ) {\n  if ( event.pointerId == this.pointerIdentifier ) {\n    this[ methodName ]( event, event );\n  }\n};\n\n// trigger method with matching touch\nproto.withTouch = function( methodName, event ) {\n  let touch;\n  for ( let changedTouch of event.changedTouches ) {\n    if ( changedTouch.identifier == this.pointerIdentifier ) {\n      touch = changedTouch;\n    }\n  }\n  if ( touch ) this[ methodName ]( event, touch );\n};\n\n// ----- start event ----- //\n\nproto.onmousedown = function( event ) {\n  this.pointerDown( event, event );\n};\n\nproto.ontouchstart = function( event ) {\n  this.pointerDown( event, event.changedTouches[0] );\n};\n\nproto.onpointerdown = function( event ) {\n  this.pointerDown( event, event );\n};\n\n// nodes that have text fields\nconst cursorNodes = [ 'TEXTAREA', 'INPUT', 'SELECT', 'OPTION' ];\n// input types that do not have text fields\nconst clickTypes = [ 'radio', 'checkbox', 'button', 'submit', 'image', 'file' ];\n\n/**\n * any time you set `event, pointer` it refers to:\n * @param {Event} event\n * @param {Event | Touch} pointer\n */\nproto.pointerDown = function( event, pointer ) {\n  // dismiss multi-touch taps, right clicks, and clicks on text fields\n  let isCursorNode = cursorNodes.includes( event.target.nodeName );\n  let isClickType = clickTypes.includes( event.target.type );\n  let isOkayElement = !isCursorNode || isClickType;\n  let isOkay = !this.isPointerDown && !event.button && isOkayElement;\n  if ( !isOkay ) return;\n\n  this.isPointerDown = true;\n  // save pointer identifier to match up touch events\n  this.pointerIdentifier = pointer.pointerId !== undefined ?\n    // pointerId for pointer events, touch.indentifier for touch events\n    pointer.pointerId : pointer.identifier;\n  // track position for move\n  this.pointerDownPointer = {\n    pageX: pointer.pageX,\n    pageY: pointer.pageY,\n  };\n\n  this.bindActivePointerEvents();\n  this.emitEvent( 'pointerDown', [ event, pointer ] );\n};\n\n// ----- move ----- //\n\nproto.onmousemove = function( event ) {\n  this.pointerMove( event, event );\n};\n\nproto.onpointermove = function( event ) {\n  this.withPointer( 'pointerMove', event );\n};\n\nproto.ontouchmove = function( event ) {\n  this.withTouch( 'pointerMove', event );\n};\n\nproto.pointerMove = function( event, pointer ) {\n  let moveVector = {\n    x: pointer.pageX - this.pointerDownPointer.pageX,\n    y: pointer.pageY - this.pointerDownPointer.pageY,\n  };\n  this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );\n  // start drag if pointer has moved far enough to start drag\n  let isDragStarting = !this.isDragging && this.hasDragStarted( moveVector );\n  if ( isDragStarting ) this.dragStart( event, pointer );\n  if ( this.isDragging ) this.dragMove( event, pointer, moveVector );\n};\n\n// condition if pointer has moved far enough to start drag\nproto.hasDragStarted = function( moveVector ) {\n  return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;\n};\n\n// ----- drag ----- //\n\nproto.dragStart = function( event, pointer ) {\n  this.isDragging = true;\n  this.isPreventingClicks = true; // set flag to prevent clicks\n  this.emitEvent( 'dragStart', [ event, pointer ] );\n};\n\nproto.dragMove = function( event, pointer, moveVector ) {\n  this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );\n};\n\n// ----- end ----- //\n\nproto.onmouseup = function( event ) {\n  this.pointerUp( event, event );\n};\n\nproto.onpointerup = function( event ) {\n  this.withPointer( 'pointerUp', event );\n};\n\nproto.ontouchend = function( event ) {\n  this.withTouch( 'pointerUp', event );\n};\n\nproto.pointerUp = function( event, pointer ) {\n  this.pointerDone();\n  this.emitEvent( 'pointerUp', [ event, pointer ] );\n\n  if ( this.isDragging ) {\n    this.dragEnd( event, pointer );\n  } else {\n    // pointer didn't move enough for drag to start\n    this.staticClick( event, pointer );\n  }\n};\n\nproto.dragEnd = function( event, pointer ) {\n  this.isDragging = false; // reset flag\n  // re-enable clicking async\n  setTimeout( () => delete this.isPreventingClicks );\n\n  this.emitEvent( 'dragEnd', [ event, pointer ] );\n};\n\n// triggered on pointer up & pointer cancel\nproto.pointerDone = function() {\n  this.isPointerDown = false;\n  delete this.pointerIdentifier;\n  this.unbindActivePointerEvents();\n  this.emitEvent('pointerDone');\n};\n\n// ----- cancel ----- //\n\nproto.onpointercancel = function( event ) {\n  this.withPointer( 'pointerCancel', event );\n};\n\nproto.ontouchcancel = function( event ) {\n  this.withTouch( 'pointerCancel', event );\n};\n\nproto.pointerCancel = function( event, pointer ) {\n  this.pointerDone();\n  this.emitEvent( 'pointerCancel', [ event, pointer ] );\n};\n\n// ----- click ----- //\n\n// handle all clicks and prevent clicks when dragging\nproto.onclick = function( event ) {\n  if ( this.isPreventingClicks ) event.preventDefault();\n};\n\n// triggered after pointer down & up with no/tiny movement\nproto.staticClick = function( event, pointer ) {\n  // ignore emulated mouse up clicks\n  let isMouseup = event.type == 'mouseup';\n  if ( isMouseup && this.isIgnoringMouseUp ) return;\n\n  this.emitEvent( 'staticClick', [ event, pointer ] );\n\n  // set flag for emulated clicks 300ms after touchend\n  if ( isMouseup ) {\n    this.isIgnoringMouseUp = true;\n    // reset flag after 400ms\n    setTimeout( () => {\n      delete this.isIgnoringMouseUp;\n    }, 400 );\n  }\n};\n\n// -----  ----- //\n\nreturn Unidragger;\n\n} ) );\n/*!\n * imagesLoaded v5.0.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( window, require('ev-emitter') );\n  } else {\n    // browser global\n    window.imagesLoaded = factory( window, window.EvEmitter );\n  }\n\n} )( typeof window !== 'undefined' ? window : this,\n    function factory( window, EvEmitter ) {\n\nlet $ = window.jQuery;\nlet console = window.console;\n\n// -------------------------- helpers -------------------------- //\n\n// turn element or nodeList into an array\nfunction makeArray( obj ) {\n  // use object if already an array\n  if ( Array.isArray( obj ) ) return obj;\n\n  let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';\n  // convert nodeList to array\n  if ( isArrayLike ) return [ ...obj ];\n\n  // array of single index\n  return [ obj ];\n}\n\n// -------------------------- imagesLoaded -------------------------- //\n\n/**\n * @param {[Array, Element, NodeList, String]} elem\n * @param {[Object, Function]} options - if function, use as callback\n * @param {Function} onAlways - callback function\n * @returns {ImagesLoaded}\n */\nfunction ImagesLoaded( elem, options, onAlways ) {\n  // coerce ImagesLoaded() without new, to be new ImagesLoaded()\n  if ( !( this instanceof ImagesLoaded ) ) {\n    return new ImagesLoaded( elem, options, onAlways );\n  }\n  // use elem as selector string\n  let queryElem = elem;\n  if ( typeof elem == 'string' ) {\n    queryElem = document.querySelectorAll( elem );\n  }\n  // bail if bad element\n  if ( !queryElem ) {\n    console.error(`Bad element for imagesLoaded ${queryElem || elem}`);\n    return;\n  }\n\n  this.elements = makeArray( queryElem );\n  this.options = {};\n  // shift arguments if no options set\n  if ( typeof options == 'function' ) {\n    onAlways = options;\n  } else {\n    Object.assign( this.options, options );\n  }\n\n  if ( onAlways ) this.on( 'always', onAlways );\n\n  this.getImages();\n  // add jQuery Deferred object\n  if ( $ ) this.jqDeferred = new $.Deferred();\n\n  // HACK check async to allow time to bind listeners\n  setTimeout( this.check.bind( this ) );\n}\n\nImagesLoaded.prototype = Object.create( EvEmitter.prototype );\n\nImagesLoaded.prototype.getImages = function() {\n  this.images = [];\n\n  // filter & find items if we have an item selector\n  this.elements.forEach( this.addElementImages, this );\n};\n\nconst elementNodeTypes = [ 1, 9, 11 ];\n\n/**\n * @param {Node} elem\n */\nImagesLoaded.prototype.addElementImages = function( elem ) {\n  // filter siblings\n  if ( elem.nodeName === 'IMG' ) {\n    this.addImage( elem );\n  }\n  // get background image on element\n  if ( this.options.background === true ) {\n    this.addElementBackgroundImages( elem );\n  }\n\n  // find children\n  // no non-element nodes, #143\n  let { nodeType } = elem;\n  if ( !nodeType || !elementNodeTypes.includes( nodeType ) ) return;\n\n  let childImgs = elem.querySelectorAll('img');\n  // concat childElems to filterFound array\n  for ( let img of childImgs ) {\n    this.addImage( img );\n  }\n\n  // get child background images\n  if ( typeof this.options.background == 'string' ) {\n    let children = elem.querySelectorAll( this.options.background );\n    for ( let child of children ) {\n      this.addElementBackgroundImages( child );\n    }\n  }\n};\n\nconst reURL = /url\\((['\"])?(.*?)\\1\\)/gi;\n\nImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {\n  let style = getComputedStyle( elem );\n  // Firefox returns null if in a hidden iframe https://bugzil.la/548397\n  if ( !style ) return;\n\n  // get url inside url(\"...\")\n  let matches = reURL.exec( style.backgroundImage );\n  while ( matches !== null ) {\n    let url = matches && matches[2];\n    if ( url ) {\n      this.addBackground( url, elem );\n    }\n    matches = reURL.exec( style.backgroundImage );\n  }\n};\n\n/**\n * @param {Image} img\n */\nImagesLoaded.prototype.addImage = function( img ) {\n  let loadingImage = new LoadingImage( img );\n  this.images.push( loadingImage );\n};\n\nImagesLoaded.prototype.addBackground = function( url, elem ) {\n  let background = new Background( url, elem );\n  this.images.push( background );\n};\n\nImagesLoaded.prototype.check = function() {\n  this.progressedCount = 0;\n  this.hasAnyBroken = false;\n  // complete if no images\n  if ( !this.images.length ) {\n    this.complete();\n    return;\n  }\n\n  /* eslint-disable-next-line func-style */\n  let onProgress = ( image, elem, message ) => {\n    // HACK - Chrome triggers event before object properties have changed. #83\n    setTimeout( () => {\n      this.progress( image, elem, message );\n    } );\n  };\n\n  this.images.forEach( function( loadingImage ) {\n    loadingImage.once( 'progress', onProgress );\n    loadingImage.check();\n  } );\n};\n\nImagesLoaded.prototype.progress = function( image, elem, message ) {\n  this.progressedCount++;\n  this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;\n  // progress event\n  this.emitEvent( 'progress', [ this, image, elem ] );\n  if ( this.jqDeferred && this.jqDeferred.notify ) {\n    this.jqDeferred.notify( this, image );\n  }\n  // check if completed\n  if ( this.progressedCount === this.images.length ) {\n    this.complete();\n  }\n\n  if ( this.options.debug && console ) {\n    console.log( `progress: ${message}`, image, elem );\n  }\n};\n\nImagesLoaded.prototype.complete = function() {\n  let eventName = this.hasAnyBroken ? 'fail' : 'done';\n  this.isComplete = true;\n  this.emitEvent( eventName, [ this ] );\n  this.emitEvent( 'always', [ this ] );\n  if ( this.jqDeferred ) {\n    let jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';\n    this.jqDeferred[ jqMethod ]( this );\n  }\n};\n\n// --------------------------  -------------------------- //\n\nfunction LoadingImage( img ) {\n  this.img = img;\n}\n\nLoadingImage.prototype = Object.create( EvEmitter.prototype );\n\nLoadingImage.prototype.check = function() {\n  // If complete is true and browser supports natural sizes,\n  // try to check for image status manually.\n  let isComplete = this.getIsImageComplete();\n  if ( isComplete ) {\n    // report based on naturalWidth\n    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );\n    return;\n  }\n\n  // If none of the checks above matched, simulate loading on detached element.\n  this.proxyImage = new Image();\n  // add crossOrigin attribute. #204\n  if ( this.img.crossOrigin ) {\n    this.proxyImage.crossOrigin = this.img.crossOrigin;\n  }\n  this.proxyImage.addEventListener( 'load', this );\n  this.proxyImage.addEventListener( 'error', this );\n  // bind to image as well for Firefox. #191\n  this.img.addEventListener( 'load', this );\n  this.img.addEventListener( 'error', this );\n  this.proxyImage.src = this.img.currentSrc || this.img.src;\n};\n\nLoadingImage.prototype.getIsImageComplete = function() {\n  // check for non-zero, non-undefined naturalWidth\n  // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671\n  return this.img.complete && this.img.naturalWidth;\n};\n\nLoadingImage.prototype.confirm = function( isLoaded, message ) {\n  this.isLoaded = isLoaded;\n  let { parentNode } = this.img;\n  // emit progress with parent <picture> or self <img>\n  let elem = parentNode.nodeName === 'PICTURE' ? parentNode : this.img;\n  this.emitEvent( 'progress', [ this, elem, message ] );\n};\n\n// ----- events ----- //\n\n// trigger specified handler for event type\nLoadingImage.prototype.handleEvent = function( event ) {\n  let method = 'on' + event.type;\n  if ( this[ method ] ) {\n    this[ method ]( event );\n  }\n};\n\nLoadingImage.prototype.onload = function() {\n  this.confirm( true, 'onload' );\n  this.unbindEvents();\n};\n\nLoadingImage.prototype.onerror = function() {\n  this.confirm( false, 'onerror' );\n  this.unbindEvents();\n};\n\nLoadingImage.prototype.unbindEvents = function() {\n  this.proxyImage.removeEventListener( 'load', this );\n  this.proxyImage.removeEventListener( 'error', this );\n  this.img.removeEventListener( 'load', this );\n  this.img.removeEventListener( 'error', this );\n};\n\n// -------------------------- Background -------------------------- //\n\nfunction Background( url, element ) {\n  this.url = url;\n  this.element = element;\n  this.img = new Image();\n}\n\n// inherit LoadingImage prototype\nBackground.prototype = Object.create( LoadingImage.prototype );\n\nBackground.prototype.check = function() {\n  this.img.addEventListener( 'load', this );\n  this.img.addEventListener( 'error', this );\n  this.img.src = this.url;\n  // check if image is already complete\n  let isComplete = this.getIsImageComplete();\n  if ( isComplete ) {\n    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );\n    this.unbindEvents();\n  }\n};\n\nBackground.prototype.unbindEvents = function() {\n  this.img.removeEventListener( 'load', this );\n  this.img.removeEventListener( 'error', this );\n};\n\nBackground.prototype.confirm = function( isLoaded, message ) {\n  this.isLoaded = isLoaded;\n  this.emitEvent( 'progress', [ this, this.element, message ] );\n};\n\n// -------------------------- jQuery -------------------------- //\n\nImagesLoaded.makeJQueryPlugin = function( jQuery ) {\n  jQuery = jQuery || window.jQuery;\n  if ( !jQuery ) return;\n\n  // set local variable\n  $ = jQuery;\n  // $().imagesLoaded()\n  $.fn.imagesLoaded = function( options, onAlways ) {\n    let instance = new ImagesLoaded( this, options, onAlways );\n    return instance.jqDeferred.promise( $( this ) );\n  };\n};\n// try making plugin\nImagesLoaded.makeJQueryPlugin();\n\n// --------------------------  -------------------------- //\n\nreturn ImagesLoaded;\n\n} );\n// Flickity.Cell\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('get-size') );\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.Cell = factory( window.getSize );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( getSize ) {\n\nconst cellClassName = 'flickity-cell';\n\nfunction Cell( elem ) {\n  this.element = elem;\n  this.element.classList.add( cellClassName );\n\n  this.x = 0;\n  this.unselect();\n}\n\nlet proto = Cell.prototype;\n\nproto.destroy = function() {\n  // reset style\n  this.unselect();\n  this.element.classList.remove( cellClassName );\n  this.element.style.transform = '';\n  this.element.removeAttribute('aria-hidden');\n};\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n};\n\nproto.select = function() {\n  this.element.classList.add('is-selected');\n  this.element.removeAttribute('aria-hidden');\n};\n\nproto.unselect = function() {\n  this.element.classList.remove('is-selected');\n  this.element.setAttribute( 'aria-hidden', 'true' );\n};\n\nproto.remove = function() {\n  this.element.remove();\n};\n\nreturn Cell;\n\n} ) );\n// slide\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory();\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.Slide = factory();\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory() {\n\nfunction Slide( beginMargin, endMargin, cellAlign ) {\n  this.beginMargin = beginMargin;\n  this.endMargin = endMargin;\n  this.cellAlign = cellAlign;\n  this.cells = [];\n  this.outerWidth = 0;\n  this.height = 0;\n}\n\nlet proto = Slide.prototype;\n\nproto.addCell = function( cell ) {\n  this.cells.push( cell );\n  this.outerWidth += cell.size.outerWidth;\n  this.height = Math.max( cell.size.outerHeight, this.height );\n  // first cell stuff\n  if ( this.cells.length === 1 ) {\n    this.x = cell.x; // x comes from first cell\n    this.firstMargin = cell.size[ this.beginMargin ];\n  }\n};\n\nproto.updateTarget = function() {\n  let lastCell = this.getLastCell();\n  let lastMargin = lastCell ? lastCell.size[ this.endMargin ] : 0;\n  let slideWidth = this.outerWidth - ( this.firstMargin + lastMargin );\n  this.target = this.x + this.firstMargin + slideWidth * this.cellAlign;\n};\n\nproto.getLastCell = function() {\n  return this.cells[ this.cells.length - 1 ];\n};\n\nproto.select = function() {\n  this.cells.forEach( ( cell ) => cell.select() );\n};\n\nproto.unselect = function() {\n  this.cells.forEach( ( cell ) => cell.unselect() );\n};\n\nproto.getCellElements = function() {\n  return this.cells.map( ( cell ) => cell.element );\n};\n\nreturn Slide;\n\n} ) );\n// animate\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('fizzy-ui-utils') );\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.animatePrototype = factory( window.fizzyUIUtils );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( utils ) {\n\n// -------------------------- animate -------------------------- //\n\nlet proto = {};\n\nproto.startAnimation = function() {\n  if ( this.isAnimating ) return;\n\n  this.isAnimating = true;\n  this.restingFrames = 0;\n  this.animate();\n};\n\nproto.animate = function() {\n  this.applyDragForce();\n  this.applySelectedAttraction();\n\n  let previousX = this.x;\n\n  this.integratePhysics();\n  this.positionSlider();\n  this.settle( previousX );\n  // animate next frame\n  if ( this.isAnimating ) requestAnimationFrame( () => this.animate() );\n};\n\nproto.positionSlider = function() {\n  let x = this.x;\n  // wrap position around\n  if ( this.isWrapping ) {\n    x = utils.modulo( x, this.slideableWidth ) - this.slideableWidth;\n    this.shiftWrapCells( x );\n  }\n\n  this.setTranslateX( x, this.isAnimating );\n  this.dispatchScrollEvent();\n};\n\nproto.setTranslateX = function( x, is3d ) {\n  x += this.cursorPosition;\n  // reverse if right-to-left and using transform\n  if ( this.options.rightToLeft ) x = -x;\n  let translateX = this.getPositionValue( x );\n  // use 3D transforms for hardware acceleration on iOS\n  // but use 2D when settled, for better font-rendering\n  this.slider.style.transform = is3d ?\n    `translate3d(${translateX},0,0)` : `translateX(${translateX})`;\n};\n\nproto.dispatchScrollEvent = function() {\n  let firstSlide = this.slides[0];\n  if ( !firstSlide ) return;\n\n  let positionX = -this.x - firstSlide.target;\n  let progress = positionX / this.slidesWidth;\n  this.dispatchEvent( 'scroll', null, [ progress, positionX ] );\n};\n\nproto.positionSliderAtSelected = function() {\n  if ( !this.cells.length ) return;\n\n  this.x = -this.selectedSlide.target;\n  this.velocity = 0; // stop wobble\n  this.positionSlider();\n};\n\nproto.getPositionValue = function( position ) {\n  if ( this.options.percentPosition ) {\n    // percent position, round to 2 digits, like 12.34%\n    return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%';\n  } else {\n    // pixel positioning\n    return Math.round( position ) + 'px';\n  }\n};\n\nproto.settle = function( previousX ) {\n  // keep track of frames where x hasn't moved\n  let isResting = !this.isPointerDown &&\n      Math.round( this.x * 100 ) === Math.round( previousX * 100 );\n  if ( isResting ) this.restingFrames++;\n  // stop animating if resting for 3 or more frames\n  if ( this.restingFrames > 2 ) {\n    this.isAnimating = false;\n    delete this.isFreeScrolling;\n    // render position with translateX when settled\n    this.positionSlider();\n    this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );\n  }\n};\n\nproto.shiftWrapCells = function( x ) {\n  // shift before cells\n  let beforeGap = this.cursorPosition + x;\n  this._shiftCells( this.beforeShiftCells, beforeGap, -1 );\n  // shift after cells\n  let afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );\n  this._shiftCells( this.afterShiftCells, afterGap, 1 );\n};\n\nproto._shiftCells = function( cells, gap, shift ) {\n  cells.forEach( ( cell ) => {\n    let cellShift = gap > 0 ? shift : 0;\n    this._wrapShiftCell( cell, cellShift );\n    gap -= cell.size.outerWidth;\n  } );\n};\n\nproto._unshiftCells = function( cells ) {\n  if ( !cells || !cells.length ) return;\n\n  cells.forEach( ( cell ) => this._wrapShiftCell( cell, 0 ) );\n};\n\n// @param {Integer} shift - 0, 1, or -1\nproto._wrapShiftCell = function( cell, shift ) {\n  this._renderCellPosition( cell, cell.x + this.slideableWidth * shift );\n};\n\n// -------------------------- physics -------------------------- //\n\nproto.integratePhysics = function() {\n  this.x += this.velocity;\n  this.velocity *= this.getFrictionFactor();\n};\n\nproto.applyForce = function( force ) {\n  this.velocity += force;\n};\n\nproto.getFrictionFactor = function() {\n  return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];\n};\n\nproto.getRestingPosition = function() {\n  // my thanks to Steven Wittens, who simplified this math greatly\n  return this.x + this.velocity / ( 1 - this.getFrictionFactor() );\n};\n\nproto.applyDragForce = function() {\n  if ( !this.isDraggable || !this.isPointerDown ) return;\n\n  // change the position to drag position by applying force\n  let dragVelocity = this.dragX - this.x;\n  let dragForce = dragVelocity - this.velocity;\n  this.applyForce( dragForce );\n};\n\nproto.applySelectedAttraction = function() {\n  // do not attract if pointer down or no slides\n  let dragDown = this.isDraggable && this.isPointerDown;\n  if ( dragDown || this.isFreeScrolling || !this.slides.length ) return;\n\n  let distance = this.selectedSlide.target * -1 - this.x;\n  let force = distance * this.options.selectedAttraction;\n  this.applyForce( force );\n};\n\nreturn proto;\n\n} ) );\n// Flickity main\n/* eslint-disable max-params */\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        window,\n        require('ev-emitter'),\n        require('get-size'),\n        require('fizzy-ui-utils'),\n        require('./cell'),\n        require('./slide'),\n        require('./animate'),\n    );\n  } else {\n    // browser global\n    let _Flickity = window.Flickity;\n\n    window.Flickity = factory(\n        window,\n        window.EvEmitter,\n        window.getSize,\n        window.fizzyUIUtils,\n        _Flickity.Cell,\n        _Flickity.Slide,\n        _Flickity.animatePrototype,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) {\n/* eslint-enable max-params */\n\n// vars\nconst { getComputedStyle, console } = window;\nlet { jQuery } = window;\n\n// -------------------------- Flickity -------------------------- //\n\n// globally unique identifiers\nlet GUID = 0;\n// internal store of all Flickity intances\nlet instances = {};\n\nfunction Flickity( element, options ) {\n  let queryElement = utils.getQueryElement( element );\n  if ( !queryElement ) {\n    if ( console ) console.error(`Bad element for Flickity: ${queryElement || element}`);\n    return;\n  }\n  this.element = queryElement;\n  // do not initialize twice on same element\n  if ( this.element.flickityGUID ) {\n    let instance = instances[ this.element.flickityGUID ];\n    if ( instance ) instance.option( options );\n    return instance;\n  }\n\n  // add jQuery\n  if ( jQuery ) {\n    this.$element = jQuery( this.element );\n  }\n  // options\n  this.options = { ...this.constructor.defaults };\n  this.option( options );\n\n  // kick things off\n  this._create();\n}\n\nFlickity.defaults = {\n  accessibility: true,\n  // adaptiveHeight: false,\n  cellAlign: 'center',\n  // cellSelector: undefined,\n  // contain: false,\n  freeScrollFriction: 0.075, // friction when free-scrolling\n  friction: 0.28, // friction when selecting\n  namespaceJQueryEvents: true,\n  // initialIndex: 0,\n  percentPosition: true,\n  resize: true,\n  selectedAttraction: 0.025,\n  setGallerySize: true,\n  // watchCSS: false,\n  // wrapAround: false\n};\n\n// hash of methods triggered on _create()\nFlickity.create = {};\n\nlet proto = Flickity.prototype;\n// inherit EventEmitter\nObject.assign( proto, EvEmitter.prototype );\n\nproto._create = function() {\n  let { resize, watchCSS, rightToLeft } = this.options;\n  // add id for Flickity.data\n  let id = this.guid = ++GUID;\n  this.element.flickityGUID = id; // expando\n  instances[ id ] = this; // associate via id\n  // initial properties\n  this.selectedIndex = 0;\n  // how many frames slider has been in same position\n  this.restingFrames = 0;\n  // initial physics properties\n  this.x = 0;\n  this.velocity = 0;\n  this.beginMargin = rightToLeft ? 'marginRight' : 'marginLeft';\n  this.endMargin = rightToLeft ? 'marginLeft' : 'marginRight';\n  // create viewport & slider\n  this.viewport = document.createElement('div');\n  this.viewport.className = 'flickity-viewport';\n  this._createSlider();\n  // used for keyboard navigation\n  this.focusableElems = [ this.element ];\n\n  if ( resize || watchCSS ) {\n    window.addEventListener( 'resize', this );\n  }\n\n  // add listeners from on option\n  for ( let eventName in this.options.on ) {\n    let listener = this.options.on[ eventName ];\n    this.on( eventName, listener );\n  }\n\n  for ( let method in Flickity.create ) {\n    Flickity.create[ method ].call( this );\n  }\n\n  if ( watchCSS ) {\n    this.watchCSS();\n  } else {\n    this.activate();\n  }\n};\n\n/**\n * set options\n * @param {Object} opts - options to extend\n */\nproto.option = function( opts ) {\n  Object.assign( this.options, opts );\n};\n\nproto.activate = function() {\n  if ( this.isActive ) return;\n\n  this.isActive = true;\n  this.element.classList.add('flickity-enabled');\n  if ( this.options.rightToLeft ) {\n    this.element.classList.add('flickity-rtl');\n  }\n\n  this.getSize();\n  // move initial cell elements so they can be loaded as cells\n  let cellElems = this._filterFindCellElements( this.element.children );\n  this.slider.append( ...cellElems );\n  this.viewport.append( this.slider );\n  this.element.append( this.viewport );\n  // get cells from children\n  this.reloadCells();\n\n  if ( this.options.accessibility ) {\n    // allow element to focusable\n    this.element.tabIndex = 0;\n    // listen for key presses\n    this.element.addEventListener( 'keydown', this );\n  }\n\n  this.emitEvent('activate');\n  this.selectInitialIndex();\n  // flag for initial activation, for using initialIndex\n  this.isInitActivated = true;\n  // ready event. #493\n  this.dispatchEvent('ready');\n};\n\n// slider positions the cells\nproto._createSlider = function() {\n  // slider element does all the positioning\n  let slider = document.createElement('div');\n  slider.className = 'flickity-slider';\n  this.slider = slider;\n};\n\nproto._filterFindCellElements = function( elems ) {\n  return utils.filterFindElements( elems, this.options.cellSelector );\n};\n\n// goes through all children\nproto.reloadCells = function() {\n  // collection of item elements\n  this.cells = this._makeCells( this.slider.children );\n  this.positionCells();\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n};\n\n/**\n * turn elements into Flickity.Cells\n * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells\n * @returns {Array} items - collection of new Flickity Cells\n */\nproto._makeCells = function( elems ) {\n  let cellElems = this._filterFindCellElements( elems );\n\n  // create new Cells for collection\n  return cellElems.map( ( cellElem ) => new Cell( cellElem ) );\n};\n\nproto.getLastCell = function() {\n  return this.cells[ this.cells.length - 1 ];\n};\n\nproto.getLastSlide = function() {\n  return this.slides[ this.slides.length - 1 ];\n};\n\n// positions all cells\nproto.positionCells = function() {\n  // size all cells\n  this._sizeCells( this.cells );\n  // position all cells\n  this._positionCells( 0 );\n};\n\n/**\n * position certain cells\n * @param {Integer} index - which cell to start with\n */\nproto._positionCells = function( index ) {\n  index = index || 0;\n  // also measure maxCellHeight\n  // start 0 if positioning all cells\n  this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;\n  let cellX = 0;\n  // get cellX\n  if ( index > 0 ) {\n    let startCell = this.cells[ index - 1 ];\n    cellX = startCell.x + startCell.size.outerWidth;\n  }\n\n  this.cells.slice( index ).forEach( ( cell ) => {\n    cell.x = cellX;\n    this._renderCellPosition( cell, cellX );\n    cellX += cell.size.outerWidth;\n    this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );\n  } );\n  // keep track of cellX for wrap-around\n  this.slideableWidth = cellX;\n  // slides\n  this.updateSlides();\n  // contain slides target\n  this._containSlides();\n  // update slidesWidth\n  this.slidesWidth = this.cells.length ?\n    this.getLastSlide().target - this.slides[0].target : 0;\n};\n\nproto._renderCellPosition = function( cell, x ) {\n  // render position of cell with in slider\n  let sideOffset = this.options.rightToLeft ? -1 : 1;\n  let renderX = x * sideOffset;\n  if ( this.options.percentPosition ) renderX *= this.size.innerWidth / cell.size.width;\n  let positionValue = this.getPositionValue( renderX );\n  cell.element.style.transform = `translateX( ${positionValue} )`;\n};\n\n/**\n * cell.getSize() on multiple cells\n * @param {Array} cells - cells to size\n */\nproto._sizeCells = function( cells ) {\n  cells.forEach( ( cell ) => cell.getSize() );\n};\n\n// --------------------------  -------------------------- //\n\nproto.updateSlides = function() {\n  this.slides = [];\n  if ( !this.cells.length ) return;\n\n  let { beginMargin, endMargin } = this;\n  let slide = new Slide( beginMargin, endMargin, this.cellAlign );\n  this.slides.push( slide );\n\n  let canCellFit = this._getCanCellFit();\n\n  this.cells.forEach( ( cell, i ) => {\n    // just add cell if first cell in slide\n    if ( !slide.cells.length ) {\n      slide.addCell( cell );\n      return;\n    }\n\n    let slideWidth = ( slide.outerWidth - slide.firstMargin ) +\n      ( cell.size.outerWidth - cell.size[ endMargin ] );\n\n    if ( canCellFit( i, slideWidth ) ) {\n      slide.addCell( cell );\n    } else {\n      // doesn't fit, new slide\n      slide.updateTarget();\n\n      slide = new Slide( beginMargin, endMargin, this.cellAlign );\n      this.slides.push( slide );\n      slide.addCell( cell );\n    }\n  } );\n  // last slide\n  slide.updateTarget();\n  // update .selectedSlide\n  this.updateSelectedSlide();\n};\n\nproto._getCanCellFit = function() {\n  let { groupCells } = this.options;\n  if ( !groupCells ) return () => false;\n\n  if ( typeof groupCells == 'number' ) {\n    // group by number. 3 -> [0,1,2], [3,4,5], ...\n    let number = parseInt( groupCells, 10 );\n    return ( i ) => ( i % number ) !== 0;\n  }\n  // default, group by width of slide\n  let percent = 1;\n  // parse '75%\n  let percentMatch = typeof groupCells == 'string' && groupCells.match( /^(\\d+)%$/ );\n  if ( percentMatch ) percent = parseInt( percentMatch[1], 10 ) / 100;\n  let groupWidth = ( this.size.innerWidth + 1 ) * percent;\n  return ( i, slideWidth ) => slideWidth <= groupWidth;\n};\n\n// alias _init for jQuery plugin .flickity()\nproto._init =\nproto.reposition = function() {\n  this.positionCells();\n  this.positionSliderAtSelected();\n};\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n  this.setCellAlign();\n  this.cursorPosition = this.size.innerWidth * this.cellAlign;\n};\n\nlet cellAlignShorthands = {\n  left: 0,\n  center: 0.5,\n  right: 1,\n};\n\nproto.setCellAlign = function() {\n  let { cellAlign, rightToLeft } = this.options;\n  let shorthand = cellAlignShorthands[ cellAlign ];\n  this.cellAlign = shorthand !== undefined ? shorthand : cellAlign;\n  if ( rightToLeft ) this.cellAlign = 1 - this.cellAlign;\n};\n\nproto.setGallerySize = function() {\n  if ( !this.options.setGallerySize ) return;\n\n  let height = this.options.adaptiveHeight && this.selectedSlide ?\n    this.selectedSlide.height : this.maxCellHeight;\n  this.viewport.style.height = `${height}px`;\n};\n\nproto._updateWrapShiftCells = function() {\n  // update isWrapping\n  this.isWrapping = this.getIsWrapping();\n  // only for wrap-around\n  if ( !this.isWrapping ) return;\n\n  // unshift previous cells\n  this._unshiftCells( this.beforeShiftCells );\n  this._unshiftCells( this.afterShiftCells );\n  // get before cells\n  // initial gap\n  let beforeGapX = this.cursorPosition;\n  let lastIndex = this.cells.length - 1;\n  this.beforeShiftCells = this._getGapCells( beforeGapX, lastIndex, -1 );\n  // get after cells\n  // ending gap between last cell and end of gallery viewport\n  let afterGapX = this.size.innerWidth - this.cursorPosition;\n  // start cloning at first cell, working forwards\n  this.afterShiftCells = this._getGapCells( afterGapX, 0, 1 );\n};\n\nproto.getIsWrapping = function() {\n  let { wrapAround } = this.options;\n  if ( !wrapAround || this.slides.length < 2 ) return false;\n\n  if ( wrapAround !== 'fill' ) return true;\n  // check that slides can fit\n\n  let gapWidth = this.slideableWidth - this.size.innerWidth;\n  if ( gapWidth > this.size.innerWidth ) return true; // gap * 2x big, all good\n  // check that content width - shifting cell is bigger than viewport width\n  for ( let cell of this.cells ) {\n    if ( cell.size.outerWidth > gapWidth ) return false;\n  }\n  return true;\n};\n\nproto._getGapCells = function( gapX, cellIndex, increment ) {\n  // keep adding cells until the cover the initial gap\n  let cells = [];\n  while ( gapX > 0 ) {\n    let cell = this.cells[ cellIndex ];\n    if ( !cell ) break;\n\n    cells.push( cell );\n    cellIndex += increment;\n    gapX -= cell.size.outerWidth;\n  }\n  return cells;\n};\n\n// ----- contain & wrap ----- //\n\n// contain cell targets so no excess sliding\nproto._containSlides = function() {\n  let isContaining = this.options.contain && !this.isWrapping &&\n      this.cells.length;\n  if ( !isContaining ) return;\n\n  let contentWidth = this.slideableWidth - this.getLastCell().size[ this.endMargin ];\n  // content is less than gallery size\n  let isContentSmaller = contentWidth < this.size.innerWidth;\n  if ( isContentSmaller ) {\n    // all cells fit inside gallery\n    this.slides.forEach( ( slide ) => {\n      slide.target = contentWidth * this.cellAlign;\n    } );\n  } else {\n    // contain to bounds\n    let beginBound = this.cursorPosition + this.cells[0].size[ this.beginMargin ];\n    let endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );\n    this.slides.forEach( ( slide ) => {\n      slide.target = Math.max( slide.target, beginBound );\n      slide.target = Math.min( slide.target, endBound );\n    } );\n  }\n};\n\n// ----- events ----- //\n\n/**\n * emits events via eventEmitter and jQuery events\n * @param {String} type - name of event\n * @param {Event} event - original event\n * @param {Array} args - extra arguments\n */\nproto.dispatchEvent = function( type, event, args ) {\n  let emitArgs = event ? [ event ].concat( args ) : args;\n  this.emitEvent( type, emitArgs );\n\n  if ( jQuery && this.$element ) {\n    // default trigger with type if no event\n    type += this.options.namespaceJQueryEvents ? '.flickity' : '';\n    let $event = type;\n    if ( event ) {\n      // create jQuery event\n      let jQEvent = new jQuery.Event( event );\n      jQEvent.type = type;\n      $event = jQEvent;\n    }\n    this.$element.trigger( $event, args );\n  }\n};\n\nconst unidraggerEvents = [\n  'dragStart',\n  'dragMove',\n  'dragEnd',\n  'pointerDown',\n  'pointerMove',\n  'pointerEnd',\n  'staticClick',\n];\n\nlet _emitEvent = proto.emitEvent;\nproto.emitEvent = function( eventName, args ) {\n  if ( eventName === 'staticClick' ) {\n    // add cellElem and cellIndex args to staticClick\n    let clickedCell = this.getParentCell( args[0].target );\n    let cellElem = clickedCell && clickedCell.element;\n    let cellIndex = clickedCell && this.cells.indexOf( clickedCell );\n    args = args.concat( cellElem, cellIndex );\n  }\n  // do regular thing\n  _emitEvent.call( this, eventName, args );\n  // duck-punch in jQuery events for Unidragger events\n  let isUnidraggerEvent = unidraggerEvents.includes( eventName );\n  if ( !isUnidraggerEvent || !jQuery || !this.$element ) return;\n\n  eventName += this.options.namespaceJQueryEvents ? '.flickity' : '';\n  let event = args.shift( 0 );\n  let jQEvent = new jQuery.Event( event );\n  jQEvent.type = eventName;\n  this.$element.trigger( jQEvent, args );\n};\n\n// -------------------------- select -------------------------- //\n\n/**\n * @param {Integer} index - index of the slide\n * @param {Boolean} isWrap - will wrap-around to last/first if at the end\n * @param {Boolean} isInstant - will immediately set position at selected cell\n */\nproto.select = function( index, isWrap, isInstant ) {\n  if ( !this.isActive ) return;\n\n  index = parseInt( index, 10 );\n  this._wrapSelect( index );\n\n  if ( this.isWrapping || isWrap ) {\n    index = utils.modulo( index, this.slides.length );\n  }\n  // bail if invalid index\n  if ( !this.slides[ index ] ) return;\n\n  let prevIndex = this.selectedIndex;\n  this.selectedIndex = index;\n  this.updateSelectedSlide();\n  if ( isInstant ) {\n    this.positionSliderAtSelected();\n  } else {\n    this.startAnimation();\n  }\n  if ( this.options.adaptiveHeight ) {\n    this.setGallerySize();\n  }\n  // events\n  this.dispatchEvent( 'select', null, [ index ] );\n  // change event if new index\n  if ( index !== prevIndex ) {\n    this.dispatchEvent( 'change', null, [ index ] );\n  }\n};\n\n// wraps position for wrapAround, to move to closest slide. #113\nproto._wrapSelect = function( index ) {\n  if ( !this.isWrapping ) return;\n\n  const { selectedIndex, slideableWidth, slides: { length } } = this;\n  // shift index for wrap, do not wrap dragSelect\n  if ( !this.isDragSelect ) {\n    let wrapIndex = utils.modulo( index, length );\n    // go to shortest\n    let delta = Math.abs( wrapIndex - selectedIndex );\n    let backWrapDelta = Math.abs( ( wrapIndex + length ) - selectedIndex );\n    let forewardWrapDelta = Math.abs( ( wrapIndex - length ) - selectedIndex );\n    if ( backWrapDelta < delta ) {\n      index += length;\n    } else if ( forewardWrapDelta < delta ) {\n      index -= length;\n    }\n  }\n\n  // wrap position so slider is within normal area\n  if ( index < 0 ) {\n    this.x -= slideableWidth;\n  } else if ( index >= length ) {\n    this.x += slideableWidth;\n  }\n};\n\nproto.previous = function( isWrap, isInstant ) {\n  this.select( this.selectedIndex - 1, isWrap, isInstant );\n};\n\nproto.next = function( isWrap, isInstant ) {\n  this.select( this.selectedIndex + 1, isWrap, isInstant );\n};\n\nproto.updateSelectedSlide = function() {\n  let slide = this.slides[ this.selectedIndex ];\n  // selectedIndex could be outside of slides, if triggered before resize()\n  if ( !slide ) return;\n\n  // unselect previous selected slide\n  this.unselectSelectedSlide();\n  // update new selected slide\n  this.selectedSlide = slide;\n  slide.select();\n  this.selectedCells = slide.cells;\n  this.selectedElements = slide.getCellElements();\n  // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility\n  this.selectedCell = slide.cells[0];\n  this.selectedElement = this.selectedElements[0];\n};\n\nproto.unselectSelectedSlide = function() {\n  if ( this.selectedSlide ) this.selectedSlide.unselect();\n};\n\nproto.selectInitialIndex = function() {\n  let initialIndex = this.options.initialIndex;\n  // already activated, select previous selectedIndex\n  if ( this.isInitActivated ) {\n    this.select( this.selectedIndex, false, true );\n    return;\n  }\n  // select with selector string\n  if ( initialIndex && typeof initialIndex == 'string' ) {\n    let cell = this.queryCell( initialIndex );\n    if ( cell ) {\n      this.selectCell( initialIndex, false, true );\n      return;\n    }\n  }\n\n  let index = 0;\n  // select with number\n  if ( initialIndex && this.slides[ initialIndex ] ) {\n    index = initialIndex;\n  }\n  // select instantly\n  this.select( index, false, true );\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, Number]} value - zero-based index or element to select\n * @param {Boolean} isWrap - enables wrapping around for extra index\n * @param {Boolean} isInstant - disables slide animation\n */\nproto.selectCell = function( value, isWrap, isInstant ) {\n  // get cell\n  let cell = this.queryCell( value );\n  if ( !cell ) return;\n\n  let index = this.getCellSlideIndex( cell );\n  this.select( index, isWrap, isInstant );\n};\n\nproto.getCellSlideIndex = function( cell ) {\n  // get index of slide that has cell\n  let cellSlide = this.slides.find( ( slide ) => slide.cells.includes( cell ) );\n  return this.slides.indexOf( cellSlide );\n};\n\n// -------------------------- get cells -------------------------- //\n\n/**\n * get Flickity.Cell, given an Element\n * @param {Element} elem - matching cell element\n * @returns {Flickity.Cell} cell - matching cell\n */\nproto.getCell = function( elem ) {\n  // loop through cells to get the one that matches\n  for ( let cell of this.cells ) {\n    if ( cell.element === elem ) return cell;\n  }\n};\n\n/**\n * get collection of Flickity.Cells, given Elements\n * @param {[Element, Array, NodeList]} elems - multiple elements\n * @returns {Array} cells - Flickity.Cells\n */\nproto.getCells = function( elems ) {\n  elems = utils.makeArray( elems );\n  return elems.map( ( elem ) => this.getCell( elem ) ).filter( Boolean );\n};\n\n/**\n * get cell elements\n * @returns {Array} cellElems\n */\nproto.getCellElements = function() {\n  return this.cells.map( ( cell ) => cell.element );\n};\n\n/**\n * get parent cell from an element\n * @param {Element} elem - child element\n * @returns {Flickit.Cell} cell - parent cell\n */\nproto.getParentCell = function( elem ) {\n  // first check if elem is cell\n  let cell = this.getCell( elem );\n  if ( cell ) return cell;\n\n  // try to get parent cell elem\n  let closest = elem.closest('.flickity-slider > *');\n  return this.getCell( closest );\n};\n\n/**\n * get cells adjacent to a slide\n * @param {Integer} adjCount - number of adjacent slides\n * @param {Integer} index - index of slide to start\n * @returns {Array} cells - array of Flickity.Cells\n */\nproto.getAdjacentCellElements = function( adjCount, index ) {\n  if ( !adjCount ) return this.selectedSlide.getCellElements();\n\n  index = index === undefined ? this.selectedIndex : index;\n\n  let len = this.slides.length;\n  if ( 1 + ( adjCount * 2 ) >= len ) {\n    return this.getCellElements(); // get all\n  }\n\n  let cellElems = [];\n  for ( let i = index - adjCount; i <= index + adjCount; i++ ) {\n    let slideIndex = this.isWrapping ? utils.modulo( i, len ) : i;\n    let slide = this.slides[ slideIndex ];\n    if ( slide ) {\n      cellElems = cellElems.concat( slide.getCellElements() );\n    }\n  }\n  return cellElems;\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, String, Number]} selector - element, selector string, or index\n * @returns {Flickity.Cell} - matching cell\n */\nproto.queryCell = function( selector ) {\n  if ( typeof selector == 'number' ) {\n    // use number as index\n    return this.cells[ selector ];\n  }\n  // do not select invalid selectors from hash: #123, #/. #791\n  let isSelectorString = typeof selector == 'string' && !selector.match( /^[#.]?[\\d/]/ );\n  if ( isSelectorString ) {\n    // use string as selector, get element\n    selector = this.element.querySelector( selector );\n  }\n  // get cell from element\n  return this.getCell( selector );\n};\n\n// -------------------------- events -------------------------- //\n\nproto.uiChange = function() {\n  this.emitEvent('uiChange');\n};\n\n// ----- resize ----- //\n\nproto.onresize = function() {\n  this.watchCSS();\n  this.resize();\n};\n\nutils.debounceMethod( Flickity, 'onresize', 150 );\n\nproto.resize = function() {\n  // #1177 disable resize behavior when animating or dragging for iOS 15\n  if ( !this.isActive || this.isAnimating || this.isDragging ) return;\n  this.getSize();\n  // wrap values\n  if ( this.isWrapping ) {\n    this.x = utils.modulo( this.x, this.slideableWidth );\n  }\n  this.positionCells();\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n  this.emitEvent('resize');\n  // update selected index for group slides, instant\n  // TODO: position can be lost between groups of various numbers\n  let selectedElement = this.selectedElements && this.selectedElements[0];\n  this.selectCell( selectedElement, false, true );\n};\n\n// watches the :after property, activates/deactivates\nproto.watchCSS = function() {\n  if ( !this.options.watchCSS ) return;\n\n  let afterContent = getComputedStyle( this.element, ':after' ).content;\n  // activate if :after { content: 'flickity' }\n  if ( afterContent.includes('flickity') ) {\n    this.activate();\n  } else {\n    this.deactivate();\n  }\n};\n\n// ----- keydown ----- //\n\n// go previous/next if left/right keys pressed\nproto.onkeydown = function( event ) {\n  let { activeElement } = document;\n  let handler = Flickity.keyboardHandlers[ event.key ];\n  // only work if element is in focus\n  if ( !this.options.accessibility || !activeElement || !handler ) return;\n\n  let isFocused = this.focusableElems.some( ( elem ) => activeElement === elem );\n  if ( isFocused ) handler.call( this );\n};\n\nFlickity.keyboardHandlers = {\n  ArrowLeft: function() {\n    this.uiChange();\n    let leftMethod = this.options.rightToLeft ? 'next' : 'previous';\n    this[ leftMethod ]();\n  },\n  ArrowRight: function() {\n    this.uiChange();\n    let rightMethod = this.options.rightToLeft ? 'previous' : 'next';\n    this[ rightMethod ]();\n  },\n};\n\n// ----- focus ----- //\n\nproto.focus = function() {\n  this.element.focus({ preventScroll: true });\n};\n\n// -------------------------- destroy -------------------------- //\n\n// deactivate all Flickity functionality, but keep stuff available\nproto.deactivate = function() {\n  if ( !this.isActive ) return;\n\n  this.element.classList.remove('flickity-enabled');\n  this.element.classList.remove('flickity-rtl');\n  this.unselectSelectedSlide();\n  // destroy cells\n  this.cells.forEach( ( cell ) => cell.destroy() );\n  this.viewport.remove();\n  // move child elements back into element\n  this.element.append( ...this.slider.children );\n  if ( this.options.accessibility ) {\n    this.element.removeAttribute('tabIndex');\n    this.element.removeEventListener( 'keydown', this );\n  }\n  // set flags\n  this.isActive = false;\n  this.emitEvent('deactivate');\n};\n\nproto.destroy = function() {\n  this.deactivate();\n  window.removeEventListener( 'resize', this );\n  this.allOff();\n  this.emitEvent('destroy');\n  if ( jQuery && this.$element ) {\n    jQuery.removeData( this.element, 'flickity' );\n  }\n  delete this.element.flickityGUID;\n  delete instances[ this.guid ];\n};\n\n// -------------------------- prototype -------------------------- //\n\nObject.assign( proto, animatePrototype );\n\n// -------------------------- extras -------------------------- //\n\n/**\n * get Flickity instance from element\n * @param {[Element, String]} elem - element or selector string\n * @returns {Flickity} - Flickity instance\n */\nFlickity.data = function( elem ) {\n  elem = utils.getQueryElement( elem );\n  if ( elem ) return instances[ elem.flickityGUID ];\n};\n\nutils.htmlInit( Flickity, 'flickity' );\n\nlet { jQueryBridget } = window;\nif ( jQuery && jQueryBridget ) {\n  jQueryBridget( 'flickity', Flickity, jQuery );\n}\n\n// set internal jQuery, for Webpack + jQuery v3, #478\nFlickity.setJQuery = function( jq ) {\n  jQuery = jq;\n};\n\nFlickity.Cell = Cell;\nFlickity.Slide = Slide;\n\nreturn Flickity;\n\n} ) );\n// drag\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        window,\n        require('./core'),\n        require('unidragger'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    window.Flickity = factory(\n        window,\n        window.Flickity,\n        window.Unidragger,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( window, Flickity, Unidragger, utils ) {\n\n// ----- defaults ----- //\n\nObject.assign( Flickity.defaults, {\n  draggable: '>1',\n  dragThreshold: 3,\n} );\n\n// -------------------------- drag prototype -------------------------- //\n\nlet proto = Flickity.prototype;\nObject.assign( proto, Unidragger.prototype ); // inherit Unidragger\nproto.touchActionValue = '';\n\n// --------------------------  -------------------------- //\n\nFlickity.create.drag = function() {\n  this.on( 'activate', this.onActivateDrag );\n  this.on( 'uiChange', this._uiChangeDrag );\n  this.on( 'deactivate', this.onDeactivateDrag );\n  this.on( 'cellChange', this.updateDraggable );\n  this.on( 'pointerDown', this.handlePointerDown );\n  this.on( 'pointerUp', this.handlePointerUp );\n  this.on( 'pointerDown', this.handlePointerDone );\n  this.on( 'dragStart', this.handleDragStart );\n  this.on( 'dragMove', this.handleDragMove );\n  this.on( 'dragEnd', this.handleDragEnd );\n  this.on( 'staticClick', this.handleStaticClick );\n  // TODO updateDraggable on resize? if groupCells & slides change\n};\n\nproto.onActivateDrag = function() {\n  this.handles = [ this.viewport ];\n  this.bindHandles();\n  this.updateDraggable();\n};\n\nproto.onDeactivateDrag = function() {\n  this.unbindHandles();\n  this.element.classList.remove('is-draggable');\n};\n\nproto.updateDraggable = function() {\n  // disable dragging if less than 2 slides. #278\n  if ( this.options.draggable === '>1' ) {\n    this.isDraggable = this.slides.length > 1;\n  } else {\n    this.isDraggable = this.options.draggable;\n  }\n  this.element.classList.toggle( 'is-draggable', this.isDraggable );\n};\n\nproto._uiChangeDrag = function() {\n  delete this.isFreeScrolling;\n};\n\n// -------------------------- pointer events -------------------------- //\n\nproto.handlePointerDown = function( event ) {\n  if ( !this.isDraggable ) {\n    // proceed for staticClick\n    this.bindActivePointerEvents( event );\n    return;\n  }\n\n  let isTouchStart = event.type === 'touchstart';\n  let isTouchPointer = event.pointerType === 'touch';\n  let isFocusNode = event.target.matches('input, textarea, select');\n  if ( !isTouchStart && !isTouchPointer && !isFocusNode ) event.preventDefault();\n  if ( !isFocusNode ) this.focus();\n  // blur\n  if ( document.activeElement !== this.element ) document.activeElement.blur();\n  // stop if it was moving\n  this.dragX = this.x;\n  this.viewport.classList.add('is-pointer-down');\n  // track scrolling\n  this.pointerDownScroll = getScrollPosition();\n  window.addEventListener( 'scroll', this );\n  this.bindActivePointerEvents( event );\n};\n\n// ----- move ----- //\n\nproto.hasDragStarted = function( moveVector ) {\n  return Math.abs( moveVector.x ) > this.options.dragThreshold;\n};\n\n// ----- up ----- //\n\nproto.handlePointerUp = function() {\n  delete this.isTouchScrolling;\n  this.viewport.classList.remove('is-pointer-down');\n};\n\nproto.handlePointerDone = function() {\n  window.removeEventListener( 'scroll', this );\n  delete this.pointerDownScroll;\n};\n\n// -------------------------- dragging -------------------------- //\n\nproto.handleDragStart = function() {\n  if ( !this.isDraggable ) return;\n\n  this.dragStartPosition = this.x;\n  this.startAnimation();\n  window.removeEventListener( 'scroll', this );\n};\n\nproto.handleDragMove = function( event, pointer, moveVector ) {\n  if ( !this.isDraggable ) return;\n\n  event.preventDefault();\n\n  this.previousDragX = this.dragX;\n  // reverse if right-to-left\n  let direction = this.options.rightToLeft ? -1 : 1;\n  // wrap around move. #589\n  if ( this.isWrapping ) moveVector.x %= this.slideableWidth;\n  let dragX = this.dragStartPosition + moveVector.x * direction;\n\n  if ( !this.isWrapping ) {\n    // slow drag\n    let originBound = Math.max( -this.slides[0].target, this.dragStartPosition );\n    dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;\n    let endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition );\n    dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;\n  }\n\n  this.dragX = dragX;\n  this.dragMoveTime = new Date();\n};\n\nproto.handleDragEnd = function() {\n  if ( !this.isDraggable ) return;\n\n  let { freeScroll } = this.options;\n  if ( freeScroll ) this.isFreeScrolling = true;\n  // set selectedIndex based on where flick will end up\n  let index = this.dragEndRestingSelect();\n\n  if ( freeScroll && !this.isWrapping ) {\n    // if free-scroll & not wrap around\n    // do not free-scroll if going outside of bounding slides\n    // so bounding slides can attract slider, and keep it in bounds\n    let restingX = this.getRestingPosition();\n    this.isFreeScrolling = -restingX > this.slides[0].target &&\n      -restingX < this.getLastSlide().target;\n  } else if ( !freeScroll && index === this.selectedIndex ) {\n    // boost selection if selected index has not changed\n    index += this.dragEndBoostSelect();\n  }\n  delete this.previousDragX;\n  // apply selection\n  // HACK, set flag so dragging stays in correct direction\n  this.isDragSelect = this.isWrapping;\n  this.select( index );\n  delete this.isDragSelect;\n};\n\nproto.dragEndRestingSelect = function() {\n  let restingX = this.getRestingPosition();\n  // how far away from selected slide\n  let distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) );\n  // get closet resting going up and going down\n  let positiveResting = this._getClosestResting( restingX, distance, 1 );\n  let negativeResting = this._getClosestResting( restingX, distance, -1 );\n  // use closer resting for wrap-around\n  return positiveResting.distance < negativeResting.distance ?\n    positiveResting.index : negativeResting.index;\n};\n\n/**\n * given resting X and distance to selected cell\n * get the distance and index of the closest cell\n * @param {Number} restingX - estimated post-flick resting position\n * @param {Number} distance - distance to selected cell\n * @param {Integer} increment - +1 or -1, going up or down\n * @returns {Object} - { distance: {Number}, index: {Integer} }\n */\nproto._getClosestResting = function( restingX, distance, increment ) {\n  let index = this.selectedIndex;\n  let minDistance = Infinity;\n  let condition = this.options.contain && !this.isWrapping ?\n    // if containing, keep going if distance is equal to minDistance\n    ( dist, minDist ) => dist <= minDist :\n    ( dist, minDist ) => dist < minDist;\n\n  while ( condition( distance, minDistance ) ) {\n    // measure distance to next cell\n    index += increment;\n    minDistance = distance;\n    distance = this.getSlideDistance( -restingX, index );\n    if ( distance === null ) break;\n\n    distance = Math.abs( distance );\n  }\n  return {\n    distance: minDistance,\n    // selected was previous index\n    index: index - increment,\n  };\n};\n\n/**\n * measure distance between x and a slide target\n * @param {Number} x - horizontal position\n * @param {Integer} index - slide index\n * @returns {Number} - slide distance\n */\nproto.getSlideDistance = function( x, index ) {\n  let len = this.slides.length;\n  // wrap around if at least 2 slides\n  let isWrapAround = this.options.wrapAround && len > 1;\n  let slideIndex = isWrapAround ? utils.modulo( index, len ) : index;\n  let slide = this.slides[ slideIndex ];\n  if ( !slide ) return null;\n\n  // add distance for wrap-around slides\n  let wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0;\n  return x - ( slide.target + wrap );\n};\n\nproto.dragEndBoostSelect = function() {\n  // do not boost if no previousDragX or dragMoveTime\n  if ( this.previousDragX === undefined || !this.dragMoveTime ||\n    // or if drag was held for 100 ms\n    new Date() - this.dragMoveTime > 100 ) {\n    return 0;\n  }\n\n  let distance = this.getSlideDistance( -this.dragX, this.selectedIndex );\n  let delta = this.previousDragX - this.dragX;\n  if ( distance > 0 && delta > 0 ) {\n    // boost to next if moving towards the right, and positive velocity\n    return 1;\n  } else if ( distance < 0 && delta < 0 ) {\n    // boost to previous if moving towards the left, and negative velocity\n    return -1;\n  }\n  return 0;\n};\n\n// ----- scroll ----- //\n\nproto.onscroll = function() {\n  let scroll = getScrollPosition();\n  let scrollMoveX = this.pointerDownScroll.x - scroll.x;\n  let scrollMoveY = this.pointerDownScroll.y - scroll.y;\n  // cancel click/tap if scroll is too much\n  if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {\n    this.pointerDone();\n  }\n};\n\n// ----- utils ----- //\n\nfunction getScrollPosition() {\n  return {\n    x: window.pageXOffset,\n    y: window.pageYOffset,\n  };\n}\n\n// -----  ----- //\n\nreturn Flickity;\n\n} ) );\n// prev/next buttons\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('./core') );\n  } else {\n    // browser global\n    factory( window.Flickity );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity ) {\n\nconst svgURI = 'http://www.w3.org/2000/svg';\n\n// -------------------------- PrevNextButton -------------------------- //\n\nfunction PrevNextButton( increment, direction, arrowShape ) {\n  this.increment = increment;\n  this.direction = direction;\n  this.isPrevious = increment === 'previous';\n  this.isLeft = direction === 'left';\n  this._create( arrowShape );\n}\n\nPrevNextButton.prototype._create = function( arrowShape ) {\n  // properties\n  let element = this.element = document.createElement('button');\n  element.className = `flickity-button flickity-prev-next-button ${this.increment}`;\n  let label = this.isPrevious ? 'Previous' : 'Next';\n  // prevent button from submitting form https://stackoverflow.com/a/10836076/182183\n  element.setAttribute( 'type', 'button' );\n  element.setAttribute( 'aria-label', label );\n  // init as disabled\n  this.disable();\n  // create arrow\n  let svg = this.createSVG( label, arrowShape );\n  element.append( svg );\n};\n\nPrevNextButton.prototype.createSVG = function( label, arrowShape ) {\n  let svg = document.createElementNS( svgURI, 'svg' );\n  svg.setAttribute( 'class', 'flickity-button-icon' );\n  svg.setAttribute( 'viewBox', '0 0 100 100' );\n  // add title #1189\n  let title = document.createElementNS( svgURI, 'title' );\n  title.append( label );\n  // add path\n  let path = document.createElementNS( svgURI, 'path' );\n  let pathMovements = getArrowMovements( arrowShape );\n  path.setAttribute( 'd', pathMovements );\n  path.setAttribute( 'class', 'arrow' );\n  // rotate arrow\n  if ( !this.isLeft ) {\n    path.setAttribute( 'transform', 'translate(100, 100) rotate(180)' );\n  }\n  svg.append( title, path );\n  return svg;\n};\n\n// get SVG path movmement\nfunction getArrowMovements( shape ) {\n  // use shape as movement if string\n  if ( typeof shape == 'string' ) return shape;\n\n  let { x0, x1, x2, x3, y1, y2 } = shape;\n\n  // create movement string\n  return `M ${x0}, 50\n    L ${x1}, ${y1 + 50}\n    L ${x2}, ${y2 + 50}\n    L ${x3}, 50\n    L ${x2}, ${50 - y2}\n    L ${x1}, ${50 - y1}\n    Z`;\n}\n\n// -----  ----- //\n\nPrevNextButton.prototype.enable = function() {\n  this.element.removeAttribute('disabled');\n};\n\nPrevNextButton.prototype.disable = function() {\n  this.element.setAttribute( 'disabled', true );\n};\n\n// -------------------------- Flickity prototype -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  prevNextButtons: true,\n  arrowShape: {\n    x0: 10,\n    x1: 60, y1: 50,\n    x2: 70, y2: 40,\n    x3: 30,\n  },\n} );\n\nFlickity.create.prevNextButtons = function() {\n  if ( !this.options.prevNextButtons ) return;\n\n  let { rightToLeft, arrowShape } = this.options;\n  let prevDirection = rightToLeft ? 'right' : 'left';\n  let nextDirection = rightToLeft ? 'left' : 'right';\n  this.prevButton = new PrevNextButton( 'previous', prevDirection, arrowShape );\n  this.nextButton = new PrevNextButton( 'next', nextDirection, arrowShape );\n  this.focusableElems.push( this.prevButton.element );\n  this.focusableElems.push( this.nextButton.element );\n\n  this.handlePrevButtonClick = () => {\n    this.uiChange();\n    this.previous();\n  };\n\n  this.handleNextButtonClick = () => {\n    this.uiChange();\n    this.next();\n  };\n\n  this.on( 'activate', this.activatePrevNextButtons );\n  this.on( 'select', this.updatePrevNextButtons );\n};\n\nlet proto = Flickity.prototype;\n\nproto.updatePrevNextButtons = function() {\n  let lastIndex = this.slides.length ? this.slides.length - 1 : 0;\n  this.updatePrevNextButton( this.prevButton, 0 );\n  this.updatePrevNextButton( this.nextButton, lastIndex );\n};\n\nproto.updatePrevNextButton = function( button, disabledIndex ) {\n  // enable is wrapAround and at least 2 slides\n  if ( this.isWrapping && this.slides.length > 1 ) {\n    button.enable();\n    return;\n  }\n\n  let isEnabled = this.selectedIndex !== disabledIndex;\n  button[ isEnabled ? 'enable' : 'disable' ]();\n  // if disabling button that is focused,\n  // shift focus to element to maintain keyboard accessibility\n  let isDisabledFocused = !isEnabled && document.activeElement === button.element;\n  if ( isDisabledFocused ) this.focus();\n};\n\nproto.activatePrevNextButtons = function() {\n  this.prevButton.element.addEventListener( 'click', this.handlePrevButtonClick );\n  this.nextButton.element.addEventListener( 'click', this.handleNextButtonClick );\n  this.element.append( this.prevButton.element, this.nextButton.element );\n  this.on( 'deactivate', this.deactivatePrevNextButtons );\n};\n\nproto.deactivatePrevNextButtons = function() {\n  this.prevButton.element.remove();\n  this.nextButton.element.remove();\n  this.prevButton.element.removeEventListener( 'click', this.handlePrevButtonClick );\n  this.nextButton.element.removeEventListener( 'click', this.handleNextButtonClick );\n  this.off( 'deactivate', this.deactivatePrevNextButtons );\n};\n\n// --------------------------  -------------------------- //\n\nFlickity.PrevNextButton = PrevNextButton;\n\nreturn Flickity;\n\n} ) );\n// page dots\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\n// -------------------------- PageDots -------------------------- //\n\nfunction PageDots() {\n  // create holder element\n  this.holder = document.createElement('div');\n  this.holder.className = 'flickity-page-dots';\n  // create dots, array of elements\n  this.dots = [];\n}\n\nPageDots.prototype.setDots = function( slidesLength ) {\n  // get difference between number of slides and number of dots\n  let delta = slidesLength - this.dots.length;\n  if ( delta > 0 ) {\n    this.addDots( delta );\n  } else if ( delta < 0 ) {\n    this.removeDots( -delta );\n  }\n};\n\nPageDots.prototype.addDots = function( count ) {\n  let newDots = new Array( count ).fill()\n    .map( ( item, i ) => {\n      let dot = document.createElement('button');\n      dot.setAttribute( 'type', 'button' );\n      let num = i + 1 + this.dots.length;\n      dot.className = 'flickity-page-dot';\n      dot.textContent = `View slide ${num}`;\n      return dot;\n    } );\n\n  this.holder.append( ...newDots );\n  this.dots = this.dots.concat( newDots );\n};\n\nPageDots.prototype.removeDots = function( count ) {\n  // remove from this.dots collection\n  let removeDots = this.dots.splice( this.dots.length - count, count );\n  // remove from DOM\n  removeDots.forEach( ( dot ) => dot.remove() );\n};\n\nPageDots.prototype.updateSelected = function( index ) {\n  // remove selected class on previous\n  if ( this.selectedDot ) {\n    this.selectedDot.classList.remove('is-selected');\n    this.selectedDot.removeAttribute('aria-current');\n  }\n  // don't proceed if no dots\n  if ( !this.dots.length ) return;\n\n  this.selectedDot = this.dots[ index ];\n  this.selectedDot.classList.add('is-selected');\n  this.selectedDot.setAttribute( 'aria-current', 'step' );\n};\n\nFlickity.PageDots = PageDots;\n\n// -------------------------- Flickity -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  pageDots: true,\n} );\n\nFlickity.create.pageDots = function() {\n  if ( !this.options.pageDots ) return;\n\n  this.pageDots = new PageDots();\n  this.handlePageDotsClick = this.onPageDotsClick.bind( this );\n  // events\n  this.on( 'activate', this.activatePageDots );\n  this.on( 'select', this.updateSelectedPageDots );\n  this.on( 'cellChange', this.updatePageDots );\n  this.on( 'resize', this.updatePageDots );\n  this.on( 'deactivate', this.deactivatePageDots );\n};\n\nlet proto = Flickity.prototype;\n\nproto.activatePageDots = function() {\n  this.pageDots.setDots( this.slides.length );\n  this.focusableElems.push( ...this.pageDots.dots );\n  this.pageDots.holder.addEventListener( 'click', this.handlePageDotsClick );\n  this.element.append( this.pageDots.holder );\n};\n\nproto.onPageDotsClick = function( event ) {\n  let index = this.pageDots.dots.indexOf( event.target );\n  if ( index === -1 ) return; // only dot clicks\n\n  this.uiChange();\n  this.select( index );\n};\n\nproto.updateSelectedPageDots = function() {\n  this.pageDots.updateSelected( this.selectedIndex );\n};\n\nproto.updatePageDots = function() {\n  this.pageDots.dots.forEach( ( dot ) => {\n    utils.removeFrom( this.focusableElems, dot );\n  } );\n  this.pageDots.setDots( this.slides.length );\n  this.focusableElems.push( ...this.pageDots.dots );\n};\n\nproto.deactivatePageDots = function() {\n  this.pageDots.holder.remove();\n  this.pageDots.holder.removeEventListener( 'click', this.handlePageDotsClick );\n};\n\n// -----  ----- //\n\nFlickity.PageDots = PageDots;\n\nreturn Flickity;\n\n} ) );\n// player & autoPlay\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('./core') );\n  } else {\n    // browser global\n    factory( window.Flickity );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity ) {\n\n// -------------------------- Player -------------------------- //\n\nfunction Player( autoPlay, onTick ) {\n  this.autoPlay = autoPlay;\n  this.onTick = onTick;\n  this.state = 'stopped';\n  // visibility change event handler\n  this.onVisibilityChange = this.visibilityChange.bind( this );\n  this.onVisibilityPlay = this.visibilityPlay.bind( this );\n}\n\n// start play\nPlayer.prototype.play = function() {\n  if ( this.state === 'playing' ) return;\n\n  // do not play if page is hidden, start playing when page is visible\n  let isPageHidden = document.hidden;\n  if ( isPageHidden ) {\n    document.addEventListener( 'visibilitychange', this.onVisibilityPlay );\n    return;\n  }\n\n  this.state = 'playing';\n  // listen to visibility change\n  document.addEventListener( 'visibilitychange', this.onVisibilityChange );\n  // start ticking\n  this.tick();\n};\n\nPlayer.prototype.tick = function() {\n  // do not tick if not playing\n  if ( this.state !== 'playing' ) return;\n\n  // default to 3 seconds\n  let time = typeof this.autoPlay == 'number' ? this.autoPlay : 3000;\n  // HACK: reset ticks if stopped and started within interval\n  this.clear();\n  this.timeout = setTimeout( () => {\n    this.onTick();\n    this.tick();\n  }, time );\n};\n\nPlayer.prototype.stop = function() {\n  this.state = 'stopped';\n  this.clear();\n  // remove visibility change event\n  document.removeEventListener( 'visibilitychange', this.onVisibilityChange );\n};\n\nPlayer.prototype.clear = function() {\n  clearTimeout( this.timeout );\n};\n\nPlayer.prototype.pause = function() {\n  if ( this.state === 'playing' ) {\n    this.state = 'paused';\n    this.clear();\n  }\n};\n\nPlayer.prototype.unpause = function() {\n  // re-start play if paused\n  if ( this.state === 'paused' ) this.play();\n};\n\n// pause if page visibility is hidden, unpause if visible\nPlayer.prototype.visibilityChange = function() {\n  let isPageHidden = document.hidden;\n  this[ isPageHidden ? 'pause' : 'unpause' ]();\n};\n\nPlayer.prototype.visibilityPlay = function() {\n  this.play();\n  document.removeEventListener( 'visibilitychange', this.onVisibilityPlay );\n};\n\n// -------------------------- Flickity -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  pauseAutoPlayOnHover: true,\n} );\n\nFlickity.create.player = function() {\n  this.player = new Player( this.options.autoPlay, () => {\n    this.next( true );\n  } );\n\n  this.on( 'activate', this.activatePlayer );\n  this.on( 'uiChange', this.stopPlayer );\n  this.on( 'pointerDown', this.stopPlayer );\n  this.on( 'deactivate', this.deactivatePlayer );\n};\n\nlet proto = Flickity.prototype;\n\nproto.activatePlayer = function() {\n  if ( !this.options.autoPlay ) return;\n\n  this.player.play();\n  this.element.addEventListener( 'mouseenter', this );\n};\n\n// Player API, don't hate the ... thanks I know where the door is\n\nproto.playPlayer = function() {\n  this.player.play();\n};\n\nproto.stopPlayer = function() {\n  this.player.stop();\n};\n\nproto.pausePlayer = function() {\n  this.player.pause();\n};\n\nproto.unpausePlayer = function() {\n  this.player.unpause();\n};\n\nproto.deactivatePlayer = function() {\n  this.player.stop();\n  this.element.removeEventListener( 'mouseenter', this );\n};\n\n// ----- mouseenter/leave ----- //\n\n// pause auto-play on hover\nproto.onmouseenter = function() {\n  if ( !this.options.pauseAutoPlayOnHover ) return;\n\n  this.player.pause();\n  this.element.addEventListener( 'mouseleave', this );\n};\n\n// resume auto-play on hover off\nproto.onmouseleave = function() {\n  this.player.unpause();\n  this.element.removeEventListener( 'mouseleave', this );\n};\n\n// -----  ----- //\n\nFlickity.Player = Player;\n\nreturn Flickity;\n\n} ) );\n// add, remove cell\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\n// append cells to a document fragment\nfunction getCellsFragment( cells ) {\n  let fragment = document.createDocumentFragment();\n  cells.forEach( ( cell ) => fragment.appendChild( cell.element ) );\n  return fragment;\n}\n\n// -------------------------- add/remove cell prototype -------------------------- //\n\nlet proto = Flickity.prototype;\n\n/**\n * Insert, prepend, or append cells\n * @param {[Element, Array, NodeList]} elems - Elements to insert\n * @param {Integer} index - Zero-based number to insert\n */\nproto.insert = function( elems, index ) {\n  let cells = this._makeCells( elems );\n  if ( !cells || !cells.length ) return;\n\n  let len = this.cells.length;\n  // default to append\n  index = index === undefined ? len : index;\n  // add cells with document fragment\n  let fragment = getCellsFragment( cells );\n  // append to slider\n  let isAppend = index === len;\n  if ( isAppend ) {\n    this.slider.appendChild( fragment );\n  } else {\n    let insertCellElement = this.cells[ index ].element;\n    this.slider.insertBefore( fragment, insertCellElement );\n  }\n  // add to this.cells\n  if ( index === 0 ) {\n    // prepend, add to start\n    this.cells = cells.concat( this.cells );\n  } else if ( isAppend ) {\n    // append, add to end\n    this.cells = this.cells.concat( cells );\n  } else {\n    // insert in this.cells\n    let endCells = this.cells.splice( index, len - index );\n    this.cells = this.cells.concat( cells ).concat( endCells );\n  }\n\n  this._sizeCells( cells );\n  this.cellChange( index );\n  this.positionSliderAtSelected();\n};\n\nproto.append = function( elems ) {\n  this.insert( elems, this.cells.length );\n};\n\nproto.prepend = function( elems ) {\n  this.insert( elems, 0 );\n};\n\n/**\n * Remove cells\n * @param {[Element, Array, NodeList]} elems - ELements to remove\n */\nproto.remove = function( elems ) {\n  let cells = this.getCells( elems );\n  if ( !cells || !cells.length ) return;\n\n  let minCellIndex = this.cells.length - 1;\n  // remove cells from collection & DOM\n  cells.forEach( ( cell ) => {\n    cell.remove();\n    let index = this.cells.indexOf( cell );\n    minCellIndex = Math.min( index, minCellIndex );\n    utils.removeFrom( this.cells, cell );\n  } );\n\n  this.cellChange( minCellIndex );\n  this.positionSliderAtSelected();\n};\n\n/**\n * logic to be run after a cell's size changes\n * @param {Element} elem - cell's element\n */\nproto.cellSizeChange = function( elem ) {\n  let cell = this.getCell( elem );\n  if ( !cell ) return;\n\n  cell.getSize();\n\n  let index = this.cells.indexOf( cell );\n  this.cellChange( index );\n  // do not position slider after lazy load\n};\n\n/**\n * logic any time a cell is changed: added, removed, or size changed\n * @param {Integer} changedCellIndex - index of the changed cell, optional\n */\nproto.cellChange = function( changedCellIndex ) {\n  let prevSelectedElem = this.selectedElement;\n  this._positionCells( changedCellIndex );\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n  // update selectedIndex, try to maintain position & select previous selected element\n  let cell = this.getCell( prevSelectedElem );\n  if ( cell ) this.selectedIndex = this.getCellSlideIndex( cell );\n  this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex );\n\n  this.emitEvent( 'cellChange', [ changedCellIndex ] );\n  // position slider\n  this.select( this.selectedIndex );\n};\n\n// -----  ----- //\n\nreturn Flickity;\n\n} ) );\n// lazyload\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\nconst lazyAttr = 'data-flickity-lazyload';\nconst lazySrcAttr = `${lazyAttr}-src`;\nconst lazySrcsetAttr = `${lazyAttr}-srcset`;\nconst imgSelector = `img[${lazyAttr}], img[${lazySrcAttr}], ` +\n  `img[${lazySrcsetAttr}], source[${lazySrcsetAttr}]`;\n\nFlickity.create.lazyLoad = function() {\n  this.on( 'select', this.lazyLoad );\n\n  this.handleLazyLoadComplete = this.onLazyLoadComplete.bind( this );\n};\n\nlet proto = Flickity.prototype;\n\nproto.lazyLoad = function() {\n  let { lazyLoad } = this.options;\n  if ( !lazyLoad ) return;\n\n  // get adjacent cells, use lazyLoad option for adjacent count\n  let adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;\n  // lazy load images\n  this.getAdjacentCellElements( adjCount )\n    .map( getCellLazyImages )\n    .flat()\n    .forEach( ( img ) => new LazyLoader( img, this.handleLazyLoadComplete ) );\n};\n\nfunction getCellLazyImages( cellElem ) {\n  // check if cell element is lazy image\n  if ( cellElem.matches('img') ) {\n    let cellAttr = cellElem.getAttribute( lazyAttr );\n    let cellSrcAttr = cellElem.getAttribute( lazySrcAttr );\n    let cellSrcsetAttr = cellElem.getAttribute( lazySrcsetAttr );\n    if ( cellAttr || cellSrcAttr || cellSrcsetAttr ) {\n      return cellElem;\n    }\n  }\n  // select lazy images in cell\n  return [ ...cellElem.querySelectorAll( imgSelector ) ];\n}\n\nproto.onLazyLoadComplete = function( img, event ) {\n  let cell = this.getParentCell( img );\n  let cellElem = cell && cell.element;\n  this.cellSizeChange( cellElem );\n\n  this.dispatchEvent( 'lazyLoad', event, cellElem );\n};\n\n// -------------------------- LazyLoader -------------------------- //\n\n/**\n * class to handle loading images\n * @param {Image} img - Image element\n * @param {Function} onComplete - callback function\n */\nfunction LazyLoader( img, onComplete ) {\n  this.img = img;\n  this.onComplete = onComplete;\n  this.load();\n}\n\nLazyLoader.prototype.handleEvent = utils.handleEvent;\n\nLazyLoader.prototype.load = function() {\n  this.img.addEventListener( 'load', this );\n  this.img.addEventListener( 'error', this );\n  // get src & srcset\n  let src = this.img.getAttribute( lazyAttr ) ||\n    this.img.getAttribute( lazySrcAttr );\n  let srcset = this.img.getAttribute( lazySrcsetAttr );\n  // set src & serset\n  this.img.src = src;\n  if ( srcset ) this.img.setAttribute( 'srcset', srcset );\n  // remove attr\n  this.img.removeAttribute( lazyAttr );\n  this.img.removeAttribute( lazySrcAttr );\n  this.img.removeAttribute( lazySrcsetAttr );\n};\n\nLazyLoader.prototype.onload = function( event ) {\n  this.complete( event, 'flickity-lazyloaded' );\n};\n\nLazyLoader.prototype.onerror = function( event ) {\n  this.complete( event, 'flickity-lazyerror' );\n};\n\nLazyLoader.prototype.complete = function( event, className ) {\n  // unbind events\n  this.img.removeEventListener( 'load', this );\n  this.img.removeEventListener( 'error', this );\n  let mediaElem = this.img.parentNode.matches('picture') ? this.img.parentNode : this.img;\n  mediaElem.classList.add( className );\n\n  this.onComplete( this.img, event );\n};\n\n// -----  ----- //\n\nFlickity.LazyLoader = LazyLoader;\n\nreturn Flickity;\n\n} ) );\n// imagesloaded\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('imagesloaded'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.imagesLoaded,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( Flickity, imagesLoaded ) {\n\nFlickity.create.imagesLoaded = function() {\n  this.on( 'activate', this.imagesLoaded );\n};\n\nFlickity.prototype.imagesLoaded = function() {\n  if ( !this.options.imagesLoaded ) return;\n\n  let onImagesLoadedProgress = ( instance, image ) => {\n    let cell = this.getParentCell( image.img );\n    this.cellSizeChange( cell && cell.element );\n    if ( !this.options.freeScroll ) this.positionSliderAtSelected();\n  };\n  imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );\n};\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/add-remove-cell.js",
    "content": "// add, remove cell\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\n// append cells to a document fragment\nfunction getCellsFragment( cells ) {\n  let fragment = document.createDocumentFragment();\n  cells.forEach( ( cell ) => fragment.appendChild( cell.element ) );\n  return fragment;\n}\n\n// -------------------------- add/remove cell prototype -------------------------- //\n\nlet proto = Flickity.prototype;\n\n/**\n * Insert, prepend, or append cells\n * @param {[Element, Array, NodeList]} elems - Elements to insert\n * @param {Integer} index - Zero-based number to insert\n */\nproto.insert = function( elems, index ) {\n  let cells = this._makeCells( elems );\n  if ( !cells || !cells.length ) return;\n\n  let len = this.cells.length;\n  // default to append\n  index = index === undefined ? len : index;\n  // add cells with document fragment\n  let fragment = getCellsFragment( cells );\n  // append to slider\n  let isAppend = index === len;\n  if ( isAppend ) {\n    this.slider.appendChild( fragment );\n  } else {\n    let insertCellElement = this.cells[ index ].element;\n    this.slider.insertBefore( fragment, insertCellElement );\n  }\n  // add to this.cells\n  if ( index === 0 ) {\n    // prepend, add to start\n    this.cells = cells.concat( this.cells );\n  } else if ( isAppend ) {\n    // append, add to end\n    this.cells = this.cells.concat( cells );\n  } else {\n    // insert in this.cells\n    let endCells = this.cells.splice( index, len - index );\n    this.cells = this.cells.concat( cells ).concat( endCells );\n  }\n\n  this._sizeCells( cells );\n  this.cellChange( index );\n  this.positionSliderAtSelected();\n};\n\nproto.append = function( elems ) {\n  this.insert( elems, this.cells.length );\n};\n\nproto.prepend = function( elems ) {\n  this.insert( elems, 0 );\n};\n\n/**\n * Remove cells\n * @param {[Element, Array, NodeList]} elems - ELements to remove\n */\nproto.remove = function( elems ) {\n  let cells = this.getCells( elems );\n  if ( !cells || !cells.length ) return;\n\n  let minCellIndex = this.cells.length - 1;\n  // remove cells from collection & DOM\n  cells.forEach( ( cell ) => {\n    cell.remove();\n    let index = this.cells.indexOf( cell );\n    minCellIndex = Math.min( index, minCellIndex );\n    utils.removeFrom( this.cells, cell );\n  } );\n\n  this.cellChange( minCellIndex );\n  this.positionSliderAtSelected();\n};\n\n/**\n * logic to be run after a cell's size changes\n * @param {Element} elem - cell's element\n */\nproto.cellSizeChange = function( elem ) {\n  let cell = this.getCell( elem );\n  if ( !cell ) return;\n\n  cell.getSize();\n\n  let index = this.cells.indexOf( cell );\n  this.cellChange( index );\n  // do not position slider after lazy load\n};\n\n/**\n * logic any time a cell is changed: added, removed, or size changed\n * @param {Integer} changedCellIndex - index of the changed cell, optional\n */\nproto.cellChange = function( changedCellIndex ) {\n  let prevSelectedElem = this.selectedElement;\n  this._positionCells( changedCellIndex );\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n  // update selectedIndex, try to maintain position & select previous selected element\n  let cell = this.getCell( prevSelectedElem );\n  if ( cell ) this.selectedIndex = this.getCellSlideIndex( cell );\n  this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex );\n\n  this.emitEvent( 'cellChange', [ changedCellIndex ] );\n  // position slider\n  this.select( this.selectedIndex );\n};\n\n// -----  ----- //\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/animate.js",
    "content": "// animate\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('fizzy-ui-utils') );\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.animatePrototype = factory( window.fizzyUIUtils );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( utils ) {\n\n// -------------------------- animate -------------------------- //\n\nlet proto = {};\n\nproto.startAnimation = function() {\n  if ( this.isAnimating ) return;\n\n  this.isAnimating = true;\n  this.restingFrames = 0;\n  this.animate();\n};\n\nproto.animate = function() {\n  this.applyDragForce();\n  this.applySelectedAttraction();\n\n  let previousX = this.x;\n\n  this.integratePhysics();\n  this.positionSlider();\n  this.settle( previousX );\n  // animate next frame\n  if ( this.isAnimating ) requestAnimationFrame( () => this.animate() );\n};\n\nproto.positionSlider = function() {\n  let x = this.x;\n  // wrap position around\n  if ( this.isWrapping ) {\n    x = utils.modulo( x, this.slideableWidth ) - this.slideableWidth;\n    this.shiftWrapCells( x );\n  }\n\n  this.setTranslateX( x, this.isAnimating );\n  this.dispatchScrollEvent();\n};\n\nproto.setTranslateX = function( x, is3d ) {\n  x += this.cursorPosition;\n  // reverse if right-to-left and using transform\n  if ( this.options.rightToLeft ) x = -x;\n  let translateX = this.getPositionValue( x );\n  // use 3D transforms for hardware acceleration on iOS\n  // but use 2D when settled, for better font-rendering\n  this.slider.style.transform = is3d ?\n    `translate3d(${translateX},0,0)` : `translateX(${translateX})`;\n};\n\nproto.dispatchScrollEvent = function() {\n  let firstSlide = this.slides[0];\n  if ( !firstSlide ) return;\n\n  let positionX = -this.x - firstSlide.target;\n  let progress = positionX / this.slidesWidth;\n  this.dispatchEvent( 'scroll', null, [ progress, positionX ] );\n};\n\nproto.positionSliderAtSelected = function() {\n  if ( !this.cells.length ) return;\n\n  this.x = -this.selectedSlide.target;\n  this.velocity = 0; // stop wobble\n  this.positionSlider();\n};\n\nproto.getPositionValue = function( position ) {\n  if ( this.options.percentPosition ) {\n    // percent position, round to 2 digits, like 12.34%\n    return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%';\n  } else {\n    // pixel positioning\n    return Math.round( position ) + 'px';\n  }\n};\n\nproto.settle = function( previousX ) {\n  // keep track of frames where x hasn't moved\n  let isResting = !this.isPointerDown &&\n      Math.round( this.x * 100 ) === Math.round( previousX * 100 );\n  if ( isResting ) this.restingFrames++;\n  // stop animating if resting for 3 or more frames\n  if ( this.restingFrames > 2 ) {\n    this.isAnimating = false;\n    delete this.isFreeScrolling;\n    // render position with translateX when settled\n    this.positionSlider();\n    this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );\n  }\n};\n\nproto.shiftWrapCells = function( x ) {\n  // shift before cells\n  let beforeGap = this.cursorPosition + x;\n  this._shiftCells( this.beforeShiftCells, beforeGap, -1 );\n  // shift after cells\n  let afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );\n  this._shiftCells( this.afterShiftCells, afterGap, 1 );\n};\n\nproto._shiftCells = function( cells, gap, shift ) {\n  cells.forEach( ( cell ) => {\n    let cellShift = gap > 0 ? shift : 0;\n    this._wrapShiftCell( cell, cellShift );\n    gap -= cell.size.outerWidth;\n  } );\n};\n\nproto._unshiftCells = function( cells ) {\n  if ( !cells || !cells.length ) return;\n\n  cells.forEach( ( cell ) => this._wrapShiftCell( cell, 0 ) );\n};\n\n// @param {Integer} shift - 0, 1, or -1\nproto._wrapShiftCell = function( cell, shift ) {\n  this._renderCellPosition( cell, cell.x + this.slideableWidth * shift );\n};\n\n// -------------------------- physics -------------------------- //\n\nproto.integratePhysics = function() {\n  this.x += this.velocity;\n  this.velocity *= this.getFrictionFactor();\n};\n\nproto.applyForce = function( force ) {\n  this.velocity += force;\n};\n\nproto.getFrictionFactor = function() {\n  return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];\n};\n\nproto.getRestingPosition = function() {\n  // my thanks to Steven Wittens, who simplified this math greatly\n  return this.x + this.velocity / ( 1 - this.getFrictionFactor() );\n};\n\nproto.applyDragForce = function() {\n  if ( !this.isDraggable || !this.isPointerDown ) return;\n\n  // change the position to drag position by applying force\n  let dragVelocity = this.dragX - this.x;\n  let dragForce = dragVelocity - this.velocity;\n  this.applyForce( dragForce );\n};\n\nproto.applySelectedAttraction = function() {\n  // do not attract if pointer down or no slides\n  let dragDown = this.isDraggable && this.isPointerDown;\n  if ( dragDown || this.isFreeScrolling || !this.slides.length ) return;\n\n  let distance = this.selectedSlide.target * -1 - this.x;\n  let force = distance * this.options.selectedAttraction;\n  this.applyForce( force );\n};\n\nreturn proto;\n\n} ) );\n"
  },
  {
    "path": "js/cell.js",
    "content": "// Flickity.Cell\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('get-size') );\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.Cell = factory( window.getSize );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( getSize ) {\n\nconst cellClassName = 'flickity-cell';\n\nfunction Cell( elem ) {\n  this.element = elem;\n  this.element.classList.add( cellClassName );\n\n  this.x = 0;\n  this.unselect();\n}\n\nlet proto = Cell.prototype;\n\nproto.destroy = function() {\n  // reset style\n  this.unselect();\n  this.element.classList.remove( cellClassName );\n  this.element.style.transform = '';\n  this.element.removeAttribute('aria-hidden');\n};\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n};\n\nproto.select = function() {\n  this.element.classList.add('is-selected');\n  this.element.removeAttribute('aria-hidden');\n};\n\nproto.unselect = function() {\n  this.element.classList.remove('is-selected');\n  this.element.setAttribute( 'aria-hidden', 'true' );\n};\n\nproto.remove = function() {\n  this.element.remove();\n};\n\nreturn Cell;\n\n} ) );\n"
  },
  {
    "path": "js/core.js",
    "content": "// Flickity main\n/* eslint-disable max-params */\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        window,\n        require('ev-emitter'),\n        require('get-size'),\n        require('fizzy-ui-utils'),\n        require('./cell'),\n        require('./slide'),\n        require('./animate'),\n    );\n  } else {\n    // browser global\n    let _Flickity = window.Flickity;\n\n    window.Flickity = factory(\n        window,\n        window.EvEmitter,\n        window.getSize,\n        window.fizzyUIUtils,\n        _Flickity.Cell,\n        _Flickity.Slide,\n        _Flickity.animatePrototype,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) {\n/* eslint-enable max-params */\n\n// vars\nconst { getComputedStyle, console } = window;\nlet { jQuery } = window;\n\n// -------------------------- Flickity -------------------------- //\n\n// globally unique identifiers\nlet GUID = 0;\n// internal store of all Flickity intances\nlet instances = {};\n\nfunction Flickity( element, options ) {\n  let queryElement = utils.getQueryElement( element );\n  if ( !queryElement ) {\n    if ( console ) console.error(`Bad element for Flickity: ${queryElement || element}`);\n    return;\n  }\n  this.element = queryElement;\n  // do not initialize twice on same element\n  if ( this.element.flickityGUID ) {\n    let instance = instances[ this.element.flickityGUID ];\n    if ( instance ) instance.option( options );\n    return instance;\n  }\n\n  // add jQuery\n  if ( jQuery ) {\n    this.$element = jQuery( this.element );\n  }\n  // options\n  this.options = { ...this.constructor.defaults };\n  this.option( options );\n\n  // kick things off\n  this._create();\n}\n\nFlickity.defaults = {\n  accessibility: true,\n  // adaptiveHeight: false,\n  cellAlign: 'center',\n  // cellSelector: undefined,\n  // contain: false,\n  freeScrollFriction: 0.075, // friction when free-scrolling\n  friction: 0.28, // friction when selecting\n  namespaceJQueryEvents: true,\n  // initialIndex: 0,\n  percentPosition: true,\n  resize: true,\n  selectedAttraction: 0.025,\n  setGallerySize: true,\n  // watchCSS: false,\n  // wrapAround: false\n};\n\n// hash of methods triggered on _create()\nFlickity.create = {};\n\nlet proto = Flickity.prototype;\n// inherit EventEmitter\nObject.assign( proto, EvEmitter.prototype );\n\nproto._create = function() {\n  let { resize, watchCSS, rightToLeft } = this.options;\n  // add id for Flickity.data\n  let id = this.guid = ++GUID;\n  this.element.flickityGUID = id; // expando\n  instances[ id ] = this; // associate via id\n  // initial properties\n  this.selectedIndex = 0;\n  // how many frames slider has been in same position\n  this.restingFrames = 0;\n  // initial physics properties\n  this.x = 0;\n  this.velocity = 0;\n  this.beginMargin = rightToLeft ? 'marginRight' : 'marginLeft';\n  this.endMargin = rightToLeft ? 'marginLeft' : 'marginRight';\n  // create viewport & slider\n  this.viewport = document.createElement('div');\n  this.viewport.className = 'flickity-viewport';\n  this._createSlider();\n  // used for keyboard navigation\n  this.focusableElems = [ this.element ];\n\n  if ( resize || watchCSS ) {\n    window.addEventListener( 'resize', this );\n  }\n\n  // add listeners from on option\n  for ( let eventName in this.options.on ) {\n    let listener = this.options.on[ eventName ];\n    this.on( eventName, listener );\n  }\n\n  for ( let method in Flickity.create ) {\n    Flickity.create[ method ].call( this );\n  }\n\n  if ( watchCSS ) {\n    this.watchCSS();\n  } else {\n    this.activate();\n  }\n};\n\n/**\n * set options\n * @param {Object} opts - options to extend\n */\nproto.option = function( opts ) {\n  Object.assign( this.options, opts );\n};\n\nproto.activate = function() {\n  if ( this.isActive ) return;\n\n  this.isActive = true;\n  this.element.classList.add('flickity-enabled');\n  if ( this.options.rightToLeft ) {\n    this.element.classList.add('flickity-rtl');\n  }\n\n  this.getSize();\n  // move initial cell elements so they can be loaded as cells\n  let cellElems = this._filterFindCellElements( this.element.children );\n  this.slider.append( ...cellElems );\n  this.viewport.append( this.slider );\n  this.element.append( this.viewport );\n  // get cells from children\n  this.reloadCells();\n\n  if ( this.options.accessibility ) {\n    // allow element to focusable\n    this.element.tabIndex = 0;\n    // listen for key presses\n    this.element.addEventListener( 'keydown', this );\n  }\n\n  this.emitEvent('activate');\n  this.selectInitialIndex();\n  // flag for initial activation, for using initialIndex\n  this.isInitActivated = true;\n  // ready event. #493\n  this.dispatchEvent('ready');\n};\n\n// slider positions the cells\nproto._createSlider = function() {\n  // slider element does all the positioning\n  let slider = document.createElement('div');\n  slider.className = 'flickity-slider';\n  this.slider = slider;\n};\n\nproto._filterFindCellElements = function( elems ) {\n  return utils.filterFindElements( elems, this.options.cellSelector );\n};\n\n// goes through all children\nproto.reloadCells = function() {\n  // collection of item elements\n  this.cells = this._makeCells( this.slider.children );\n  this.positionCells();\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n};\n\n/**\n * turn elements into Flickity.Cells\n * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells\n * @returns {Array} items - collection of new Flickity Cells\n */\nproto._makeCells = function( elems ) {\n  let cellElems = this._filterFindCellElements( elems );\n\n  // create new Cells for collection\n  return cellElems.map( ( cellElem ) => new Cell( cellElem ) );\n};\n\nproto.getLastCell = function() {\n  return this.cells[ this.cells.length - 1 ];\n};\n\nproto.getLastSlide = function() {\n  return this.slides[ this.slides.length - 1 ];\n};\n\n// positions all cells\nproto.positionCells = function() {\n  // size all cells\n  this._sizeCells( this.cells );\n  // position all cells\n  this._positionCells( 0 );\n};\n\n/**\n * position certain cells\n * @param {Integer} index - which cell to start with\n */\nproto._positionCells = function( index ) {\n  index = index || 0;\n  // also measure maxCellHeight\n  // start 0 if positioning all cells\n  this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;\n  let cellX = 0;\n  // get cellX\n  if ( index > 0 ) {\n    let startCell = this.cells[ index - 1 ];\n    cellX = startCell.x + startCell.size.outerWidth;\n  }\n\n  this.cells.slice( index ).forEach( ( cell ) => {\n    cell.x = cellX;\n    this._renderCellPosition( cell, cellX );\n    cellX += cell.size.outerWidth;\n    this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );\n  } );\n  // keep track of cellX for wrap-around\n  this.slideableWidth = cellX;\n  // slides\n  this.updateSlides();\n  // contain slides target\n  this._containSlides();\n  // update slidesWidth\n  this.slidesWidth = this.cells.length ?\n    this.getLastSlide().target - this.slides[0].target : 0;\n};\n\nproto._renderCellPosition = function( cell, x ) {\n  // render position of cell with in slider\n  let sideOffset = this.options.rightToLeft ? -1 : 1;\n  let renderX = x * sideOffset;\n  if ( this.options.percentPosition ) renderX *= this.size.innerWidth / cell.size.width;\n  let positionValue = this.getPositionValue( renderX );\n  cell.element.style.transform = `translateX( ${positionValue} )`;\n};\n\n/**\n * cell.getSize() on multiple cells\n * @param {Array} cells - cells to size\n */\nproto._sizeCells = function( cells ) {\n  cells.forEach( ( cell ) => cell.getSize() );\n};\n\n// --------------------------  -------------------------- //\n\nproto.updateSlides = function() {\n  this.slides = [];\n  if ( !this.cells.length ) return;\n\n  let { beginMargin, endMargin } = this;\n  let slide = new Slide( beginMargin, endMargin, this.cellAlign );\n  this.slides.push( slide );\n\n  let canCellFit = this._getCanCellFit();\n\n  this.cells.forEach( ( cell, i ) => {\n    // just add cell if first cell in slide\n    if ( !slide.cells.length ) {\n      slide.addCell( cell );\n      return;\n    }\n\n    let slideWidth = ( slide.outerWidth - slide.firstMargin ) +\n      ( cell.size.outerWidth - cell.size[ endMargin ] );\n\n    if ( canCellFit( i, slideWidth ) ) {\n      slide.addCell( cell );\n    } else {\n      // doesn't fit, new slide\n      slide.updateTarget();\n\n      slide = new Slide( beginMargin, endMargin, this.cellAlign );\n      this.slides.push( slide );\n      slide.addCell( cell );\n    }\n  } );\n  // last slide\n  slide.updateTarget();\n  // update .selectedSlide\n  this.updateSelectedSlide();\n};\n\nproto._getCanCellFit = function() {\n  let { groupCells } = this.options;\n  if ( !groupCells ) return () => false;\n\n  if ( typeof groupCells == 'number' ) {\n    // group by number. 3 -> [0,1,2], [3,4,5], ...\n    let number = parseInt( groupCells, 10 );\n    return ( i ) => ( i % number ) !== 0;\n  }\n  // default, group by width of slide\n  let percent = 1;\n  // parse '75%\n  let percentMatch = typeof groupCells == 'string' && groupCells.match( /^(\\d+)%$/ );\n  if ( percentMatch ) percent = parseInt( percentMatch[1], 10 ) / 100;\n  let groupWidth = ( this.size.innerWidth + 1 ) * percent;\n  return ( i, slideWidth ) => slideWidth <= groupWidth;\n};\n\n// alias _init for jQuery plugin .flickity()\nproto._init =\nproto.reposition = function() {\n  this.positionCells();\n  this.positionSliderAtSelected();\n};\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n  this.setCellAlign();\n  this.cursorPosition = this.size.innerWidth * this.cellAlign;\n};\n\nlet cellAlignShorthands = {\n  left: 0,\n  center: 0.5,\n  right: 1,\n};\n\nproto.setCellAlign = function() {\n  let { cellAlign, rightToLeft } = this.options;\n  let shorthand = cellAlignShorthands[ cellAlign ];\n  this.cellAlign = shorthand !== undefined ? shorthand : cellAlign;\n  if ( rightToLeft ) this.cellAlign = 1 - this.cellAlign;\n};\n\nproto.setGallerySize = function() {\n  if ( !this.options.setGallerySize ) return;\n\n  let height = this.options.adaptiveHeight && this.selectedSlide ?\n    this.selectedSlide.height : this.maxCellHeight;\n  this.viewport.style.height = `${height}px`;\n};\n\nproto._updateWrapShiftCells = function() {\n  // update isWrapping\n  this.isWrapping = this.getIsWrapping();\n  // only for wrap-around\n  if ( !this.isWrapping ) return;\n\n  // unshift previous cells\n  this._unshiftCells( this.beforeShiftCells );\n  this._unshiftCells( this.afterShiftCells );\n  // get before cells\n  // initial gap\n  let beforeGapX = this.cursorPosition;\n  let lastIndex = this.cells.length - 1;\n  this.beforeShiftCells = this._getGapCells( beforeGapX, lastIndex, -1 );\n  // get after cells\n  // ending gap between last cell and end of gallery viewport\n  let afterGapX = this.size.innerWidth - this.cursorPosition;\n  // start cloning at first cell, working forwards\n  this.afterShiftCells = this._getGapCells( afterGapX, 0, 1 );\n};\n\nproto.getIsWrapping = function() {\n  let { wrapAround } = this.options;\n  if ( !wrapAround || this.slides.length < 2 ) return false;\n\n  if ( wrapAround !== 'fill' ) return true;\n  // check that slides can fit\n\n  let gapWidth = this.slideableWidth - this.size.innerWidth;\n  if ( gapWidth > this.size.innerWidth ) return true; // gap * 2x big, all good\n  // check that content width - shifting cell is bigger than viewport width\n  for ( let cell of this.cells ) {\n    if ( cell.size.outerWidth > gapWidth ) return false;\n  }\n  return true;\n};\n\nproto._getGapCells = function( gapX, cellIndex, increment ) {\n  // keep adding cells until the cover the initial gap\n  let cells = [];\n  while ( gapX > 0 ) {\n    let cell = this.cells[ cellIndex ];\n    if ( !cell ) break;\n\n    cells.push( cell );\n    cellIndex += increment;\n    gapX -= cell.size.outerWidth;\n  }\n  return cells;\n};\n\n// ----- contain & wrap ----- //\n\n// contain cell targets so no excess sliding\nproto._containSlides = function() {\n  let isContaining = this.options.contain && !this.isWrapping &&\n      this.cells.length;\n  if ( !isContaining ) return;\n\n  let contentWidth = this.slideableWidth - this.getLastCell().size[ this.endMargin ];\n  // content is less than gallery size\n  let isContentSmaller = contentWidth < this.size.innerWidth;\n  if ( isContentSmaller ) {\n    // all cells fit inside gallery\n    this.slides.forEach( ( slide ) => {\n      slide.target = contentWidth * this.cellAlign;\n    } );\n  } else {\n    // contain to bounds\n    let beginBound = this.cursorPosition + this.cells[0].size[ this.beginMargin ];\n    let endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );\n    this.slides.forEach( ( slide ) => {\n      slide.target = Math.max( slide.target, beginBound );\n      slide.target = Math.min( slide.target, endBound );\n    } );\n  }\n};\n\n// ----- events ----- //\n\n/**\n * emits events via eventEmitter and jQuery events\n * @param {String} type - name of event\n * @param {Event} event - original event\n * @param {Array} args - extra arguments\n */\nproto.dispatchEvent = function( type, event, args ) {\n  let emitArgs = event ? [ event ].concat( args ) : args;\n  this.emitEvent( type, emitArgs );\n\n  if ( jQuery && this.$element ) {\n    // default trigger with type if no event\n    type += this.options.namespaceJQueryEvents ? '.flickity' : '';\n    let $event = type;\n    if ( event ) {\n      // create jQuery event\n      let jQEvent = new jQuery.Event( event );\n      jQEvent.type = type;\n      $event = jQEvent;\n    }\n    this.$element.trigger( $event, args );\n  }\n};\n\nconst unidraggerEvents = [\n  'dragStart',\n  'dragMove',\n  'dragEnd',\n  'pointerDown',\n  'pointerMove',\n  'pointerEnd',\n  'staticClick',\n];\n\nlet _emitEvent = proto.emitEvent;\nproto.emitEvent = function( eventName, args ) {\n  if ( eventName === 'staticClick' ) {\n    // add cellElem and cellIndex args to staticClick\n    let clickedCell = this.getParentCell( args[0].target );\n    let cellElem = clickedCell && clickedCell.element;\n    let cellIndex = clickedCell && this.cells.indexOf( clickedCell );\n    args = args.concat( cellElem, cellIndex );\n  }\n  // do regular thing\n  _emitEvent.call( this, eventName, args );\n  // duck-punch in jQuery events for Unidragger events\n  let isUnidraggerEvent = unidraggerEvents.includes( eventName );\n  if ( !isUnidraggerEvent || !jQuery || !this.$element ) return;\n\n  eventName += this.options.namespaceJQueryEvents ? '.flickity' : '';\n  let event = args.shift( 0 );\n  let jQEvent = new jQuery.Event( event );\n  jQEvent.type = eventName;\n  this.$element.trigger( jQEvent, args );\n};\n\n// -------------------------- select -------------------------- //\n\n/**\n * @param {Integer} index - index of the slide\n * @param {Boolean} isWrap - will wrap-around to last/first if at the end\n * @param {Boolean} isInstant - will immediately set position at selected cell\n */\nproto.select = function( index, isWrap, isInstant ) {\n  if ( !this.isActive ) return;\n\n  index = parseInt( index, 10 );\n  this._wrapSelect( index );\n\n  if ( this.isWrapping || isWrap ) {\n    index = utils.modulo( index, this.slides.length );\n  }\n  // bail if invalid index\n  if ( !this.slides[ index ] ) return;\n\n  let prevIndex = this.selectedIndex;\n  this.selectedIndex = index;\n  this.updateSelectedSlide();\n  if ( isInstant ) {\n    this.positionSliderAtSelected();\n  } else {\n    this.startAnimation();\n  }\n  if ( this.options.adaptiveHeight ) {\n    this.setGallerySize();\n  }\n  // events\n  this.dispatchEvent( 'select', null, [ index ] );\n  // change event if new index\n  if ( index !== prevIndex ) {\n    this.dispatchEvent( 'change', null, [ index ] );\n  }\n};\n\n// wraps position for wrapAround, to move to closest slide. #113\nproto._wrapSelect = function( index ) {\n  if ( !this.isWrapping ) return;\n\n  const { selectedIndex, slideableWidth, slides: { length } } = this;\n  // shift index for wrap, do not wrap dragSelect\n  if ( !this.isDragSelect ) {\n    let wrapIndex = utils.modulo( index, length );\n    // go to shortest\n    let delta = Math.abs( wrapIndex - selectedIndex );\n    let backWrapDelta = Math.abs( ( wrapIndex + length ) - selectedIndex );\n    let forewardWrapDelta = Math.abs( ( wrapIndex - length ) - selectedIndex );\n    if ( backWrapDelta < delta ) {\n      index += length;\n    } else if ( forewardWrapDelta < delta ) {\n      index -= length;\n    }\n  }\n\n  // wrap position so slider is within normal area\n  if ( index < 0 ) {\n    this.x -= slideableWidth;\n  } else if ( index >= length ) {\n    this.x += slideableWidth;\n  }\n};\n\nproto.previous = function( isWrap, isInstant ) {\n  this.select( this.selectedIndex - 1, isWrap, isInstant );\n};\n\nproto.next = function( isWrap, isInstant ) {\n  this.select( this.selectedIndex + 1, isWrap, isInstant );\n};\n\nproto.updateSelectedSlide = function() {\n  let slide = this.slides[ this.selectedIndex ];\n  // selectedIndex could be outside of slides, if triggered before resize()\n  if ( !slide ) return;\n\n  // unselect previous selected slide\n  this.unselectSelectedSlide();\n  // update new selected slide\n  this.selectedSlide = slide;\n  slide.select();\n  this.selectedCells = slide.cells;\n  this.selectedElements = slide.getCellElements();\n  // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility\n  this.selectedCell = slide.cells[0];\n  this.selectedElement = this.selectedElements[0];\n};\n\nproto.unselectSelectedSlide = function() {\n  if ( this.selectedSlide ) this.selectedSlide.unselect();\n};\n\nproto.selectInitialIndex = function() {\n  let initialIndex = this.options.initialIndex;\n  // already activated, select previous selectedIndex\n  if ( this.isInitActivated ) {\n    this.select( this.selectedIndex, false, true );\n    return;\n  }\n  // select with selector string\n  if ( initialIndex && typeof initialIndex == 'string' ) {\n    let cell = this.queryCell( initialIndex );\n    if ( cell ) {\n      this.selectCell( initialIndex, false, true );\n      return;\n    }\n  }\n\n  let index = 0;\n  // select with number\n  if ( initialIndex && this.slides[ initialIndex ] ) {\n    index = initialIndex;\n  }\n  // select instantly\n  this.select( index, false, true );\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, Number]} value - zero-based index or element to select\n * @param {Boolean} isWrap - enables wrapping around for extra index\n * @param {Boolean} isInstant - disables slide animation\n */\nproto.selectCell = function( value, isWrap, isInstant ) {\n  // get cell\n  let cell = this.queryCell( value );\n  if ( !cell ) return;\n\n  let index = this.getCellSlideIndex( cell );\n  this.select( index, isWrap, isInstant );\n};\n\nproto.getCellSlideIndex = function( cell ) {\n  // get index of slide that has cell\n  let cellSlide = this.slides.find( ( slide ) => slide.cells.includes( cell ) );\n  return this.slides.indexOf( cellSlide );\n};\n\n// -------------------------- get cells -------------------------- //\n\n/**\n * get Flickity.Cell, given an Element\n * @param {Element} elem - matching cell element\n * @returns {Flickity.Cell} cell - matching cell\n */\nproto.getCell = function( elem ) {\n  // loop through cells to get the one that matches\n  for ( let cell of this.cells ) {\n    if ( cell.element === elem ) return cell;\n  }\n};\n\n/**\n * get collection of Flickity.Cells, given Elements\n * @param {[Element, Array, NodeList]} elems - multiple elements\n * @returns {Array} cells - Flickity.Cells\n */\nproto.getCells = function( elems ) {\n  elems = utils.makeArray( elems );\n  return elems.map( ( elem ) => this.getCell( elem ) ).filter( Boolean );\n};\n\n/**\n * get cell elements\n * @returns {Array} cellElems\n */\nproto.getCellElements = function() {\n  return this.cells.map( ( cell ) => cell.element );\n};\n\n/**\n * get parent cell from an element\n * @param {Element} elem - child element\n * @returns {Flickit.Cell} cell - parent cell\n */\nproto.getParentCell = function( elem ) {\n  // first check if elem is cell\n  let cell = this.getCell( elem );\n  if ( cell ) return cell;\n\n  // try to get parent cell elem\n  let closest = elem.closest('.flickity-slider > *');\n  return this.getCell( closest );\n};\n\n/**\n * get cells adjacent to a slide\n * @param {Integer} adjCount - number of adjacent slides\n * @param {Integer} index - index of slide to start\n * @returns {Array} cells - array of Flickity.Cells\n */\nproto.getAdjacentCellElements = function( adjCount, index ) {\n  if ( !adjCount ) return this.selectedSlide.getCellElements();\n\n  index = index === undefined ? this.selectedIndex : index;\n  let len = this.slides.length;\n  let cellElems = [];\n  for ( let i = index - adjCount; i <= index + adjCount; i++ ) {\n    let slideIndex = this.isWrapping ? utils.modulo( i, len ) : i;\n    let slide = this.slides[ slideIndex ];\n    if ( slide ) {\n      cellElems = cellElems.concat( slide.getCellElements() );\n    }\n  }\n  return cellElems;\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, String, Number]} selector - element, selector string, or index\n * @returns {Flickity.Cell} - matching cell\n */\nproto.queryCell = function( selector ) {\n  if ( typeof selector == 'number' ) {\n    // use number as index\n    return this.cells[ selector ];\n  }\n  // do not select invalid selectors from hash: #123, #/. #791\n  let isSelectorString = typeof selector == 'string' && !selector.match( /^[#.]?[\\d/]/ );\n  if ( isSelectorString ) {\n    // use string as selector, get element\n    selector = this.element.querySelector( selector );\n  }\n  // get cell from element\n  return this.getCell( selector );\n};\n\n// -------------------------- events -------------------------- //\n\nproto.uiChange = function() {\n  this.emitEvent('uiChange');\n};\n\n// ----- resize ----- //\n\nproto.onresize = function() {\n  this.watchCSS();\n  this.resize();\n};\n\nutils.debounceMethod( Flickity, 'onresize', 150 );\n\nproto.resize = function() {\n  // #1177 disable resize behavior when animating or dragging for iOS 15\n  if ( !this.isActive || this.isAnimating || this.isDragging ) return;\n  this.getSize();\n  // wrap values\n  if ( this.isWrapping ) {\n    this.x = utils.modulo( this.x, this.slideableWidth );\n  }\n  this.positionCells();\n  this._updateWrapShiftCells();\n  this.setGallerySize();\n  this.emitEvent('resize');\n  // update selected index for group slides, instant\n  // TODO: position can be lost between groups of various numbers\n  let selectedElement = this.selectedElements && this.selectedElements[0];\n  this.selectCell( selectedElement, false, true );\n};\n\n// watches the :after property, activates/deactivates\nproto.watchCSS = function() {\n  if ( !this.options.watchCSS ) return;\n\n  let afterContent = getComputedStyle( this.element, ':after' ).content;\n  // activate if :after { content: 'flickity' }\n  if ( afterContent.includes('flickity') ) {\n    this.activate();\n  } else {\n    this.deactivate();\n  }\n};\n\n// ----- keydown ----- //\n\n// go previous/next if left/right keys pressed\nproto.onkeydown = function( event ) {\n  let { activeElement } = document;\n  let handler = Flickity.keyboardHandlers[ event.key ];\n  // only work if element is in focus\n  if ( !this.options.accessibility || !activeElement || !handler ) return;\n\n  let isFocused = this.focusableElems.some( ( elem ) => activeElement === elem );\n  if ( isFocused ) handler.call( this );\n};\n\nFlickity.keyboardHandlers = {\n  ArrowLeft: function() {\n    this.uiChange();\n    let leftMethod = this.options.rightToLeft ? 'next' : 'previous';\n    this[ leftMethod ]();\n  },\n  ArrowRight: function() {\n    this.uiChange();\n    let rightMethod = this.options.rightToLeft ? 'previous' : 'next';\n    this[ rightMethod ]();\n  },\n};\n\n// ----- focus ----- //\n\nproto.focus = function() {\n  this.element.focus({ preventScroll: true });\n};\n\n// -------------------------- destroy -------------------------- //\n\n// deactivate all Flickity functionality, but keep stuff available\nproto.deactivate = function() {\n  if ( !this.isActive ) return;\n\n  this.element.classList.remove('flickity-enabled');\n  this.element.classList.remove('flickity-rtl');\n  this.unselectSelectedSlide();\n  // destroy cells\n  this.cells.forEach( ( cell ) => cell.destroy() );\n  this.viewport.remove();\n  // move child elements back into element\n  this.element.append( ...this.slider.children );\n  if ( this.options.accessibility ) {\n    this.element.removeAttribute('tabIndex');\n    this.element.removeEventListener( 'keydown', this );\n  }\n  // set flags\n  this.isActive = false;\n  this.emitEvent('deactivate');\n};\n\nproto.destroy = function() {\n  this.deactivate();\n  window.removeEventListener( 'resize', this );\n  this.allOff();\n  this.emitEvent('destroy');\n  if ( jQuery && this.$element ) {\n    jQuery.removeData( this.element, 'flickity' );\n  }\n  delete this.element.flickityGUID;\n  delete instances[ this.guid ];\n};\n\n// -------------------------- prototype -------------------------- //\n\nObject.assign( proto, animatePrototype );\n\n// -------------------------- extras -------------------------- //\n\n/**\n * get Flickity instance from element\n * @param {[Element, String]} elem - element or selector string\n * @returns {Flickity} - Flickity instance\n */\nFlickity.data = function( elem ) {\n  elem = utils.getQueryElement( elem );\n  if ( elem ) return instances[ elem.flickityGUID ];\n};\n\nutils.htmlInit( Flickity, 'flickity' );\n\nlet { jQueryBridget } = window;\nif ( jQuery && jQueryBridget ) {\n  jQueryBridget( 'flickity', Flickity, jQuery );\n}\n\n// set internal jQuery, for Webpack + jQuery v3, #478\nFlickity.setJQuery = function( jq ) {\n  jQuery = jq;\n};\n\nFlickity.Cell = Cell;\nFlickity.Slide = Slide;\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/drag.js",
    "content": "// drag\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        window,\n        require('./core'),\n        require('unidragger'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    window.Flickity = factory(\n        window,\n        window.Flickity,\n        window.Unidragger,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( window, Flickity, Unidragger, utils ) {\n\n// ----- defaults ----- //\n\nObject.assign( Flickity.defaults, {\n  draggable: '>1',\n  dragThreshold: 3,\n} );\n\n// -------------------------- drag prototype -------------------------- //\n\nlet proto = Flickity.prototype;\nObject.assign( proto, Unidragger.prototype ); // inherit Unidragger\nproto.touchActionValue = '';\n\n// --------------------------  -------------------------- //\n\nFlickity.create.drag = function() {\n  this.on( 'activate', this.onActivateDrag );\n  this.on( 'uiChange', this._uiChangeDrag );\n  this.on( 'deactivate', this.onDeactivateDrag );\n  this.on( 'cellChange', this.updateDraggable );\n  this.on( 'pointerDown', this.handlePointerDown );\n  this.on( 'pointerUp', this.handlePointerUp );\n  this.on( 'pointerDown', this.handlePointerDone );\n  this.on( 'dragStart', this.handleDragStart );\n  this.on( 'dragMove', this.handleDragMove );\n  this.on( 'dragEnd', this.handleDragEnd );\n  this.on( 'staticClick', this.handleStaticClick );\n  // TODO updateDraggable on resize? if groupCells & slides change\n};\n\nproto.onActivateDrag = function() {\n  this.handles = [ this.viewport ];\n  this.bindHandles();\n  this.updateDraggable();\n};\n\nproto.onDeactivateDrag = function() {\n  this.unbindHandles();\n  this.element.classList.remove('is-draggable');\n};\n\nproto.updateDraggable = function() {\n  // disable dragging if less than 2 slides. #278\n  if ( this.options.draggable === '>1' ) {\n    this.isDraggable = this.slides.length > 1;\n  } else {\n    this.isDraggable = this.options.draggable;\n  }\n  this.element.classList.toggle( 'is-draggable', this.isDraggable );\n};\n\nproto._uiChangeDrag = function() {\n  delete this.isFreeScrolling;\n};\n\n// -------------------------- pointer events -------------------------- //\n\nproto.handlePointerDown = function( event ) {\n  if ( !this.isDraggable ) {\n    // proceed for staticClick\n    this.bindActivePointerEvents( event );\n    return;\n  }\n\n  let isTouchStart = event.type === 'touchstart';\n  let isTouchPointer = event.pointerType === 'touch';\n  let isFocusNode = event.target.matches('input, textarea, select');\n  if ( !isTouchStart && !isTouchPointer && !isFocusNode ) event.preventDefault();\n  if ( !isFocusNode ) this.focus();\n  // blur\n  if ( document.activeElement !== this.element ) document.activeElement.blur();\n  // stop if it was moving\n  this.dragX = this.x;\n  this.viewport.classList.add('is-pointer-down');\n  // track scrolling\n  this.pointerDownScroll = getScrollPosition();\n  window.addEventListener( 'scroll', this );\n  this.bindActivePointerEvents( event );\n};\n\n// ----- move ----- //\n\nproto.hasDragStarted = function( moveVector ) {\n  return Math.abs( moveVector.x ) > this.options.dragThreshold;\n};\n\n// ----- up ----- //\n\nproto.handlePointerUp = function() {\n  delete this.isTouchScrolling;\n  this.viewport.classList.remove('is-pointer-down');\n};\n\nproto.handlePointerDone = function() {\n  window.removeEventListener( 'scroll', this );\n  delete this.pointerDownScroll;\n};\n\n// -------------------------- dragging -------------------------- //\n\nproto.handleDragStart = function() {\n  if ( !this.isDraggable ) return;\n\n  this.dragStartPosition = this.x;\n  this.startAnimation();\n  window.removeEventListener( 'scroll', this );\n};\n\nproto.handleDragMove = function( event, pointer, moveVector ) {\n  if ( !this.isDraggable ) return;\n\n  event.preventDefault();\n\n  this.previousDragX = this.dragX;\n  // reverse if right-to-left\n  let direction = this.options.rightToLeft ? -1 : 1;\n  // wrap around move. #589\n  if ( this.isWrapping ) moveVector.x %= this.slideableWidth;\n  let dragX = this.dragStartPosition + moveVector.x * direction;\n\n  if ( !this.isWrapping ) {\n    // slow drag\n    let originBound = Math.max( -this.slides[0].target, this.dragStartPosition );\n    dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;\n    let endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition );\n    dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;\n  }\n\n  this.dragX = dragX;\n  this.dragMoveTime = new Date();\n};\n\nproto.handleDragEnd = function() {\n  if ( !this.isDraggable ) return;\n\n  let { freeScroll } = this.options;\n  if ( freeScroll ) this.isFreeScrolling = true;\n  // set selectedIndex based on where flick will end up\n  let index = this.dragEndRestingSelect();\n\n  if ( freeScroll && !this.isWrapping ) {\n    // if free-scroll & not wrap around\n    // do not free-scroll if going outside of bounding slides\n    // so bounding slides can attract slider, and keep it in bounds\n    let restingX = this.getRestingPosition();\n    this.isFreeScrolling = -restingX > this.slides[0].target &&\n      -restingX < this.getLastSlide().target;\n  } else if ( !freeScroll && index === this.selectedIndex ) {\n    // boost selection if selected index has not changed\n    index += this.dragEndBoostSelect();\n  }\n  delete this.previousDragX;\n  // apply selection\n  // HACK, set flag so dragging stays in correct direction\n  this.isDragSelect = this.isWrapping;\n  this.select( index );\n  delete this.isDragSelect;\n};\n\nproto.dragEndRestingSelect = function() {\n  let restingX = this.getRestingPosition();\n  // how far away from selected slide\n  let distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) );\n  // get closet resting going up and going down\n  let positiveResting = this._getClosestResting( restingX, distance, 1 );\n  let negativeResting = this._getClosestResting( restingX, distance, -1 );\n  // use closer resting for wrap-around\n  return positiveResting.distance < negativeResting.distance ?\n    positiveResting.index : negativeResting.index;\n};\n\n/**\n * given resting X and distance to selected cell\n * get the distance and index of the closest cell\n * @param {Number} restingX - estimated post-flick resting position\n * @param {Number} distance - distance to selected cell\n * @param {Integer} increment - +1 or -1, going up or down\n * @returns {Object} - { distance: {Number}, index: {Integer} }\n */\nproto._getClosestResting = function( restingX, distance, increment ) {\n  let index = this.selectedIndex;\n  let minDistance = Infinity;\n  let condition = this.options.contain && !this.isWrapping ?\n    // if containing, keep going if distance is equal to minDistance\n    ( dist, minDist ) => dist <= minDist :\n    ( dist, minDist ) => dist < minDist;\n\n  while ( condition( distance, minDistance ) ) {\n    // measure distance to next cell\n    index += increment;\n    minDistance = distance;\n    distance = this.getSlideDistance( -restingX, index );\n    if ( distance === null ) break;\n\n    distance = Math.abs( distance );\n  }\n  return {\n    distance: minDistance,\n    // selected was previous index\n    index: index - increment,\n  };\n};\n\n/**\n * measure distance between x and a slide target\n * @param {Number} x - horizontal position\n * @param {Integer} index - slide index\n * @returns {Number} - slide distance\n */\nproto.getSlideDistance = function( x, index ) {\n  let len = this.slides.length;\n  // wrap around if at least 2 slides\n  let isWrapAround = this.options.wrapAround && len > 1;\n  let slideIndex = isWrapAround ? utils.modulo( index, len ) : index;\n  let slide = this.slides[ slideIndex ];\n  if ( !slide ) return null;\n\n  // add distance for wrap-around slides\n  let wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0;\n  return x - ( slide.target + wrap );\n};\n\nproto.dragEndBoostSelect = function() {\n  // do not boost if no previousDragX or dragMoveTime\n  if ( this.previousDragX === undefined || !this.dragMoveTime ||\n    // or if drag was held for 100 ms\n    new Date() - this.dragMoveTime > 100 ) {\n    return 0;\n  }\n\n  let distance = this.getSlideDistance( -this.dragX, this.selectedIndex );\n  let delta = this.previousDragX - this.dragX;\n  if ( distance > 0 && delta > 0 ) {\n    // boost to next if moving towards the right, and positive velocity\n    return 1;\n  } else if ( distance < 0 && delta < 0 ) {\n    // boost to previous if moving towards the left, and negative velocity\n    return -1;\n  }\n  return 0;\n};\n\n// ----- scroll ----- //\n\nproto.onscroll = function() {\n  let scroll = getScrollPosition();\n  let scrollMoveX = this.pointerDownScroll.x - scroll.x;\n  let scrollMoveY = this.pointerDownScroll.y - scroll.y;\n  // cancel click/tap if scroll is too much\n  if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {\n    this.pointerDone();\n  }\n};\n\n// ----- utils ----- //\n\nfunction getScrollPosition() {\n  return {\n    x: window.pageXOffset,\n    y: window.pageYOffset,\n  };\n}\n\n// -----  ----- //\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/imagesloaded.js",
    "content": "// imagesloaded\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('imagesloaded'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.imagesLoaded,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this,\n    function factory( Flickity, imagesLoaded ) {\n\nFlickity.create.imagesLoaded = function() {\n  this.on( 'activate', this.imagesLoaded );\n};\n\nFlickity.prototype.imagesLoaded = function() {\n  if ( !this.options.imagesLoaded ) return;\n\n  let onImagesLoadedProgress = ( instance, image ) => {\n    let cell = this.getParentCell( image.img );\n    this.cellSizeChange( cell && cell.element );\n    if ( !this.options.freeScroll ) this.positionSliderAtSelected();\n  };\n  imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );\n};\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/index.js",
    "content": "/*!\n * Flickity v3.0.0\n * Touch, responsive, flickable carousels\n *\n * Licensed GPLv3 for open source use\n * or Flickity Commercial License for commercial use\n *\n * https://flickity.metafizzy.co\n * Copyright 2015-2022 Metafizzy\n */\n\nif ( typeof module == 'object' && module.exports ) {\n  const Flickity = require('./core');\n  require('./drag');\n  require('./prev-next-button');\n  require('./page-dots');\n  require('./player');\n  require('./add-remove-cell');\n  require('./lazyload');\n  require('./imagesloaded');\n\n  module.exports = Flickity;\n}\n"
  },
  {
    "path": "js/lazyload.js",
    "content": "// lazyload\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\nconst lazyAttr = 'data-flickity-lazyload';\nconst lazySrcAttr = `${lazyAttr}-src`;\nconst lazySrcsetAttr = `${lazyAttr}-srcset`;\nconst imgSelector = `img[${lazyAttr}], img[${lazySrcAttr}], ` +\n  `img[${lazySrcsetAttr}], source[${lazySrcsetAttr}]`;\n\nFlickity.create.lazyLoad = function() {\n  this.on( 'select', this.lazyLoad );\n\n  this.handleLazyLoadComplete = this.onLazyLoadComplete.bind( this );\n};\n\nlet proto = Flickity.prototype;\n\nproto.lazyLoad = function() {\n  let { lazyLoad } = this.options;\n  if ( !lazyLoad ) return;\n\n  // get adjacent cells, use lazyLoad option for adjacent count\n  let adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;\n  // lazy load images\n  this.getAdjacentCellElements( adjCount )\n    .map( getCellLazyImages )\n    .flat()\n    .forEach( ( img ) => new LazyLoader( img, this.handleLazyLoadComplete ) );\n};\n\nfunction getCellLazyImages( cellElem ) {\n  // check if cell element is lazy image\n  if ( cellElem.matches('img') ) {\n    let cellAttr = cellElem.getAttribute( lazyAttr );\n    let cellSrcAttr = cellElem.getAttribute( lazySrcAttr );\n    let cellSrcsetAttr = cellElem.getAttribute( lazySrcsetAttr );\n    if ( cellAttr || cellSrcAttr || cellSrcsetAttr ) {\n      return cellElem;\n    }\n  }\n  // select lazy images in cell\n  return [ ...cellElem.querySelectorAll( imgSelector ) ];\n}\n\nproto.onLazyLoadComplete = function( img, event ) {\n  let cell = this.getParentCell( img );\n  let cellElem = cell && cell.element;\n  this.cellSizeChange( cellElem );\n\n  this.dispatchEvent( 'lazyLoad', event, cellElem );\n};\n\n// -------------------------- LazyLoader -------------------------- //\n\n/**\n * class to handle loading images\n * @param {Image} img - Image element\n * @param {Function} onComplete - callback function\n */\nfunction LazyLoader( img, onComplete ) {\n  this.img = img;\n  this.onComplete = onComplete;\n  this.load();\n}\n\nLazyLoader.prototype.handleEvent = utils.handleEvent;\n\nLazyLoader.prototype.load = function() {\n  this.img.addEventListener( 'load', this );\n  this.img.addEventListener( 'error', this );\n  // get src & srcset\n  let src = this.img.getAttribute( lazyAttr ) ||\n    this.img.getAttribute( lazySrcAttr );\n  let srcset = this.img.getAttribute( lazySrcsetAttr );\n  // set src & serset\n  this.img.src = src;\n  if ( srcset ) this.img.setAttribute( 'srcset', srcset );\n  // remove attr\n  this.img.removeAttribute( lazyAttr );\n  this.img.removeAttribute( lazySrcAttr );\n  this.img.removeAttribute( lazySrcsetAttr );\n};\n\nLazyLoader.prototype.onload = function( event ) {\n  this.complete( event, 'flickity-lazyloaded' );\n};\n\nLazyLoader.prototype.onerror = function( event ) {\n  this.complete( event, 'flickity-lazyerror' );\n};\n\nLazyLoader.prototype.complete = function( event, className ) {\n  // unbind events\n  this.img.removeEventListener( 'load', this );\n  this.img.removeEventListener( 'error', this );\n  let mediaElem = this.img.parentNode.matches('picture') ? this.img.parentNode : this.img;\n  mediaElem.classList.add( className );\n\n  this.onComplete( this.img, event );\n};\n\n// -----  ----- //\n\nFlickity.LazyLoader = LazyLoader;\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/page-dots.js",
    "content": "// page dots\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n        require('./core'),\n        require('fizzy-ui-utils'),\n    );\n  } else {\n    // browser global\n    factory(\n        window.Flickity,\n        window.fizzyUIUtils,\n    );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {\n\n// -------------------------- PageDots -------------------------- //\n\nfunction PageDots() {\n  // create holder element\n  this.holder = document.createElement('div');\n  this.holder.className = 'flickity-page-dots';\n  // create dots, array of elements\n  this.dots = [];\n}\n\nPageDots.prototype.setDots = function( slidesLength ) {\n  // get difference between number of slides and number of dots\n  let delta = slidesLength - this.dots.length;\n  if ( delta > 0 ) {\n    this.addDots( delta );\n  } else if ( delta < 0 ) {\n    this.removeDots( -delta );\n  }\n};\n\nPageDots.prototype.addDots = function( count ) {\n  let newDots = new Array( count ).fill()\n    .map( ( item, i ) => {\n      let dot = document.createElement('button');\n      dot.setAttribute( 'type', 'button' );\n      let num = i + 1 + this.dots.length;\n      dot.className = 'flickity-button flickity-page-dot';\n      dot.textContent = `View slide ${num}`;\n      return dot;\n    } );\n\n  this.holder.append( ...newDots );\n  this.dots = this.dots.concat( newDots );\n};\n\nPageDots.prototype.removeDots = function( count ) {\n  // remove from this.dots collection\n  let removeDots = this.dots.splice( this.dots.length - count, count );\n  // remove from DOM\n  removeDots.forEach( ( dot ) => dot.remove() );\n};\n\nPageDots.prototype.updateSelected = function( index ) {\n  // remove selected class on previous\n  if ( this.selectedDot ) {\n    this.selectedDot.classList.remove('is-selected');\n    this.selectedDot.removeAttribute('aria-current');\n  }\n  // don't proceed if no dots\n  if ( !this.dots.length ) return;\n\n  this.selectedDot = this.dots[ index ];\n  this.selectedDot.classList.add('is-selected');\n  this.selectedDot.setAttribute( 'aria-current', 'step' );\n};\n\nFlickity.PageDots = PageDots;\n\n// -------------------------- Flickity -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  pageDots: true,\n} );\n\nFlickity.create.pageDots = function() {\n  if ( !this.options.pageDots ) return;\n\n  this.pageDots = new PageDots();\n  this.handlePageDotsClick = this.onPageDotsClick.bind( this );\n  // events\n  this.on( 'activate', this.activatePageDots );\n  this.on( 'select', this.updateSelectedPageDots );\n  this.on( 'cellChange', this.updatePageDots );\n  this.on( 'resize', this.updatePageDots );\n  this.on( 'deactivate', this.deactivatePageDots );\n};\n\nlet proto = Flickity.prototype;\n\nproto.activatePageDots = function() {\n  this.pageDots.setDots( this.slides.length );\n  this.focusableElems.push( ...this.pageDots.dots );\n  this.pageDots.holder.addEventListener( 'click', this.handlePageDotsClick );\n  this.element.insertBefore( this.pageDots.holder, this.viewport );\n};\n\nproto.onPageDotsClick = function( event ) {\n  let index = this.pageDots.dots.indexOf( event.target );\n  if ( index === -1 ) return; // only dot clicks\n\n  this.uiChange();\n  this.select( index );\n};\n\nproto.updateSelectedPageDots = function() {\n  this.pageDots.updateSelected( this.selectedIndex );\n};\n\nproto.updatePageDots = function() {\n  this.pageDots.dots.forEach( ( dot ) => {\n    utils.removeFrom( this.focusableElems, dot );\n  } );\n  this.pageDots.setDots( this.slides.length );\n  this.focusableElems.push( ...this.pageDots.dots );\n};\n\nproto.deactivatePageDots = function() {\n  this.pageDots.holder.remove();\n  this.pageDots.holder.removeEventListener( 'click', this.handlePageDotsClick );\n};\n\n// -----  ----- //\n\nFlickity.PageDots = PageDots;\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/player.js",
    "content": "// player & autoPlay\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('./core') );\n  } else {\n    // browser global\n    factory( window.Flickity );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity ) {\n\n// -------------------------- Player -------------------------- //\n\nfunction Player( autoPlay, onTick ) {\n  this.autoPlay = autoPlay;\n  this.onTick = onTick;\n  this.state = 'stopped';\n  // visibility change event handler\n  this.onVisibilityChange = this.visibilityChange.bind( this );\n  this.onVisibilityPlay = this.visibilityPlay.bind( this );\n}\n\n// start play\nPlayer.prototype.play = function() {\n  if ( this.state === 'playing' ) return;\n\n  // do not play if page is hidden, start playing when page is visible\n  let isPageHidden = document.hidden;\n  if ( isPageHidden ) {\n    document.addEventListener( 'visibilitychange', this.onVisibilityPlay );\n    return;\n  }\n\n  this.state = 'playing';\n  // listen to visibility change\n  document.addEventListener( 'visibilitychange', this.onVisibilityChange );\n  // start ticking\n  this.tick();\n};\n\nPlayer.prototype.tick = function() {\n  // do not tick if not playing\n  if ( this.state !== 'playing' ) return;\n\n  // default to 3 seconds\n  let time = typeof this.autoPlay == 'number' ? this.autoPlay : 3000;\n  // HACK: reset ticks if stopped and started within interval\n  this.clear();\n  this.timeout = setTimeout( () => {\n    this.onTick();\n    this.tick();\n  }, time );\n};\n\nPlayer.prototype.stop = function() {\n  this.state = 'stopped';\n  this.clear();\n  // remove visibility change event\n  document.removeEventListener( 'visibilitychange', this.onVisibilityChange );\n};\n\nPlayer.prototype.clear = function() {\n  clearTimeout( this.timeout );\n};\n\nPlayer.prototype.pause = function() {\n  if ( this.state === 'playing' ) {\n    this.state = 'paused';\n    this.clear();\n  }\n};\n\nPlayer.prototype.unpause = function() {\n  // re-start play if paused\n  if ( this.state === 'paused' ) this.play();\n};\n\n// pause if page visibility is hidden, unpause if visible\nPlayer.prototype.visibilityChange = function() {\n  let isPageHidden = document.hidden;\n  this[ isPageHidden ? 'pause' : 'unpause' ]();\n};\n\nPlayer.prototype.visibilityPlay = function() {\n  this.play();\n  document.removeEventListener( 'visibilitychange', this.onVisibilityPlay );\n};\n\n// -------------------------- Flickity -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  pauseAutoPlayOnHover: true,\n} );\n\nFlickity.create.player = function() {\n  this.player = new Player( this.options.autoPlay, () => {\n    this.next( true );\n  } );\n\n  this.on( 'activate', this.activatePlayer );\n  this.on( 'uiChange', this.stopPlayer );\n  this.on( 'pointerDown', this.stopPlayer );\n  this.on( 'deactivate', this.deactivatePlayer );\n};\n\nlet proto = Flickity.prototype;\n\nproto.activatePlayer = function() {\n  if ( !this.options.autoPlay ) return;\n\n  this.player.play();\n  this.element.addEventListener( 'mouseenter', this );\n};\n\n// Player API, don't hate the ... thanks I know where the door is\n\nproto.playPlayer = function() {\n  this.player.play();\n};\n\nproto.stopPlayer = function() {\n  this.player.stop();\n};\n\nproto.pausePlayer = function() {\n  this.player.pause();\n};\n\nproto.unpausePlayer = function() {\n  this.player.unpause();\n};\n\nproto.deactivatePlayer = function() {\n  this.player.stop();\n  this.element.removeEventListener( 'mouseenter', this );\n};\n\n// ----- mouseenter/leave ----- //\n\n// pause auto-play on hover\nproto.onmouseenter = function() {\n  if ( !this.options.pauseAutoPlayOnHover ) return;\n\n  this.player.pause();\n  this.element.addEventListener( 'mouseleave', this );\n};\n\n// resume auto-play on hover off\nproto.onmouseleave = function() {\n  this.player.unpause();\n  this.element.removeEventListener( 'mouseleave', this );\n};\n\n// -----  ----- //\n\nFlickity.Player = Player;\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/prev-next-button.js",
    "content": "// prev/next buttons\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory( require('./core') );\n  } else {\n    // browser global\n    factory( window.Flickity );\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory( Flickity ) {\n\nconst svgURI = 'http://www.w3.org/2000/svg';\n\n// -------------------------- PrevNextButton -------------------------- //\n\nfunction PrevNextButton( increment, direction, arrowShape ) {\n  this.increment = increment;\n  this.direction = direction;\n  this.isPrevious = increment === 'previous';\n  this.isLeft = direction === 'left';\n  this._create( arrowShape );\n}\n\nPrevNextButton.prototype._create = function( arrowShape ) {\n  // properties\n  let element = this.element = document.createElement('button');\n  element.className = `flickity-button flickity-prev-next-button ${this.increment}`;\n  let label = this.isPrevious ? 'Previous' : 'Next';\n  // prevent button from submitting form https://stackoverflow.com/a/10836076/182183\n  element.setAttribute( 'type', 'button' );\n  element.setAttribute( 'aria-label', label );\n  // init as disabled\n  this.disable();\n  // create arrow\n  let svg = this.createSVG( label, arrowShape );\n  element.append( svg );\n};\n\nPrevNextButton.prototype.createSVG = function( label, arrowShape ) {\n  let svg = document.createElementNS( svgURI, 'svg' );\n  svg.setAttribute( 'class', 'flickity-button-icon' );\n  svg.setAttribute( 'viewBox', '0 0 100 100' );\n  // add title #1189\n  let title = document.createElementNS( svgURI, 'title' );\n  title.append( label );\n  // add path\n  let path = document.createElementNS( svgURI, 'path' );\n  let pathMovements = getArrowMovements( arrowShape );\n  path.setAttribute( 'd', pathMovements );\n  path.setAttribute( 'class', 'arrow' );\n  // rotate arrow\n  if ( !this.isLeft ) {\n    path.setAttribute( 'transform', 'translate(100, 100) rotate(180)' );\n  }\n  svg.append( title, path );\n  return svg;\n};\n\n// get SVG path movmement\nfunction getArrowMovements( shape ) {\n  // use shape as movement if string\n  if ( typeof shape == 'string' ) return shape;\n\n  let { x0, x1, x2, x3, y1, y2 } = shape;\n\n  // create movement string\n  return `M ${x0}, 50\n    L ${x1}, ${y1 + 50}\n    L ${x2}, ${y2 + 50}\n    L ${x3}, 50\n    L ${x2}, ${50 - y2}\n    L ${x1}, ${50 - y1}\n    Z`;\n}\n\n// -----  ----- //\n\nPrevNextButton.prototype.enable = function() {\n  this.element.removeAttribute('disabled');\n};\n\nPrevNextButton.prototype.disable = function() {\n  this.element.setAttribute( 'disabled', true );\n};\n\n// -------------------------- Flickity prototype -------------------------- //\n\nObject.assign( Flickity.defaults, {\n  prevNextButtons: true,\n  arrowShape: {\n    x0: 10,\n    x1: 60, y1: 50,\n    x2: 70, y2: 40,\n    x3: 30,\n  },\n} );\n\nFlickity.create.prevNextButtons = function() {\n  if ( !this.options.prevNextButtons ) return;\n\n  let { rightToLeft, arrowShape } = this.options;\n  let prevDirection = rightToLeft ? 'right' : 'left';\n  let nextDirection = rightToLeft ? 'left' : 'right';\n  this.prevButton = new PrevNextButton( 'previous', prevDirection, arrowShape );\n  this.nextButton = new PrevNextButton( 'next', nextDirection, arrowShape );\n  this.focusableElems.push( this.prevButton.element );\n  this.focusableElems.push( this.nextButton.element );\n\n  this.handlePrevButtonClick = () => {\n    this.uiChange();\n    this.previous();\n  };\n\n  this.handleNextButtonClick = () => {\n    this.uiChange();\n    this.next();\n  };\n\n  this.on( 'activate', this.activatePrevNextButtons );\n  this.on( 'select', this.updatePrevNextButtons );\n};\n\nlet proto = Flickity.prototype;\n\nproto.updatePrevNextButtons = function() {\n  let lastIndex = this.slides.length ? this.slides.length - 1 : 0;\n  this.updatePrevNextButton( this.prevButton, 0 );\n  this.updatePrevNextButton( this.nextButton, lastIndex );\n};\n\nproto.updatePrevNextButton = function( button, disabledIndex ) {\n  // enable is wrapAround and at least 2 slides\n  if ( this.isWrapping && this.slides.length > 1 ) {\n    button.enable();\n    return;\n  }\n\n  let isEnabled = this.selectedIndex !== disabledIndex;\n  button[ isEnabled ? 'enable' : 'disable' ]();\n  // if disabling button that is focused,\n  // shift focus to element to maintain keyboard accessibility\n  let isDisabledFocused = !isEnabled && document.activeElement === button.element;\n  if ( isDisabledFocused ) this.focus();\n};\n\nproto.activatePrevNextButtons = function() {\n  this.prevButton.element.addEventListener( 'click', this.handlePrevButtonClick );\n  this.nextButton.element.addEventListener( 'click', this.handleNextButtonClick );\n  this.element.prepend( this.prevButton.element, this.nextButton.element );\n  this.on( 'deactivate', this.deactivatePrevNextButtons );\n};\n\nproto.deactivatePrevNextButtons = function() {\n  this.prevButton.element.remove();\n  this.nextButton.element.remove();\n  this.prevButton.element.removeEventListener( 'click', this.handlePrevButtonClick );\n  this.nextButton.element.removeEventListener( 'click', this.handleNextButtonClick );\n  this.off( 'deactivate', this.deactivatePrevNextButtons );\n};\n\n// --------------------------  -------------------------- //\n\nFlickity.PrevNextButton = PrevNextButton;\n\nreturn Flickity;\n\n} ) );\n"
  },
  {
    "path": "js/slide.js",
    "content": "// slide\n( function( window, factory ) {\n  // universal module definition\n  if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory();\n  } else {\n    // browser global\n    window.Flickity = window.Flickity || {};\n    window.Flickity.Slide = factory();\n  }\n\n}( typeof window != 'undefined' ? window : this, function factory() {\n\nfunction Slide( beginMargin, endMargin, cellAlign ) {\n  this.beginMargin = beginMargin;\n  this.endMargin = endMargin;\n  this.cellAlign = cellAlign;\n  this.cells = [];\n  this.outerWidth = 0;\n  this.height = 0;\n}\n\nlet proto = Slide.prototype;\n\nproto.addCell = function( cell ) {\n  this.cells.push( cell );\n  this.outerWidth += cell.size.outerWidth;\n  this.height = Math.max( cell.size.outerHeight, this.height );\n  // first cell stuff\n  if ( this.cells.length === 1 ) {\n    this.x = cell.x; // x comes from first cell\n    this.firstMargin = cell.size[ this.beginMargin ];\n  }\n};\n\nproto.updateTarget = function() {\n  let lastCell = this.getLastCell();\n  let lastMargin = lastCell ? lastCell.size[ this.endMargin ] : 0;\n  let slideWidth = this.outerWidth - ( this.firstMargin + lastMargin );\n  this.target = this.x + this.firstMargin + slideWidth * this.cellAlign;\n};\n\nproto.getLastCell = function() {\n  return this.cells[ this.cells.length - 1 ];\n};\n\nproto.select = function() {\n  this.cells.forEach( ( cell ) => cell.select() );\n};\n\nproto.unselect = function() {\n  this.cells.forEach( ( cell ) => cell.unselect() );\n};\n\nproto.getCellElements = function() {\n  return this.cells.map( ( cell ) => cell.element );\n};\n\nreturn Slide;\n\n} ) );\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"flickity\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Touch, responsive, flickable carousels\",\n  \"main\": \"js/index.js\",\n  \"style\": \"css/flickity.css\",\n  \"scripts\": {\n    \"test\": \"npm run lint && echo \\\"View test/ in browser\\\" && exit 1\",\n    \"lintJs\": \"npx eslint .\",\n    \"lintJson\": \"node bin/lint-json.js\",\n    \"lintCss\": \"npx stylelint '**/*.css'\",\n    \"lint\": \"npm run lintJson && npm run lintJs && npm run lintCss\",\n    \"dist\": \"npm run bundleCss && npm run bundleJs\",\n    \"bundleCss\": \"cp css/flickity.css dist/flickity.css && node bin/bundle-css.js\",\n    \"bundleJs\": \"node bin/bundle-js.js\",\n    \"version\": \"node bin/version.js && npm run dist && git add -A css js dist\"\n  },\n  \"dependencies\": {\n    \"ev-emitter\": \"^2.1.2\",\n    \"fizzy-ui-utils\": \"^3.0.0\",\n    \"get-size\": \"^3.0.0\",\n    \"imagesloaded\": \"^5.0.0\",\n    \"unidragger\": \"^3.0.1\"\n  },\n  \"devDependencies\": {\n    \"clean-css\": \"^5.2.2\",\n    \"eslint\": \"^8.10.0\",\n    \"eslint-plugin-metafizzy\": \"^2.0.1\",\n    \"jquery-bridget\": \"^3.0.1\",\n    \"qunit\": \"^2.17.2\",\n    \"stylelint\": \"^14.2.0\",\n    \"stylelint-config-standard\": \"^24.0.0\",\n    \"terser\": \"^5.10.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/metafizzy/flickity.git\"\n  },\n  \"keywords\": [\n    \"touch\",\n    \"responsive\",\n    \"flick\",\n    \"slider\",\n    \"carousel\",\n    \"gallery\",\n    \"DOM\",\n    \"browser\"\n  ],\n  \"author\": \"Metafizzy\",\n  \"license\": \"GPL-3.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/metafizzy/flickity/issues\"\n  },\n  \"homepage\": \"https://flickity.metafizzy.co\",\n  \"directories\": {\n    \"test\": \"test\"\n  }\n}\n"
  },
  {
    "path": "sandbox/adaptive-height.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>slides</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n<style>\n* { box-sizing: border-box; }\n\nhtml { overflow-y: scroll; }\n\n.carousel {\n  border: 1px solid;\n  margin-bottom: 40px;\n}\n\n.flickity-viewport {\n  overflow: visible;\n  transition: height 0.2s;\n}\n\n.carousel__cell {\n  width: 32%;\n  height: 100px;\n  background: #BDF;\n  margin-left: 1%;\n  margin-right: 1%;\n  font-size: 40px;\n}\n\n.carousel__cell.is-selected {\n  background: #68F;\n}\n\n.carousel__cell--height2 { height: 200px; }\n.carousel__cell--height3 { height: 300px; }\n.carousel__cell--height4 { height: 400px; }\n\n/* ----  ---- */\n\n.image-carousel img {\n  display: block;\n  width: 50%;\n}\n\n</style>\n\n</head>\n<body>\n\n  <h1>slides</h1>\n\n<div class=\"carousel carousel1\">\n  <div class=\"carousel__cell carousel__cell--height2\">0</div>\n  <div class=\"carousel__cell\">1</div>\n  <div class=\"carousel__cell\">2</div>\n  <div class=\"carousel__cell carousel__cell--height2\">3</div>\n  <div class=\"carousel__cell carousel__cell--height3\">4</div>\n  <div class=\"carousel__cell\">5</div>\n  <div class=\"carousel__cell carousel__cell--height4\">6</div>\n  <div class=\"carousel__cell\">7</div>\n  <div class=\"carousel__cell carousel__cell--height3\">8</div>\n  <div class=\"carousel__cell\">9</div>\n  <div class=\"carousel__cell\">10</div>\n</div>\n\n<div class=\"carousel image-carousel\">\n  <img src=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n  <img src=\"https://i.imgur.com/q9zO6tw.jpg\" />\n  <img src=\"https://i.imgur.com/bwy74ok.jpg\" />\n  <img src=\"https://i.imgur.com/bAZWoqx.jpg\" />\n  <img src=\"https://i.imgur.com/PgmEBSB.jpg\" />\n  <img src=\"https://i.imgur.com/aboaFoB.jpg\" />\n  <img src=\"https://i.imgur.com/LkmcILl.jpg\" />\n  <img src=\"https://i.imgur.com/hODreXI.jpg\" />\n  <img src=\"https://i.imgur.com/UORFJ3w.jpg\" />\n</div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script>\nvar flkty = new Flickity( '.carousel1', {\n  adaptiveHeight: true,\n  // groupCells: true,\n  // wrapAround: true,\n});\n\nvar imgFlkty = new Flickity( '.image-carousel', {\n  adaptiveHeight: true\n});\n\nwindow.onload = function() {\n  imgFlkty.reposition();\n}\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/add-remove.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>add/remove cells</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n  <style>\n    .remove-button {\n      font-size: 20px;\n      position: absolute;\n      right: 10px;\n      top: 10px;\n    }\n  </style>\n\n</head>\n<body>\n\n  <h1>add/remove cells</h1>\n\n  <div id=\"demo1\" class=\"demo\">\n    <div class=\"container variable-width\" data-flickity>\n      <div class=\"cell n1 w3\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n2\"><b>2</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n3 w3\"><b>3</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n4\"><b>4</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n5 w2\"><b>5</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n6 w2\"><b>6</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n      <button class=\"insert-button\">Insert</button>\n      <button class=\"append-button\">Append</button>\n    </p>\n  </div>\n\n  <h2>freeScroll</h2>\n\n  <div id=\"demo2\" class=\"demo\">\n    <div class=\"container variable-width\"\n      data-flickity='{ \"freeScroll\": true }'>\n      <div class=\"cell n6\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n5 w2\"><b>2</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n4\"><b>3</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n3 w3\"><b>4</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n2\"><b>5</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n      <button class=\"insert-button\">Insert</button>\n      <button class=\"append-button\">Append</button>\n    </p>\n  </div>\n\n  <h2>wrapAround</h2>\n\n  <div id=\"demo3\" class=\"demo\">\n    <div class=\"container variable-width\"\n      data-flickity='{ \"wrapAround\": true }'>\n      <div class=\"cell n6\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n5 w2\"><b>2</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n4\"><b>3</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n3 w3\"><b>4</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n2\"><b>5</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n6 w2\"><b>6</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n      <button class=\"insert-button\">Insert</button>\n      <button class=\"append-button\">Append</button>\n    </p>\n  </div>\n\n  <h2>wrapAround, freeScroll</h2>\n\n  <div id=\"demo4\" class=\"demo\">\n    <div class=\"container variable-width\"\n      data-flickity='{ \"wrapAround\": true, \"freeScroll\": true }'>\n      <div class=\"cell n6\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n5 w2\"><b>2</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n4\"><b>3</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n3 w3\"><b>4</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n2\"><b>5</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n6 w2\"><b>6</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n      <button class=\"insert-button\">Insert</button>\n      <button class=\"append-button\">Append</button>\n    </p>\n  </div>\n\n  <h2>contain</h2>\n\n  <div id=\"demo5\" class=\"demo\">\n    <div class=\"container variable-width\"\n      data-flickity='{ \"contain\": true }'>\n      <div class=\"cell n1 w3\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n2\"><b>2</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n3 w3\"><b>3</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n4\"><b>4</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n5 w2\"><b>5</b><button class=\"remove-button\">&times;</button></div>\n      <div class=\"cell n6 w2\"><b>6</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n      <button class=\"insert-button\">Insert</button>\n      <button class=\"append-button\">Append</button>\n    </p>\n  </div>\n\n\n  <h2>reposition</h2>\n\n  <div id=\"reposition\">\n    <div class=\"container variable-width\">\n      <div class=\"cell w2\"><b>1</b></div>\n      <div class=\"cell\"><b>2</b></div>\n      <div class=\"cell w3\"><b>3</b></div>\n      <div class=\"cell\"><b>4</b></div>\n      <div class=\"cell\"><b>5</b></div>\n      <div class=\"cell w2\"><b>6</b></div>\n      <div class=\"cell\"><b>7</b></div>\n      <div class=\"cell w2\"><b>8</b></div>\n      <div class=\"cell\"><b>9</b></div>\n    </div>\n  </div>\n\n  <h2>prepend with single #492</h2>\n  <div id=\"prepend-single\">\n    <div class=\"container variable-width\">\n      <div class=\"cell n1\"><b>1</b><button class=\"remove-button\">&times;</button></div>\n    </div>\n    <p>\n      <button class=\"prepend-button\">Prepend</button>\n    </p>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script src=\"js/add-remove.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/ajax.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>ajax</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <style>\n  .gallery-cell {\n      width: auto;\n      height: 320px;\n  }\n  .gallery-cell img {\n      height:100%;\n  }\n  </style>\n\n</head>\n<body>\n\n  <h1>ajax</h1>\n\n  <div class=\"gallery\"></div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n<script src=\"../node_modules/imagesloaded/imagesloaded.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/imagesloaded.js\"></script>\n\n<script>\nwindow.onajaxload = function({ items }) {\n  let gallery = document.querySelector('.gallery');\n  gallery.innerHTML = items.map( ( item ) => {\n    return `<div class=\"gallery-cell\"><img src=\"${item.media.m}\" /></div>`;\n  } ).join(' ');\n  \n  new Flickity( gallery, {\n    freeScroll: true,\n    friction: 0.2,\n    imagesLoaded: true,\n    prevNextButtons: false,\n    pageDots: false,\n    wrapAround: true\n  });\n};\n</script>\n\n<script src=\"https://api.flickr.com/services/feeds/photos_public.gne?&format=json&jsoncallback=onajaxload&extras=url_n&per_page=10\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/basic.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>basic1</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n  <style>\n    #gallery3,\n    #gallery3 .cell,\n    #gallery3 input,\n    #gallery3 button {\n      font-size: 20px;\n    }\n\n    #gallery3 .cell {\n      padding-top: 20px;\n      padding-left: 100px;\n    }\n\n    #gallery3 p { margin: 0 0 10px; }\n\n    /*#gallery6 .cell { margin: 0 40px; }*/\n\n    @media screen and ( min-width: 900px ) {\n      #gallery5 {\n        background: #DDF;\n      }\n      #gallery5:after {\n        content: 'flickity';\n        display: none;\n      }\n    }\n  </style>\n\n</head>\n<body>\n\n  <h1>basic1</h1>\n\n  <div id=\"full-width\" class=\"container\">\n    <div class=\"cell\" n1></div>\n    <div class=\"cell\" n2></div>\n    <div class=\"cell\" n3></div>\n    <div class=\"cell\" n4></div>\n    <div class=\"cell\" n5></div>\n    <div class=\"cell\" n6></div>\n    <div class=\"cell\" n7></div>\n  </div>\n\n  <div id=\"half-width\" class=\"container\">\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <div id=\"gallery3\" class=\"container\">\n    <div class=\"cell\">\n      <select>\n        <option>Michaelangelo</option>\n        <option>Donatello</option>\n        <option>Leonardo</option>\n        <option>Raphael</option>\n      </select>\n    </div>\n    <div class=\"cell\">\n      <p><button>Button</button> <a href=\"https://example.com\">go to example.com</a></p>\n      <p><input /></p>\n      <p>\n        <input type=\"checkbox\" />\n        <input type=\"radio\" name=\"foo\" />\n        <input type=\"radio\" name=\"foo\" />\n        <input type=\"range\" />\n      </p>\n    </div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <div id=\"gallery4\" class=\"container\" data-flickity>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <h2>contain</h2>\n\n  <div id=\"gallery6\" class=\"container variable-width\"\n    data-flickity='{ \"contain\": true }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n  <h2>contain, freeScroll</h2>\n\n  <div id=\"gallery6\" class=\"container variable-width\"\n    data-flickity='{ \"contain\": true, \"freeScroll\": true }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n    <div class=\"cell n1\">7</div>\n    <div class=\"cell n2 w2\">8</div>\n    <div class=\"cell n3 w3\">9</div>\n  </div>\n\n  <h2>contain, few</h2>\n\n  <div class=\"container variable-width\"\n    data-flickity='{ \"contain\": true, \"cellAlign\": \"center\" }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2\">2</div>\n    <!-- <div class=\"cell n3\">3</div> -->\n  </div>\n\n  <h2>watch, activate >900px</h2>\n\n  <div id=\"gallery5\" class=\"container variable-width\"\n    data-flickity='{ \"wrapAround\": true, \"watchCSS\": true }'>\n    <div class=\"cell n1 w3\"></div>\n    <div class=\"cell n2 w2\"></div>\n    <div class=\"cell n3\"></div>\n    <div class=\"cell n4 w3\"></div>\n    <div class=\"cell n5\"></div>\n    <div class=\"cell n6 w2\"></div>\n    <div class=\"cell n4\"></div>\n    <div class=\"cell n2\"></div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script src=\"js/basic.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/freescroll.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>freescroll</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <style>\n\n  * { box-sizing: border-box; }\n\n  body { font-family: sans-serif; }\n\n  .gallery {\n    background: #FAFAFA;\n    margin-bottom: 40px;\n  }\n\n  .gallery-cell {\n    width: 180px;\n    height: 200px;\n    margin-right: 10px;\n    background: #8C8;\n    counter-increment: gallery-cell;\n  }\n\n  .gallery-cell.is-selected {\n    background: #F90;\n  }\n\n  /* cell number */\n  .gallery-cell:before {\n    display: block;\n    text-align: center;\n    content: counter(gallery-cell);\n    line-height: 200px;\n    font-size: 80px;\n    color: white;\n  }\n\n  </style>\n\n</head>\n<body>\n\n  <h1>freescroll</h1>\n\n<div class=\"gallery\"\n  data-flickity='{ \"contain\": true, \"freeScroll\": true }'>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n</div>\n\n<div class=\"gallery\"\n  data-flickity='{ \"contain\": true }'>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n  <div class=\"gallery-cell\"></div>\n</div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/group-cells.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>group cells</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n<style>\n* { box-sizing: border-box; }\n\nhtml { overflow-y: scroll; }\n\n.carousel {\n  border: 1px solid;\n  margin-bottom: 40px;\n/*  width: 1000px;*/\n}\n\n.carousel__cell {\n/*  width: 25%;*/\n  width: 32%;\n  height: 200px;\n  background: #BDF;\n  margin-left: 1%;\n  margin-right: 1%;\n  font-size: 40px;\n}\n\n/*.carousel__cell--width2 { width: 40%; }\n.carousel__cell--width3 { width: 80%; }*/\n\n.carousel__cell--width2 { width: 66%; }\n.carousel__cell--width3 { width: 100%; }\n\n.carousel__cell.is-selected {\n  background: #68F;\n}\n\n@media (min-width: 1000px) {\n  /* fit four */\n  .carousel__cell { width: 23.5%; }\n  .carousel__cell--width2 { width: 49%; }\n  .carousel__cell--width3 { width: 74.5%; }\n}\n\n\n</style>\n\n</head>\n<body>\n\n  <h1>group cells</h1>\n\n<div class=\"carousel carousel1\">\n  <div class=\"carousel__cell carousel__cell--width2\">0</div>\n  <div class=\"carousel__cell\">1</div>\n  <div class=\"carousel__cell\">2</div>\n  <div class=\"carousel__cell carousel__cell--width2\">3</div>\n  <div class=\"carousel__cell carousel__cell--width2\">4</div>\n  <div class=\"carousel__cell\">5</div>\n  <div class=\"carousel__cell\">6</div>\n  <div class=\"carousel__cell\">7</div>\n  <div class=\"carousel__cell carousel__cell--width3\">8</div>\n  <div class=\"carousel__cell\">9</div>\n  <div class=\"carousel__cell\">10</div>\n</div>\n\n\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script>\nvar flkty = new Flickity( '.carousel1', {\n  groupCells: true,\n  wrapAround: true,\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/jquery.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\n  <title>jquery</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n</head>\n<body>\n\n  <h1>jquery</h1>\n\n  <div id=\"gallery1\" class=\"container\">\n    <div class=\"cell\" n1></div>\n    <div class=\"cell\" n2></div>\n    <div class=\"cell\" n3></div>\n    <div class=\"cell\" n4></div>\n    <div class=\"cell\" n5></div>\n    <div class=\"cell\" n6></div>\n    <div class=\"cell\" n7></div>\n  </div>\n\n  <div id=\"gallery2\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n<script src=\"../node_modules/jquery/dist/jquery.min.js\"></script>\n<script src=\"../node_modules/jquery-bridget/jquery-bridget.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script src=\"js/jquery.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/js/add-remove.js",
    "content": "let cellCount = 6;\n\nfunction getRandom( ary ) {\n  let index = Math.floor( Math.random() * ary.length );\n  return ary[ index ];\n}\n\nlet widthClasses = [ '', 'w2', 'w3' ];\nlet nClasses = 'n1 n2 n3 n4 n5 n6'.split(' ');\n\nfunction makeCell() {\n  let cell = document.createElement('div');\n  cell.className = `cell ${getRandom( widthClasses )} ${getRandom( nClasses )}`;\n  let b = document.createElement('b');\n  b.textContent = ++cellCount;\n  cell.appendChild( b );\n  let removeButton = document.createElement('button');\n  removeButton.className = 'remove-button';\n  removeButton.textContent = '×';\n  cell.appendChild( removeButton );\n  return cell;\n}\n\nfunction makeCells() {\n  return [ makeCell(), makeCell(), makeCell() ];\n}\n\n// init\n[ ...document.querySelectorAll('.demo') ].forEach( ( demo ) => {\n  let container = demo.querySelector('.container');\n  let flkty = Flickity.data( container );\n\n  demo.querySelector('.container').addEventListener( 'click', function( event ) {\n    if ( event.target.matches('.remove-button') ) return;\n\n    let cellElement = event.target.closest('.cell');\n    flkty.remove( cellElement );\n  } );\n\n  demo.querySelector('.prepend-button').addEventListener( 'click', function() {\n    flkty.prepend( makeCells() );\n  } );\n\n  demo.querySelector('.insert-button').addEventListener( 'click', function() {\n    flkty.insert( makeCells(), 3 );\n  } );\n\n  demo.querySelector('.append-button').addEventListener( 'click', function() {\n    flkty.append( makeCells() );\n  } );\n\n} );\n\n// ----- reposition ----- //\n\n( function() {\n  let flkty = new Flickity('#reposition .container');\n  flkty.on( 'staticClick', function( event, pointer, cellElem ) {\n    if ( !cellElem ) return;\n\n    cellElem.classList.toggle('w3');\n    flkty.reposition();\n  } );\n} )();\n\n// ----- prepend single, #492 ----- //\n\n( function() {\n  let demo = document.querySelector('#prepend-single');\n  let flkty = new Flickity( demo.querySelector('.container') );\n  demo.querySelector('.prepend-button').addEventListener( 'click', function() {\n    flkty.prepend( makeCell() );\n  } );\n} )();\n"
  },
  {
    "path": "sandbox/js/basic.js",
    "content": "let flky = window.flky = new Flickity('#full-width');\n\n// flky.on( 'dragMove', function( event, pointer ) {\n//   console.log( event.type, pointer.pageX, pointer.pageY );\n// });\nflky.on( 'select', function() {\n  console.log( 'selected', flky.selectedIndex );\n} );\n\nflky.on( 'settle', function() {\n  console.log( 'settled', flky.x );\n} );\n\nlet halfWidthflky = new Flickity( '#half-width', {\n  cellAlign: 'left',\n} );\n\nhalfWidthflky.on( 'staticClick', function( event, pointer, cellIndex, cellElement ) {\n  console.log( cellIndex, cellElement );\n} );\n\nnew Flickity( '#gallery3', {\n} );\n\ndocument.querySelector('#gallery3 button').onclick = function() {\n  console.log('button click');\n};\n"
  },
  {
    "path": "sandbox/js/jquery.js",
    "content": "/* globals $ */\n\nlet $gallery1 = $('#gallery1').flickity();\nlet flkty = $gallery1.data('flickity');\n\n// $gallery1.on( 'dragMove', function( event, pointer ) {\n//   console.log( event.type, pointer.pageX, pointer.pageY );\n// });\n\n$gallery1.on( 'cellSelect.flickity', function( event ) {\n  console.log( 'selected', event.type, `ns:${event.namespace}`, flkty.selectedIndex );\n} );\n\n$gallery1.on( 'settle.flickity', function( event ) {\n  console.log( 'settled', flkty.x, event.type );\n} );\n\n$gallery1.on( 'staticClick.flickity', function( event, pointer, cellElem, cellIndex ) {\n  console.log( 'staticClick', event.type, cellIndex );\n} );\n\n$('#gallery2').flickity({\n  wrapAround: true,\n});\n"
  },
  {
    "path": "sandbox/js/scroll-event.js",
    "content": "let flkty = new Flickity( '.carousel1', {\n  initialIndex: 2,\n  // groupCells: true,\n  // wrapAround: true,\n  // cellAlign: 'right'\n} );\n\nlet progressBar = document.querySelector('.progress-bar');\n\nflkty.on( 'scroll', function( progress ) {\n  console.log( progress );\n  let width = Math.max( 0, Math.min( 1, progress ) );\n  progressBar.style.width = width * 100 + '%';\n} );\n\nflkty.reposition();\n\n// -----  ----- //\n\nlet paraBG = document.querySelector('.parallax__layer--bg');\nlet paraFG = document.querySelector('.parallax__layer--fg');\n\nlet paraFlkty = new Flickity( '.parallax__carousel', {\n\n} );\n\nlet cellRatio = 0.6;\nlet bgRatio = 0.8;\nlet fgRatio = 1.25;\n\nparaFlkty.on( 'scroll', function( progress ) {\n  // console.log( progress );\n  paraBG.style.left = ( 0.5 - ( 0.5 + progress * 4 ) * cellRatio * bgRatio ) * 100 + '%';\n  paraFG.style.left = ( 0.5 - ( 0.5 + progress * 4 ) * cellRatio * fgRatio ) * 100 + '%';\n} );\n\nparaFlkty.reposition();\n\n// -----  ----- //\n\nlet imgFlkty = new Flickity( '.image-carousel', {\n} );\n\nwindow.onload = function() {\n  imgFlkty.reposition();\n};\n\nlet imgs = document.querySelectorAll('.image-carousel img');\n\nimgFlkty.on( 'scroll', function() {\n  imgFlkty.slides.forEach( ( slide, i ) => {\n    let img = imgs[i];\n    let x = ( slide.target + imgFlkty.x ) * -0.333;\n    img.style.transform = `translateX(${x}px)`;\n  } );\n} );\n"
  },
  {
    "path": "sandbox/js/tricky-drag.js",
    "content": "let nonDragFlkty = new Flickity( '.carousel--non-drag', {\n  draggable: false,\n} );\n\nfunction onStaticClick( event, pointer, cellElem, cellIndex ) {\n  console.log( 'staticClick', this.element.className, cellIndex );\n}\n\nnonDragFlkty.on( 'staticClick', onStaticClick );\n\nlet singleCellFlkty = new Flickity('.carousel--single-cell');\nsingleCellFlkty.on( 'staticClick', onStaticClick );\n\nlet groupFlkty = new Flickity( '.carousel--group', {\n  groupCells: true,\n} );\n\ngroupFlkty.on( 'staticClick', function( event ) {\n  let cellElem = event.target.closest('.carousel-cell');\n  if ( cellElem ) groupFlkty.remove( cellElem );\n} );\n\nfunction makeGroupCell() {\n  let cell = document.createElement('div');\n  cell.className = 'carousel-cell';\n  let b = document.createElement('b');\n  b.textContent = groupFlkty.cells.length + 1;\n  cell.appendChild( b );\n  return cell;\n}\n\ndocument.querySelector('.add-group-cell-button').onclick = function() {\n  groupFlkty.append( makeGroupCell() );\n};\n"
  },
  {
    "path": "sandbox/js/v2-sizzle.js",
    "content": "let flkty = new Flickity( '.carousel', {\n  groupCells: true,\n  adaptiveHeight: true,\n  wrapAround: true,\n} );\n\nlet paraBg = document.querySelector('.parallax-layer--bg');\nlet paraFg = document.querySelector('.parallax-layer--fg');\nlet count = flkty.slides.length - 1;\n\nflkty.on( 'scroll', function( progress ) {\n  paraBg.style.left = ( 0.5 - ( 0.5 + progress * count ) * 0.7 ) * ( 37/36 ) * 100 + '%';\n  paraFg.style.left = ( 0.5 - ( 0.5 + progress * count ) * 1.5 ) * ( 37/36 ) * 100 + '%';\n} );\n\nflkty.reposition();\n"
  },
  {
    "path": "sandbox/js/wrap-around.js",
    "content": "window.flkty = new Flickity( '#gallery1', {\n  wrapAround: true,\n} );\n\nwindow.flkty2 = new Flickity( '#gallery2', {\n} );\n\nwindow.flkty6 = new Flickity( '#gallery6', {\n  wrapAround: true,\n  cellAlign: 'left',\n} );\n\nwindow.flkty4 = new Flickity( '#gallery4', {\n  wrapAround: true,\n  freeScroll: true,\n} );\n\nwindow.flky5 = new Flickity( '#gallery5', {\n  freeScroll: true,\n} );\n"
  },
  {
    "path": "sandbox/lazyload.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>lazyload</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n  <style>\n  * { box-sizing: border-box; }\n\n  .carousel {\n    border: 1px solid;\n    margin-bottom: 40px;\n  }\n\n  .carousel__image {\n    display: block;\n    margin-right: 20px;\n    height: 400px;\n    max-width: 100%;\n    min-width: 200px;\n    background: #DDD;\n    transition: opacity 0.8s;\n    opacity: 0;\n  }\n\n  .carousel__image.flickity-lazyloaded {\n    opacity: 1;\n  }\n\n  .carousel__cell {\n    width: 80%;\n    height: 400px;\n    margin-right: 20px;\n    background: #DDD;\n  }\n  \n  .carousel__cell__image,\n  .carousel__cell__image img {\n    display: block;\n    max-width: 100%;\n    max-height: 400px;\n    margin: 0 auto;\n  }\n  </style>\n\n</head>\n<body>\n\n<h1>lazyload</h1>\n\n<div class=\"carousel\" data-flickity='{ \"lazyLoad\": true }'>\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/q9zO6tw.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/bwy74ok.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/hODreXI.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/UORFJ3w.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/bAZWoqx.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/PgmEBSB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/aboaFoB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/LkmcILl.jpg\" />\n</div>\n\n<div class=\"carousel\"\n  data-flickity='{ \"lazyLoad\": 1, \"wrapAround\": true }'>\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/q9zO6tw.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/bwy74ok.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/hODreXI.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/UORFJ3w.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/bAZWoqx.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/PgmEBSB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/aboaFoB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/LkmcILl.jpg\" />\n</div>\n\n<div class=\"carousel\"\n  data-flickity='{ \"lazyLoad\": true }'>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/r8p3Xgq.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/q9zO6tw.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/bwy74ok.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/hODreXI.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/UORFJ3w.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/bAZWoqx.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/PgmEBSB.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/aboaFoB.jpg\" /></div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\" data-flickity-lazyload=\"https://i.imgur.com/LkmcILl.jpg\" /></div>\n</div>\n\n<div class=\"carousel carousel--jq\">\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/q9zO6tw.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"foo.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/hODreXI.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/UORFJ3w.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/bAZWoqx.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/PgmEBSB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/aboaFoB.jpg\" />\n  <img class=\"carousel__image\" data-flickity-lazyload=\"https://i.imgur.com/LkmcILl.jpg\" />\n</div>\n\n<h2>srcset</h2>\n\n<div class=\"carousel\" data-flickity='{ \"lazyLoad\": true }'>\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=718\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=718 720w,\n      https://picsum.photos/360/270/?image=718 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=517\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=517 720w,\n      https://picsum.photos/360/270/?image=517 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=696\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=696 720w,\n      https://picsum.photos/360/270/?image=696 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=56\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=56 720w,\n      https://picsum.photos/360/270/?image=56 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=1084\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=1084 720w,\n      https://picsum.photos/360/270/?image=1084 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n  <img class=\"carousel__image\"\n    data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=1080\"\n    data-flickity-lazyload-srcset=\"\n      https://picsum.photos/720/540/?image=1080 720w,\n      https://picsum.photos/360/270/?image=1080 360w\"\n    sizes=\"(min-width: 1024px) 720px, 360px\"\n    />\n</div>\n\n<div class=\"carousel\" data-flickity='{ \"lazyLoad\": true }'>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=718 720w,\n        https://picsum.photos/360/270/?image=718 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n  </div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=517 720w,\n        https://picsum.photos/360/270/?image=517 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n  </div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=696 720w,\n        https://picsum.photos/360/270/?image=696 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n    </div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=56 720w,\n        https://picsum.photos/360/270/?image=56 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n    </div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=1084 720w,\n        https://picsum.photos/360/270/?image=1084 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n  </div>\n  <div class=\"carousel__cell\">\n    <img class=\"carousel__cell__image\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=1080 720w,\n        https://picsum.photos/360/270/?image=1080 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\" />\n  </div>\n</div>\n\n<h2>&lt;picture&gt;</h2>\n\n<div class=\"carousel\" data-flickity='{ \"lazyLoad\": true }'>\n  <div class=\"carousel__cell\">\n    <picture class=\"carousel__cell__image\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/1036/1200/900\" media=\"(min-width: 1200px)\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/1036/800/600\" media=\"(min-width: 800px)\">\n      <img data-flickity-lazyload-src=\"https://picsum.photos/id/1036/400/300\">\n    </picture>\n  </div>\n  <div class=\"carousel__cell\">\n    <picture class=\"carousel__cell__image\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/103/1200/900\" media=\"(min-width: 1200px)\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/103/800/600\" media=\"(min-width: 800px)\">\n      <img data-flickity-lazyload-src=\"https://picsum.photos/id/103/400/300\">\n    </picture>\n  </div>\n  <div class=\"carousel__cell\">\n    <picture class=\"carousel__cell__image\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/1080/900/1200\" media=\"(min-width: 1200px)\">\n      <source data-flickity-lazyload-srcset=\"https://picsum.photos/id/1080/600/800\" media=\"(min-width: 800px)\">\n      <img data-flickity-lazyload-src=\"https://picsum.photos/id/1080/300/400\">\n    </picture>\n  </div>\n</div>\n\n<!-- jQuery -->\n<script src=\"../node_modules/jquery/dist/jquery.js\"></script>\n<script src=\"../node_modules/jquery-bridget/jquery-bridget.js\"></script>\n<!-- dependencies -->\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n<!-- Flickity -->\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script>\n\n  let $jQCarousel = $('.carousel--jq').flickity({\n    lazyLoad: true\n  });\n\n  $jQCarousel.on( 'lazyLoad', function( event, cellElem ) {\n  });\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/media.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>media</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n  <style>\n  .image-gallery img {\n    display: block;\n    margin-right: 20px;\n    max-height: 400px;\n    max-width: 100%;\n  }\n\n  #video-gallery1 .cell {\n    height: 300px;\n    width: auto;\n  }\n\n  .image-gallery-contained .image-cell {\n    width: 100%;\n    height: 300px;\n    background: black;\n    text-align: center;\n  }\n\n  .image-gallery-contained .image-cell a {\n    margin: 0 auto;\n  }\n\n  .image-gallery-contained .image-cell img {\n    height: 300px;\n  }\n  </style>\n\n</head>\n<body>\n\n  <h1>media</h1>\n\n\n  <div id=\"image-gallery1\" class=\"container image-gallery\"\n     data-flickity='{ \"wrapAround\": false, \"imagesLoaded\": true, \"percentPosition\": false }'>\n     <!-- images from unsplash.com -->\n     <img src=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n     <img src=\"https://i.imgur.com/q9zO6tw.jpg\" />\n     <img src=\"https://i.imgur.com/bwy74ok.jpg\" />\n     <img src=\"https://i.imgur.com/hODreXI.jpg\" />\n     <img src=\"https://i.imgur.com/UORFJ3w.jpg\" />\n     <img src=\"https://i.imgur.com/bAZWoqx.jpg\" />\n     <img src=\"https://i.imgur.com/PgmEBSB.jpg\" />\n     <img src=\"https://i.imgur.com/aboaFoB.jpg\" />\n     <img src=\"https://i.imgur.com/LkmcILl.jpg\" />\n   </div>\n\n  <div id=\"image-gallery2\" class=\"container image-gallery-contained\"\n     data-flickity='{ \"imagesLoaded\": true, \"percentPosition\": false }'>\n     <!-- images from unsplash.com -->\n\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/r8p3Xgq.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/q9zO6tw.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/bwy74ok.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/hODreXI.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/UORFJ3w.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/bAZWoqx.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/PgmEBSB.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/aboaFoB.jpg\" /></a>\n     </div>\n     <div class=\"image-cell\">\n       <a href=\"https://example.com\"><img src=\"https://i.imgur.com/LkmcILl.jpg\" /></a>\n     </div>\n   </div>\n\n   <!-- <div id=\"video-gallery1\" class=\"container video-gallery\">\n    <div class=\"cell\">\n      <iframe src=\"//player.vimeo.com/video/87701971\" width=\"534\" height=\"300\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <p><a href=\"https://vimeo.com/87701971\">Yosemite HD II</a> from <a href=\"https://vimeo.com/projectyose\">Project Yosemite</a> on <a href=\"https://vimeo.com\">Vimeo</a>.</p>\n    </div>\n    <div class=\"cell\">\n      <iframe width=\"400\" height=\"300\" src=\"//www.youtube.com/embed/MvUE4WUtChk\" frameborder=\"0\" allowfullscreen></iframe>\n    </div>\n    <div class=\"cell\">\n      <iframe src=\"//player.vimeo.com/video/115014610\" width=\"534\" height=\"300\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <p><a href=\"https://vimeo.com/115014610\">The Coast</a> from <a href=\"https://vimeo.com/nrsfilms\">NRS Films</a> on <a href=\"https://vimeo.com\">Vimeo</a>.</p>\n    </div>\n    <div class=\"cell\">\n      <iframe width=\"400\" height=\"300\" src=\"//www.youtube.com/embed/TmQd6S9wXYQ\" frameborder=\"0\" allowfullscreen></iframe>\n    </div>\n\n    <div class=\"cell\">\n      <iframe src=\"//player.vimeo.com/video/115680769\" width=\"712\" height=\"300\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <p><a href=\"https://vimeo.com/115680769\">Quids In</a> from <a href=\"https://vimeo.com/nbnumeric\">New Balance Numeric</a> on <a href=\"https://vimeo.com\">Vimeo</a>.</p>\n    </div>\n\n  </div> -->\n\n  <!-- <div id=\"demo2\" class=\"demo\">\n    <div class=\"container variable-width\"\n      data-flickity='{ \"wrapAround\": true, \"freeScroll\": true }'>\n    </div>\n  </div> -->\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n<script src=\"../node_modules/imagesloaded/imagesloaded.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n<script src=\"../js/imagesloaded.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/right-to-left.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\n  <title>right to left</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n  <style>\n  .variable-width .cell { margin: 0 0 0 4%; }\n  </style>\n\n</head>\n<body>\n\n  <h1>right to left</h1>\n\n  <div id=\"gallery1\" class=\"container variable-width\"\n    data-flickity='{ \"rightToLeft\": true, \"wrapAround\": true }'>\n    <div class=\"cell n1\"><b>1</b></div>\n    <div class=\"cell n2 w2\"><b>2</b></div>\n    <div class=\"cell n3 w3\"><b>3</b></div>\n    <div class=\"cell n4\"><b>4</b></div>\n    <div class=\"cell n5 w2\"><b>5</b></div>\n    <div class=\"cell n6\"><b>6</b></div>\n  </div>\n\n  <div id=\"gallery2\" class=\"container variable-width\"\n    data-flickity='{ \"rightToLeft\": true }'>\n    <div class=\"cell n1\"><b>1</b></div>\n    <div class=\"cell n2 w2\"><b>2</b></div>\n    <div class=\"cell n3 w3\"><b>3</b></div>\n    <div class=\"cell n4\"><b>4</b></div>\n    <div class=\"cell n5 w2\"><b>5</b></div>\n    <div class=\"cell n6\"><b>6</b></div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/sandbox.css",
    "content": "* { box-sizing: border-box; }\n\nbody {\n  font-family: sans-serif;\n  color: #333;\n}\n\n.container {\n  border: 1px solid;\n  margin-bottom: 50px;\n}\n\n.container::after {\n  content: '';\n  display: block;\n  clear: both;\n}\n\n.container:focus { border: 1px blue dotted; }\n\n.cell {\n  width: 100%;\n  height: 200px;\n  border: 0 solid white;\n  background: #CCC;\n}\n\n.cell.is-selected {\n  outline: 4px solid hsla(0, 0%, 0%, 25%);\n  outline-offset: -4px;\n}\n\n.cell:nth-child(6n) { background: hsl(0, 80%, 70%); }\n.cell:nth-child(6n+1) { background: hsl(60, 80%, 70%); }\n.cell:nth-child(6n+2) { background: hsl(120, 80%, 70%); }\n.cell:nth-child(6n+3) { background: hsl(180, 80%, 70%); }\n.cell:nth-child(6n+4) { background: hsl(240, 80%, 70%); }\n.cell:nth-child(6n+5) { background: hsl(300, 80%, 70%); }\n\n.cell.n1 { background: hsl(0, 80%, 70%); }\n.cell.n2 { background: hsl(60, 80%, 70%); }\n.cell.n3 { background: hsl(120, 80%, 70%); }\n.cell.n4 { background: hsl(180, 80%, 70%); }\n.cell.n5 { background: hsl(240, 80%, 70%); }\n.cell.n6 { background: hsl(300, 80%, 70%); }\n\n.variable-width .cell {\n  width: 20%;\n  margin-right: 3%;\n}\n\n.variable-width .cell.w2 { width: 30%; }\n.variable-width .cell.w3 { width: 40%; }\n\n.fixed-width .cell {\n  width: 200px;\n  margin-right: 20px;\n}\n\n#half-width .cell {\n  width: 48%;\n  margin-right: 4%;\n}\n\n/* big number */\n.cell b {\n  display: block;\n  font-size: 100px;\n  color: white;\n  font-weight: bold;\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n\n/* ---- couning ---- */\n.counting {\n  counter-reset: cell;\n}\n\n.counting .cell::before {\n  counter-increment: cell;\n  content: counter(cell);\n  display: block;\n  font-size: 100px;\n  color: white;\n  font-weight: bold;\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n"
  },
  {
    "path": "sandbox/scroll-event.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>scroll event</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n<style>\n* { box-sizing: border-box; }\n\nhtml { overflow-y: scroll; }\n\n.carousel {\n  border: 1px solid;\n  margin-bottom: 40px;\n/*  width: 1000px;*/\n}\n\n.carousel__cell {\n/*  width: 25%;*/\n  width: 32%;\n  height: 200px;\n  background: #BDF;\n  margin-left: 1%;\n  margin-right: 1%;\n  font-size: 40px;\n}\n\n/*.carousel__cell--width2 { width: 40%; }\n.carousel__cell--width3 { width: 80%; }*/\n\n.carousel__cell--width2 { width: 66%; }\n.carousel__cell--width3 { width: 100%; }\n\n.carousel__cell.is-selected {\n  background: #68F;\n}\n\n.progress-bar {\n  height: 10px;\n  width: 0;\n  background: #333;\n}\n\n@media (min-width: 1000px) {\n  /* fit four */\n  .carousel__cell { width: 23.5%; }\n  .carousel__cell--width2 { width: 49%; }\n  .carousel__cell--width3 { width: 74.5%; }\n}\n\n\n\n/* ---- parallax ---- */\n\n.parallax {\n  margin-top: 100px;\n  position: relative;\n  overflow-x: hidden;\n  padding-bottom: 40px;\n}\n\n.parallax__carousel__cell {\n  background: hsla(0, 100%, 50%, 0.4);\n  height: 220px;\n  width: 50%;\n  margin: 40px 5%;\n}\n\n.parallax__layer {\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n\n.parallax__layer--bg {\n  top: 70px;\n  width: 80%;\n  height: 160px;\n}\n\n.parallax__layer--fg {\n  pointer-events: none;\n  width: 125%;\n  height: 300px;\n}\n\n.parallax__layer__cell {\n  position: absolute;\n  width: 50%;\n  margin: 0 5%;\n  height: 100%;\n}\n\n.parallax__layer__cell:nth-child(1) { left: 0%; }\n.parallax__layer__cell:nth-child(2) { left: 60%; }\n.parallax__layer__cell:nth-child(3) { left: 120%; }\n.parallax__layer__cell:nth-child(4) { left: 180%; }\n.parallax__layer__cell:nth-child(5) { left: 240%; }\n\n.parallax__layer__cell--bg {\n  background: hsla(210, 100%, 50%, 0.4);\n}\n\n.parallax__layer__cell--fg {\n  background: hsla(60, 100%, 50%, 0.4);\n}\n\n\n/* ----  ---- */\n\n.image-carousel__cell {\n  margin-right: 20px;\n  overflow: hidden;\n}\n\n.image-carousel__cell img {\n  display: block;\n  height: 400px;\n}\n</style>\n\n</head>\n<body>\n\n  <h1>scroll event</h1>\n\n<div class=\"carousel carousel1\">\n  <div class=\"carousel__cell carousel__cell--width2\">0</div>\n  <div class=\"carousel__cell\">1</div>\n  <div class=\"carousel__cell\">2</div>\n  <div class=\"carousel__cell carousel__cell--width2\">3</div>\n  <div class=\"carousel__cell carousel__cell--width2\">4</div>\n  <div class=\"carousel__cell\">5</div>\n  <div class=\"carousel__cell\">6</div>\n  <div class=\"carousel__cell\">7</div>\n  <div class=\"carousel__cell carousel__cell--width3\">8</div>\n  <div class=\"carousel__cell\">9</div>\n  <div class=\"carousel__cell\">10</div>\n</div>\n\n<div class=\"progress-bar\"></div>\n\n<div class=\"parallax\">\n\n  <div class=\"parallax__layer parallax__layer--bg\">\n    <div class=\"parallax__layer__cell parallax__layer__cell--bg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--bg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--bg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--bg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--bg\"></div>\n  </div>\n\n  <div class=\"parallax__carousel\">\n    <div class=\"parallax__carousel__cell\"></div>\n    <div class=\"parallax__carousel__cell\"></div>\n    <div class=\"parallax__carousel__cell\"></div>\n    <div class=\"parallax__carousel__cell\"></div>\n    <div class=\"parallax__carousel__cell\"></div>\n  </div>\n\n  <div class=\"parallax__layer parallax__layer--fg\">\n    <div class=\"parallax__layer__cell parallax__layer__cell--fg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--fg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--fg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--fg\"></div>\n    <div class=\"parallax__layer__cell parallax__layer__cell--fg\"></div>\n  </div>\n\n</div>\n\n<div class=\"image-carousel\">\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/r8p3Xgq.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/q9zO6tw.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/bwy74ok.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/hODreXI.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/UORFJ3w.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/bAZWoqx.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/PgmEBSB.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/aboaFoB.jpg\" /></div>\n   <div class=\"image-carousel__cell\"><img src=\"https://i.imgur.com/LkmcILl.jpg\" /></div>\n </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script src=\"js/scroll-event.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/single.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>single</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n  <style>\n    html {\n      overflow-y: scroll;\n    }\n  </style>\n\n</head>\n<body>\n\n  <h1>single</h1>\n\n  <div id=\"gallery\" class=\"container\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2\">2</div>\n    <div class=\"cell n3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5\">5</div>\n    <div class=\"cell n6\">6</div>\n    <div class=\"cell n1\">7</div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script>\nlet = new Flickity('#gallery', {\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/styles.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>styles</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n</head>\n<body>\n\n  <h1>styles</h1>\n\n  <div class=\"container carousel1\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n  </div>\n\n  <div class=\"container carousel2\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n  </div>\n\n  <div class=\"container carousel3\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n<script src=\"../js/lazyload.js\"></script>\n\n<script>\n  new Flickity( '.carousel1', {\n    arrowShape: {\n      x0: 10,\n      x1: 50, y1: 30,\n      x2: 70, y2: 30,\n      x3: 50\n    }\n  });\n\n  new Flickity( '.carousel2', {\n    arrowShape: 'M 0,50 L 60,00 L 50,30 L 80,30 L 80,70 L 50,70 L 60,100 Z'\n  });\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/tricky-drag.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>tricky drag</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n  <style>\n    .carousel {\n      background: #EEE;\n      margin-bottom: 40px;\n    }\n\n    .carousel-cell {\n      height: 200px;\n      width: 25%;\n      margin: 0 10px;\n      background: #6C6;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border-radius: 8px;\n    }\n\n    .carousel-cell b {\n      display: block;\n      font-size: 80px;\n      color: white;\n    }\n  </style>\n\n</head>\n<body>\n\n<h1>tricky drag</h1>\n\n<div class=\"carousel carousel--non-drag\">\n  <div class=\"carousel-cell\"><b>1</b></div>\n  <div class=\"carousel-cell\"><b>2</b></div>\n  <div class=\"carousel-cell\"><b>3</b></div>\n  <div class=\"carousel-cell\"><b>4</b></div>\n  <div class=\"carousel-cell\"><b>5</b></div>\n  <div class=\"carousel-cell\"><b>6</b></div>\n  <div class=\"carousel-cell\"><b>7</b></div>\n</div>\n\n<div class=\"carousel carousel--single-cell\">\n  <div class=\"carousel-cell\"><b>1</b></div>\n</div>\n\n<div class=\"carousel carousel--group\">\n  <div class=\"carousel-cell\"><b>1</b></div>\n  <div class=\"carousel-cell\"><b>2</b></div>\n</div>\n\n<p><button class=\"add-group-cell-button\">Add cell</button></p>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script src=\"js/tricky-drag.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/v2-sizzle.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>v2 sizzle</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" media=\"screen\" />\n\n  <style>\n\n  body { font-family: Texta; }\n\n  * { box-sizing: border-box; }\n\n  .parallax-container {\n    position: relative;\n    width: 360px;\n    height: 400px;\n    overflow: hidden;\n    margin: 40px auto;\n  }\n\n  .carousel {\n    width: 100%;\n  }\n\n  .flickity-viewport {\n    transition: height 0.2s;\n  }\n\n  .cell {\n    width: 360px;\n    height: 200px;\n    margin-right: 10px;\n    background: #8C8;\n    border-radius: 8px;\n  }\n\n  .cell--half-width {\n    width: 175px;\n  }\n\n  .cell--third-width {\n    width: calc((360px - 20px) / 3);\n  }\n\n  .cell--height1 {\n    height: 300px;\n  }\n\n  .cell--height2 {\n    height: 250px;\n  }\n\n  .cell__word {\n    color: white;\n    font-size: 54px;\n    line-height: 1.0;\n    display: block;\n    padding: 20px;\n    width: 100%;\n    position: absolute;\n    top: 50%;\n    left: 0;\n    transform: translateY(-50%);\n    text-align: center;\n  }\n\n\n  .cell--half-width .cell__word {\n    font-size: 40px;\n  }\n\n  .cell__word--group { text-align: right;  }\n  .cell__word--cells { text-align: left;  }\n\n  .cell--parallax { opacity: 0.6; }\n\n  .flickity-prev-next-button {\n    width: 36px;\n    height: 36px;\n  }\n\n  .parallax-layer {\n    position: absolute;\n    left: 0;\n    top: 0;\n    pointer-events: none;\n  }\n  \n  .parallax-layer--bg {\n    width: calc((100% + 10px)* 0.7);\n  }\n  \n  .parallax-bg-cell {\n    width: 252px;\n    height: 140px;\n    background: #19F;\n    position: absolute;\n    top: 30px;\n    border-radius: 6px;\n    opacity: 0.6;\n  }\n  \n/*  .parallax-bg-cell:nth-child(1) { left: 0px; }\n  .parallax-bg-cell:nth-child(2) { left: 296px; }\n  .parallax-bg-cell:nth-child(3) { left: 592px; }\n  .parallax-bg-cell:nth-child(4) { left: 888px; }*/\n  .parallax-bg-cell:nth-child(1) { left: 1036px; }\n  .parallax-bg-cell:nth-child(2) { left: 1295px; }\n\n  .parallax-layer--fg {\n    width: calc((100% + 10px)* 1.5);\n  }\n\n  .parallax-fg-cell {\n    width: 100%;\n    position: absolute;\n    top: 0;\n    font-size: 54px;\n    line-height: 200px;\n    text-align: center;\n    color: white;\n  }\n\n  .parallax-fg-cell:nth-child(1) { left: 400%; }\n  .parallax-fg-cell:nth-child(2) { left: 500%; }\n  .parallax-fg-cell:nth-child(3) { left: 600%; }\n\n  </style>\n\n</head>\n<body>\n\n<div class=\"parallax-container\">\n  <div class=\"parallax-layer parallax-layer--bg\">\n    <!-- <div class=\"parallax-bg-cell\"></div>\n    <div class=\"parallax-bg-cell\"></div>\n    <div class=\"parallax-bg-cell\"></div>\n    <div class=\"parallax-bg-cell\"></div> -->\n    <div class=\"parallax-bg-cell\"></div>\n    <div class=\"parallax-bg-cell\"></div>\n  </div>\n\n  <div class=\"carousel\">\n    <div class=\"cell cell--half-width\">\n      <span class=\"cell__word cell__word--group\">Group</span>\n    </div>\n    <div class=\"cell cell--half-width\">\n      <span class=\"cell__word cell__word--cells\">cells</span>\n    </div>\n    <div class=\"cell cell--third-width\"></div>\n    <div class=\"cell cell--third-width\"></div>\n    <div class=\"cell cell--third-width\"></div>\n    <div class=\"cell cell--height1\">\n      <span class=\"cell__word\">Adaptive height</span>\n    </div>\n    <div class=\"cell\">\n    </div>\n    <div class=\"cell cell--parallax\"></div>\n    <div class=\"cell cell--parallax\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <div class=\"parallax-layer parallax-layer--fg\">\n    <div class=\"parallax-fg-cell\">Parallax</div>\n    <div class=\"parallax-fg-cell\">whoa</div>\n    <div class=\"parallax-fg-cell\">Flickity v2</div>\n  </div>\n</div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script src=\"v2-sizzle.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "sandbox/wrap-around.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>wrap around</title>\n\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n  <link rel=\"stylesheet\" href=\"sandbox.css\" />\n\n  <style>\n    #no-margin .cell {\n      width: 25%;\n      margin: 0;\n    }\n\n    #tight-wrap {\n      width: 200px;\n      margin-left: auto;\n      margin-right: auto;\n    }\n\n    #tight-wrap .cell {\n      width: 50%;\n    }\n  </style>\n\n</head>\n<body>\n\n  <h1>wrap around</h1>\n\n  <div id=\"gallery1\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n  <div id=\"gallery2\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6 w3\">6</div>\n  </div>\n\n  <h2>Left aligned</h2>\n\n  <div id=\"gallery6\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n  <h2>Fixed-width cells, pixel-positioning HTML init</h2>\n\n  <div id=\"gallery7\" class=\"container fixed-width\"\n    data-flickity='{ \"wrapAround\": true, \"percentPosition\": false }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2\">2</div>\n    <div class=\"cell n3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5\">5</div>\n    <div class=\"cell n6\">6</div>\n    <div class=\"cell n1\">7</div>\n    <div class=\"cell n2\">8</div>\n  </div>\n\n  <h2>HTML init</h2>\n\n  <div id=\"gallery3\" class=\"container variable-width\"\n    data-flickity='{ \"wrapAround\": true }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n  <h2>freeScroll</h2>\n\n  <div id=\"gallery4\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6\">6</div>\n  </div>\n\n  <div id=\"gallery5\" class=\"container variable-width\">\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5 w2\">5</div>\n    <div class=\"cell n6 w3\">6</div>\n  </div>\n\n  <h2>no margin for error</h2>\n  <div id=\"no-margin\" class=\"container variable-width\"\n    data-flickity='{ \"wrapAround\": true, \"cellAlign\": \"right\" }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2\">2</div>\n    <div class=\"cell n3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n5\">5</div>\n  </div>\n\n  <h2>tight wrap #589</h2>\n  <div id=\"tight-wrap\" class=\"container\" data-flickity='{ \"wrapAround\": true }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2\">2</div>\n    <div class=\"cell n3\">3</div>\n    <div class=\"cell n4\">4</div>\n  </div>\n\n  <h2>wrapAround: 'fill', should disabled</h2>\n  <div class=\"container variable-width\" data-flickity='{ \"wrapAround\": \"fill\" }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n  </div>\n\n  <h2>wrapAround: 'fill', should enabled</h2>\n  <div class=\"container variable-width\" data-flickity='{ \"wrapAround\": \"fill\" }'>\n    <div class=\"cell n1\">1</div>\n    <div class=\"cell n2 w2\">2</div>\n    <div class=\"cell n3 w3\">3</div>\n    <div class=\"cell n4\">4</div>\n    <div class=\"cell n4\">5</div>\n  </div>\n\n<script src=\"../node_modules/get-size/get-size.js\"></script>\n<script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n<script src=\"../node_modules/unidragger/unidragger.js\"></script>\n<script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n\n<script src=\"../js/cell.js\"></script>\n<script src=\"../js/slide.js\"></script>\n<script src=\"../js/animate.js\"></script>\n<script src=\"../js/core.js\"></script>\n<script src=\"../js/drag.js\"></script>\n<script src=\"../js/prev-next-button.js\"></script>\n<script src=\"../js/page-dots.js\"></script>\n<script src=\"../js/player.js\"></script>\n<script src=\"../js/add-remove-cell.js\"></script>\n\n<script src=\"js/wrap-around.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "stylelint.config.js",
    "content": "module.exports = {\n  extends: 'stylelint-config-standard',\n  ignoreFiles: [ 'dist/*' ],\n  rules: {\n    'color-function-notation': 'legacy',\n    'color-hex-case': 'upper',\n    'comment-empty-line-before': null,\n    'declaration-block-no-duplicate-properties': [ true, {\n      ignore: [ 'consecutive-duplicates-with-different-values' ],\n    } ],\n    'hue-degree-notation': 'number',\n    'property-no-vendor-prefix': null,\n    'selector-class-pattern': null,\n    'string-quotes': 'single',\n  },\n};\n"
  },
  {
    "path": "test/drag.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>Drag tests</title>\n\n  <link rel=\"stylesheet\" href=\"../node_modules/qunit/qunit/qunit.css\" media=\"screen\" />\n  <link rel=\"stylesheet\" href=\"test.css\" media=\"screen\" />\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" media=\"screen\" />\n\n  <script src=\"../node_modules/qunit/qunit/qunit.js\"></script>\n\n  <!-- dependencies -->\n  <script src=\"../node_modules/get-size/get-size.js\"></script>\n  <script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n  <script src=\"../node_modules/unidragger/unidragger.js\"></script>\n  <script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n  <!-- Flickity source -->\n  <script src=\"../js/cell.js\"></script>\n  <script src=\"../js/slide.js\"></script>\n  <script src=\"../js/animate.js\"></script>\n  <script src=\"../js/core.js\"></script>\n  <script src=\"../js/drag.js\"></script>\n  <script src=\"../js/prev-next-button.js\"></script>\n  <script src=\"../js/page-dots.js\"></script>\n  <script src=\"../js/player.js\"></script>\n  <script src=\"../js/add-remove-cell.js\"></script>\n  <script src=\"../js/lazyload.js\"></script>\n  <!-- turn off accessibility for these tests\n    was causing bugs with dragging tests -->\n  <script>\n    Flickity.defaults.accessibility = false;\n  </script>\n  <!-- unit tests -->\n  <script src=\"unit/drag.js\"></script>\n\n</head>\n<body>\n\n  <div id=\"qunit\"></div>\n\n  <div id=\"demos\">\n    <p><b>drag</b> and <b>drag with wrapAround</b> tests can be buggy. Try running them again.</p>\n\n    <h2>drag</h2>\n    <div id=\"drag\" class=\"gallery variable-width drag\">\n      <div class=\"cell\">1</div>\n      <div class=\"cell\">2</div>\n      <div class=\"cell\">3</div>\n      <div class=\"cell\">4</div>\n      <div class=\"cell\">5</div>\n      <div class=\"cell\">6</div>\n    </div>\n\n    <h2>drag wrapAround</h2>\n    <div id=\"drag-wrap-around\" class=\"gallery variable-width drag\">\n      <div class=\"cell\">1</div>\n      <div class=\"cell\">2</div>\n      <div class=\"cell\">3</div>\n      <div class=\"cell\">4</div>\n      <div class=\"cell\">5</div>\n      <div class=\"cell\">6</div>\n    </div>\n  </div>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width\" />\n\n  <title>Flickity tests</title>\n\n  <link rel=\"stylesheet\" href=\"../node_modules/qunit/qunit/qunit.css\" />\n  <link rel=\"stylesheet\" href=\"test.css\" />\n  <link rel=\"stylesheet\" href=\"../css/flickity.css\" />\n\n  <script src=\"../node_modules/qunit/qunit/qunit.js\"></script>\n\n  <!-- dependencies -->\n  <script src=\"../node_modules/get-size/get-size.js\"></script>\n  <script src=\"../node_modules/ev-emitter/ev-emitter.js\"></script>\n  <script src=\"../node_modules/fizzy-ui-utils/utils.js\"></script>\n  <script src=\"../node_modules/unidragger/unidragger.js\"></script>\n  <script src=\"../node_modules/imagesloaded/imagesloaded.js\"></script>\n  <!-- Flickity source -->\n  <script src=\"../js/cell.js\"></script>\n  <script src=\"../js/slide.js\"></script>\n  <script src=\"../js/animate.js\"></script>\n  <script src=\"../js/core.js\"></script>\n  <script src=\"../js/drag.js\"></script>\n  <script src=\"../js/prev-next-button.js\"></script>\n  <script src=\"../js/page-dots.js\"></script>\n  <script src=\"../js/player.js\"></script>\n  <script src=\"../js/add-remove-cell.js\"></script>\n  <script src=\"../js/lazyload.js\"></script>\n  <script src=\"../js/imagesloaded.js\"></script>\n  <!-- unit tests -->\n  <script src=\"unit/init.js\"></script>\n  <script src=\"unit/cell-selector.js\"></script>\n  <script src=\"unit/empty.js\"></script>\n  <script src=\"unit/get-parent-cell.js\"></script>\n  <script src=\"unit/position-cells.js\"></script>\n  <script src=\"unit/contain.js\"></script>\n  <script src=\"unit/auto-play.js\"></script>\n  <script src=\"unit/prev-next-buttons.js\"></script>\n  <script src=\"unit/page-dots.js\"></script>\n  <script src=\"unit/get-wrap-cells.js\"></script>\n  <script src=\"unit/watch.js\"></script>\n  <script src=\"unit/resize.js\"></script>\n  <script src=\"unit/add-remove-cells.js\"></script>\n  <script src=\"unit/destroy.js\"></script>\n  <script src=\"unit/lazyload.js\"></script>\n  <script src=\"unit/lazyload-srcset.js\"></script>\n  <script src=\"unit/group-cells.js\"></script>\n  <script src=\"unit/adaptive-height.js\"></script>\n  <script src=\"unit/select-cell.js\"></script>\n  <script src=\"unit/change.js\"></script>\n  <script src=\"unit/initial-index.js\"></script>\n  <script src=\"unit/wrap-around-fill.js\"></script>\n  <script src=\"unit/imagesloaded.js\"></script>\n\n</head>\n<body>\n\n  <div id=\"qunit\"></div>\n\n  <h2>Init</h2>\n\n  <div id=\"init\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>cellSelector</h2>\n\n  <div id=\"cell-selector\" class=\"gallery\">\n    <p class=\"not-cell not-cell1\">not cell 1</p>\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <p class=\"not-cell not-cell2\">not cell 2</p>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>empty</h2>\n\n  <div id=\"empty\" class=\"gallery\"></div>\n\n  <h2>getParentCell</h2>\n\n  <div id=\"get-parent-cell\" class=\"gallery\">\n    <div class=\"cell cell1\"><span class=\"child1\">1</span></div>\n    <div class=\"cell\"><div><span class=\"child2\">2</span></div></div>\n    <div class=\"cell cell3\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n  <div class=\"outside\"></div>\n\n  <h2>position cells</h2>\n\n  <div id=\"position-cells\" class=\"gallery variable-width\">\n    <div class=\"cell width2\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell width3\">3</div>\n    <div class=\"cell width2\">4</div>\n    <div class=\"cell width3\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>contain</h2>\n\n  <div id=\"contain\" class=\"gallery variable-width\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell width3\">3</div>\n    <div class=\"cell width2\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>auto-play</h2>\n  <div id=\"auto-play\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n  </div>\n\n  <h2>prev/next buttons</h2>\n  <div id=\"prev-next-buttons\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>page dots</h2>\n  <div id=\"page-dots\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>getWrapCells</h2>\n  <div id=\"get-wrap-cells\" class=\"gallery variable-width\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>watch</h2>\n  <div id=\"watch\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>resize</h2>\n  <div id=\"resize\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>add/remove-cells</h2>\n  <div id=\"add-remove-cells\" class=\"gallery variable-width\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>destroy</h2>\n  <div id=\"destroy\" class=\"gallery\">\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n  </div>\n\n  <h2>lazyload</h2>\n  <div id=\"lazyload\" class=\"gallery\">\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/r8p3Xgq.jpg\" /></div>\n    <img class=\"img-cell\" data-flickity-lazyload=\"https://i.imgur.com/q9zO6tw.jpg\" />\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/bwy74ok.jpg\" /></div>\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/hODreXI.jpg\" /></div>\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/UORFJ3w.jpg\" /></div>\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/bAZWoqx.jpg\" /></div>\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/PgmEBSB.jpg\" /></div>\n    <img class=\"img-cell\" data-flickity-lazyload=\"https://i.imgur.com/aboaFoB.jpg\" />\n    <div class=\"cell\"><img data-flickity-lazyload=\"https://i.imgur.com/LkmcILl.jpg\" /></div>\n  </div>\n\n  <h2>lazyload srcset</h2>\n  <div id=\"lazyload-srcset\" class=\"gallery\">\n    <div class=\"cell\">\n      <img data-flickity-lazyload-src=\"https://picsum.photos/360/270/?image=718\"\n        data-flickity-lazyload-srcset=\"\n          https://picsum.photos/720/540/?image=718 720w,\n          https://picsum.photos/360/270/?image=718 360w\"\n        sizes=\"(min-width: 1024px) 720px, 360px\" />\n    </div>\n    <img class=\"img-cell\"\n      data-flickity-lazyload-srcset=\"\n        https://picsum.photos/720/540/?image=517 720w,\n        https://picsum.photos/360/270/?image=517 360w\"\n      sizes=\"(min-width: 1024px) 720px, 360px\"\n      />\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <h2>groupCells</h2>\n  <div id=\"group-cells\" class=\"gallery\">\n    <div class=\"cell\"></div>\n    <div class=\"cell cell--width2\"></div>\n    <div class=\"cell\"></div>\n\n    <div class=\"cell cell--width3\"></div>\n    <div class=\"cell\"></div>\n\n    <div class=\"cell cell--width2\"></div>\n    <div class=\"cell cell--width2\"></div>\n\n    <div class=\"cell cell--width2\"></div>\n\n    <div class=\"cell cell--width4\"></div>\n\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell cell--width2\"></div>\n\n    <div class=\"cell\"></div>\n    <div class=\"cell\"></div>\n  </div>\n\n  <h2>adaptiveHeight</h2>\n  <div id=\"adaptive-height\" class=\"gallery\">\n    <div class=\"cell cell--height2\"></div>\n    <div class=\"cell\"></div>\n    <div class=\"cell cell--height3\"></div>\n\n    <div class=\"cell\"></div>\n    <div class=\"cell cell--height4\"></div>\n    <div class=\"cell cell--height2\"></div>\n\n    <div class=\"cell\"></div>\n    <div class=\"cell cell--height2\"></div>\n  </div>\n\n  <h2>selectCell</h2>\n  <div id=\"select-cell\" class=\"gallery\">\n    <div class=\"cell select-cell__0\">0</div>\n    <div class=\"cell select-cell__1\">1</div>\n    <div class=\"cell select-cell__2\">2</div>\n    <div class=\"cell select-cell__3\">3</div>\n    <div class=\"cell select-cell__4\">4</div>\n    <div class=\"cell select-cell__5\">5</div>\n    <div class=\"cell select-cell__6\">6</div>\n    <div class=\"cell select-cell__7\">7</div>\n  </div>\n\n  <h2>change</h2>\n  <div id=\"change\" class=\"gallery\">\n    <div class=\"cell\">0</div>\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell\">4</div>\n  </div>\n\n  <h2>initialIndex</h2>\n  <div id=\"initial-index\" class=\"gallery variable-width\">\n    <div class=\"cell\">0</div>\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell cell--initial\">4</div>\n    <div class=\"cell\">5</div>\n    <div class=\"cell\">6</div>\n    <div class=\"cell\">7</div>\n    <div class=\"cell\">8</div>\n    <div class=\"cell\">9</div>\n  </div>\n\n  <h2>wrapAround: fill</h2>\n  <div id=\"wrap-around-fill\" class=\"gallery variable-width\">\n    <div class=\"cell\">0</div>\n    <div class=\"cell\">1</div>\n    <div class=\"cell\">2</div>\n    <div class=\"cell\">3</div>\n    <div class=\"cell cell--wrap-around-short\">4</div>\n  </div>\n\n  <h2>imagesLoaded</h2>\n  <div id=\"imagesloaded\" class=\"gallery gallery--imagesloaded\">\n    <img src=\"https://i.imgur.com/r8p3Xgq.jpg\" />\n    <img src=\"https://i.imgur.com/q9zO6tw.jpg\" />\n    <img src=\"https://i.imgur.com/bwy74ok.jpg\" />\n    <img src=\"https://i.imgur.com/hODreXI.jpg\" />\n    <img src=\"https://i.imgur.com/UORFJ3w.jpg\" />\n    <img src=\"https://i.imgur.com/bAZWoqx.jpg\" />\n    <img src=\"https://i.imgur.com/PgmEBSB.jpg\" />\n    <img src=\"https://i.imgur.com/aboaFoB.jpg\" />\n    <img src=\"https://i.imgur.com/LkmcILl.jpg\" />\n  </div>\n\n  <div id=\"imagesloaded-in-divs\" class=\"gallery gallery--imagesloaded\">\n    <div><img src=\"https://i.imgur.com/r8p3Xgq.jpg\" /></div>\n    <div><img src=\"https://i.imgur.com/q9zO6tw.jpg\" /></div>\n    <div><img src=\"https://i.imgur.com/bwy74ok.jpg\" /></div>\n    <div><div><img src=\"https://i.imgur.com/hODreXI.jpg\" /></div></div>\n    <div><div><img src=\"https://i.imgur.com/UORFJ3w.jpg\" /></div></div>\n    <div><img src=\"https://i.imgur.com/bAZWoqx.jpg\" /></div>\n    <div><img src=\"https://i.imgur.com/PgmEBSB.jpg\" /></div>\n    <div><div><img src=\"https://i.imgur.com/aboaFoB.jpg\" /></div></div>\n    <div><img src=\"https://i.imgur.com/LkmcILl.jpg\" /></div>\n  </div>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/test.css",
    "content": "/* stylelint-disable no-descending-specificity */\n\nbody {\n  font-family: sans-serif;\n  color: #333;\n}\n\n/* move over qunit window to reduce overlaps */\n@media (min-height: 500px) {\n  #qunit {\n    left: 420px;\n  }\n}\n\n.gallery {\n  border: 1px solid;\n  width: 400px;\n  margin-bottom: 40px;\n}\n\n.gallery--imagesloaded img {\n  display: block;\n  height: 140px;\n}\n\n.gallery .cell {\n  width: 100%;\n  height: 100px;\n  background: #F09;\n  font-size: 40px;\n  color: white;\n}\n\n.variable-width .cell { width: 25%; } /* 100px */\n.variable-width .cell.width2 {\n  width: 40%; /* 160px */\n  background: #F90;\n}\n\n.variable-width .cell.width3 {\n  width: 60%; /* 240px */\n  background: #09F;\n}\n\n#position-cells.percent-margin .cell { margin: 0 2%; }\n#position-cells.pixel-margin .cell { margin: 0 10px; }\n\n.drag .cell { margin-right: 5%; }\n\n#watch.has-after::after {\n  content: 'flickity';\n  display: none;\n}\n\n#lazyload img {\n  display: block;\n  max-height: 100px;\n}\n\n/* ---- group-cells ---- */\n\n#group-cells .cell {\n  width: 100px;\n}\n\n#group-cells .cell--width2 { width: 200px; }\n#group-cells .cell--width3 { width: 300px; }\n#group-cells .cell--width4 { width: 400px; }\n\n#group-cells.is-expanded { width: 600px; }\n\n#group-cells .cell:nth-child(2n) { background: #09F; }\n\n/* ---- adaptive-height ---- */\n\n#adaptive-height .cell { width: 33.33%; }\n\n#adaptive-height .cell--height2 { height: 200px; }\n#adaptive-height .cell--height3 { height: 300px; }\n#adaptive-height .cell--height4 { height: 400px; }\n\n#adaptive-height .cell:nth-child(2n) { background: #09F; }\n\n/* ---- select-cell ---- */\n\n#select-cell .cell { width: 33.33%; }\n\n/* ---- wrap-around-fill ---- */\n\n.variable-width .cell.cell--wrap-around-short {\n  width: 20%;\n}\n"
  },
  {
    "path": "test/unit/adaptive-height.js",
    "content": "QUnit.test( 'adaptiveHeight', function( assert ) {\n\n  let flkty = new Flickity( '#adaptive-height', {\n    adaptiveHeight: true,\n  } );\n\n  // 2,1,3, 1,4,2, 1,2,1\n\n  function checkSelectHeight( index, height ) {\n    flkty.select( index, false, true );\n    assert.equal( flkty.viewport.style.height, `${height}px`, `slide ${index}` );\n  }\n\n  checkSelectHeight( 0, 200 );\n  checkSelectHeight( 1, 100 );\n  checkSelectHeight( 2, 300 );\n  checkSelectHeight( 3, 100 );\n  checkSelectHeight( 4, 400 );\n  checkSelectHeight( 5, 200 );\n\n  flkty.options.groupCells = true;\n  flkty.resize();\n\n  checkSelectHeight( 0, 300 );\n  checkSelectHeight( 1, 400 );\n  checkSelectHeight( 2, 200 );\n\n} );\n"
  },
  {
    "path": "test/unit/add-remove-cells.js",
    "content": "QUnit.test( 'add/remove cells', function( assert ) {\n\n  function makeCellElem() {\n    let cellElem = document.createElement('div');\n    cellElem.className = 'cell';\n    return cellElem;\n  }\n\n  // position values can be off by 0.1% or 1px\n  function isPositionApprox( value, expected ) {\n    value = value.replace( 'translateX(', '' ).replace( ')', '' );\n    let isPercent = value.indexOf('%') !== -1;\n    value = parseFloat( value );\n    let diff = Math.abs( expected - value );\n    return isPercent ? diff < 0.1 : diff <= 1;\n  }\n\n  let elem = document.querySelector('#add-remove-cells');\n  let flkty = new Flickity( elem );\n  let sliderElem = elem.querySelector('.flickity-slider');\n\n  function checkCellElem( cellElem, index, message ) {\n    assert.equal( sliderElem.children[ index ], cellElem,\n        message + ' cell element in DOM correct' );\n    assert.equal( flkty.cells[ index ].element, cellElem,\n        message + ' element added as cell' );\n    assert.ok( isPositionApprox( cellElem.style.transform, index * 100 ),\n        ` element positioned ${index * 100}` );\n  }\n\n  // prepend cell element\n  let cellElem = makeCellElem();\n  flkty.prepend( cellElem );\n  checkCellElem( cellElem, 0, 'prepended' );\n  assert.equal( flkty.selectedIndex, 1, 'selectedIndex +1 after prepend' );\n  // append cell element\n  cellElem = makeCellElem();\n  flkty.append( cellElem );\n  let lastIndex = flkty.cells.length - 1;\n  checkCellElem( cellElem, lastIndex, 'appended' );\n  assert.equal( flkty.selectedIndex, 1, 'selectedIndex same after prepend' );\n  // insert single cell element\n  cellElem = makeCellElem(); // this one gets removed first\n  flkty.select( 2 );\n  flkty.insert( cellElem, 2 );\n  checkCellElem( cellElem, 2, 'single inserted' );\n  assert.equal( flkty.selectedIndex, 3, 'selectedIndex +1 after insert before' );\n  flkty.insert( makeCellElem(), 4 );\n  assert.equal( flkty.selectedIndex, 3, 'selectedIndex same after insert before' );\n  // insert multiple cell elements\n  let cellElems = [ makeCellElem(), makeCellElem(), makeCellElem() ];\n  flkty.insert( cellElems, 3 );\n  checkCellElem( cellElems[0], 3, 'first multiple inserted' );\n  checkCellElem( cellElems[1], 4, 'second multiple inserted' );\n  checkCellElem( cellElems[2], 5, 'third multiple inserted' );\n  assert.equal( flkty.selectedIndex, 6, 'selectedIndex +6 after 3 insert before' );\n\n  function checkCellPositions() {\n    let isGap = false;\n    flkty.cells.forEach( ( cell, i ) => {\n      if ( !isPositionApprox( cell.element.style.transform, i * 100 ) ) {\n        assert.ok( false, `gap in cell position ${i} after removal` );\n        isGap = true;\n      }\n    } );\n    assert.ok( !isGap, 'no gaps in cell positions' );\n  }\n\n  // remove single cell element that was inserted\n  let len = flkty.cells.length;\n  flkty.remove( cellElem );\n  assert.equal( len - sliderElem.children.length, 1, 'element removed from DOM' );\n  assert.equal( len - flkty.cells.length, 1, 'cell removed' );\n  assert.equal( flkty.selectedIndex, 5, 'selectedIndex -1 after remove before' );\n  checkCellPositions();\n  // remove multiple\n  len = flkty.cells.length;\n  flkty.select( 4 );\n  flkty.remove([ cellElems[2], cellElems[0], cellElems[1] ]);\n  assert.equal( len - sliderElem.children.length, 3, 'elements removed from DOM' );\n  assert.equal( len - flkty.cells.length, 3, 'cells removed' );\n  checkCellPositions();\n\n  // remove all cells\n  flkty.remove( flkty.getCellElements() );\n  assert.equal( flkty.cells.length, 0, 'all cells removed' );\n  flkty.resize();\n  assert.ok( true, 'resize with zero items didnt freak out' );\n\n} );\n"
  },
  {
    "path": "test/unit/auto-play.js",
    "content": "QUnit.test( 'auto play', function( assert ) {\n\n  let done = assert.async();\n\n  let flkty = new Flickity( '#auto-play', {\n    autoPlay: 200,\n  } );\n\n  let selectCount = 0;\n  let testDelay = flkty.options.autoPlay + 100;\n\n  let tests;\n\n  function nextTest() {\n    if ( tests.length ) {\n      let next = tests.shift();\n      return next();\n    } else {\n      flkty.stopPlayer();\n      done();\n    }\n  }\n\n  tests = [\n    // check that player runs\n    function() {\n      flkty.on( 'select', function onSelect() {\n        selectCount++;\n        if ( selectCount < 5 ) {\n          assert.equal( flkty.selectedIndex, selectCount % flkty.cells.length,\n              `auto-played to ${flkty.selectedIndex}` );\n        } else if ( selectCount === 5 ) {\n          // HACK do async, should be able to stop after a tick\n          flkty.off( 'select', onSelect );\n          nextTest();\n        }\n      } );\n    },\n    // pause & unpause\n    function() {\n      function onPauseSelect() {\n        assert.ok( false, 'player ticked during pause' );\n      }\n      flkty.on( 'select', onPauseSelect );\n      flkty.pausePlayer();\n      setTimeout( function() {\n        assert.ok( true, 'player did not tick during pause' );\n        flkty.off( 'select', onPauseSelect );\n        flkty.once( 'select', function() {\n          assert.ok( true, 'player resumed after unpausing' );\n          nextTest();\n        } );\n        flkty.unpausePlayer();\n      }, testDelay );\n    },\n    // stopPlayer\n    function() {\n      let ticks = 0;\n      function onSelect() {\n        ticks++;\n      }\n      flkty.stopPlayer();\n      setTimeout( function() {\n        flkty.off( 'select', onSelect );\n        assert.equal( ticks, 0, 'no ticks after stopped' );\n        nextTest();\n      }, testDelay * 2 );\n    },\n    // double playPlayer()\n    function() {\n      let ticks = 0;\n      function onSelect() {\n        ticks++;\n      }\n      flkty.stopPlayer();\n      flkty.on( 'select', onSelect );\n      flkty.playPlayer();\n      flkty.playPlayer();\n      setTimeout( function() {\n        flkty.off( 'select', onSelect );\n        assert.equal( ticks, 1, 'only one tick after double playPlayer' );\n        nextTest();\n      }, testDelay );\n    },\n  ];\n\n  nextTest();\n\n} );\n"
  },
  {
    "path": "test/unit/cell-selector.js",
    "content": "QUnit.test( 'cellSelector', function( assert ) {\n\n  let elem = document.querySelector('#cell-selector');\n  let notCell1 = elem.querySelector('.not-cell1');\n  let notCell2 = elem.querySelector('.not-cell2');\n\n  let flkty = new Flickity( elem, {\n    cellSelector: '.cell',\n  } );\n\n  let cellsMatchSelector = true;\n  for ( let cell of flkty.cells ) {\n    let isMatch = cell.element.matches( flkty.options.cellSelector );\n    cellsMatchSelector = cellsMatchSelector && isMatch;\n  }\n\n  // getCellElements()\n  let cellElems = flkty.getCellElements();\n  let queriedCellElems = elem.querySelectorAll( flkty.options.cellSelector );\n  cellElems.forEach( ( cellElem, i ) => {\n    assert.equal( cellElem, queriedCellElems[i],\n        'cell element same as queried cell element' );\n  } );\n\n  assert.ok( cellsMatchSelector, 'all cell elements match cellSelector' );\n\n  assert.equal( notCell1.parentNode, elem, 'notCell1 parent node is still gallery' );\n  assert.equal( notCell2.parentNode, elem, 'notCell2 parent node is still gallery' );\n\n} );\n"
  },
  {
    "path": "test/unit/change.js",
    "content": "/* eslint-disable no-invalid-this */\n\nQUnit.test( 'change', function( assert ) {\n\n  let done = assert.async();\n\n  function onInitChange() {\n    assert.ok( false, 'change should not trigger on init' );\n  }\n\n  new Flickity( '#change', {\n    on: {\n      change: onInitChange,\n      ready: function() {\n        // define events last to first for strict\n        function onChangeC( index ) {\n          assert.equal( index, 0, 'change triggered on select back to 0' );\n          done();\n        }\n\n        function onChangeB() {\n          assert.ok( false, 'change should not trigger on same select' );\n        }\n\n        function onSelectB( index ) {\n          assert.equal( index, 1, 'select triggered on same select 1' );\n          this.off( 'change', onChangeB );\n          this.once( 'change', onChangeC );\n          this.select( 0, false, true );\n        }\n\n        function onChangeA( index ) {\n          assert.equal( index, 1, 'change triggered, selected 1' );\n          this.once( 'change', onChangeB );\n          this.once( 'select', onSelectB );\n          // select 1 again\n          this.select( 1, false, true );\n        }\n\n        // kick off\n        this.off( 'change', onInitChange );\n        this.once( 'change', onChangeA );\n        this.select( 1, false, true );\n      },\n    },\n  } );\n\n} );\n"
  },
  {
    "path": "test/unit/contain.js",
    "content": "QUnit.test( 'contain', function( assert ) {\n\n  let flkty = new Flickity( '#contain', {\n    contain: true,\n  } );\n\n  assert.equal( Math.round( flkty.x + flkty.cursorPosition ), 0,\n      'selected at 0, position left edge' );\n  flkty.select( 1 );\n  flkty.positionSliderAtSelected();\n  assert.equal( Math.round( flkty.x + flkty.cursorPosition ), 0,\n      'selected at 1, position left edge' );\n  flkty.select( 4 );\n  flkty.positionSliderAtSelected();\n  let endLimit = flkty.slideableWidth - flkty.size.innerWidth * ( 1 - flkty.cellAlign );\n  assert.equal( Math.round( -endLimit ), Math.round( flkty.x ),\n      'selected at 4, position right edge' );\n  flkty.select( 5 );\n  flkty.positionSliderAtSelected();\n  assert.equal( Math.round( -endLimit ), Math.round( flkty.x ),\n      'selected at 5, position right edge' );\n\n} );\n"
  },
  {
    "path": "test/unit/destroy.js",
    "content": "QUnit.test( 'destroy', function( assert ) {\n\n  let elem = document.querySelector('#destroy');\n  let flkty = new Flickity( elem );\n\n  let done = assert.async();\n  // do it async\n  setTimeout( function() {\n    flkty.destroy();\n    assert.strictEqual( elem.flickityGUID, undefined, 'flickityGUID removed' );\n    assert.ok( !flkty.isActive, 'not active' );\n    assert.ok( !Flickity.data( elem ), '.data() returns falsey' );\n    assert.ok( elem.children[0], '.cell', 'cell is back as first child' );\n    assert.ok( !elem.matches('.flickity-enabled'), 'flickity-enabled class removed' );\n    assert.ok( !elem.querySelector('.flickity-prev-next-button'), 'no buttons' );\n    assert.ok( !elem.querySelector('.flickity-page-dots'), 'no page dots' );\n    assert.ok( !elem.style.height, 'no height set' );\n    assert.ok( !elem.children[0].style.left, 'first cell has no left position' );\n\n    done();\n  }, 20 );\n\n} );\n"
  },
  {
    "path": "test/unit/drag.js",
    "content": "( function() {\n\nfunction noop() {}\n\nlet fakeDrag = window.fakeDrag = function( flkty, positions ) {\n\n  function fakeEvent( type, pageX ) {\n    return {\n      type: type,\n      pageX: pageX,\n      pageY: 0,\n      preventDefault: noop,\n      target: flkty.viewport,\n    };\n  }\n\n  let hasBeenDown = false;\n\n  function triggerEvent() {\n    let position = positions.shift();\n    // down or move event\n    if ( !hasBeenDown ) {\n      let downEvent = fakeEvent( 'mousedown', position );\n      flkty.pointerDown( downEvent, downEvent );\n      hasBeenDown = true;\n    } else {\n      let moveEvent = fakeEvent( 'mousemove', position );\n      flkty.pointerMove( moveEvent, moveEvent );\n    }\n\n    if ( positions.length ) {\n      // loop next\n      setTimeout( triggerEvent, 40 );\n    } else {\n      // up event\n      let upEvent = fakeEvent( 'mouseup', position );\n      flkty.pointerUp( upEvent, upEvent );\n    }\n  }\n\n  triggerEvent();\n};\n\nlet dragTests;\n// do each drag test one after another\nfunction getDoNextDragTest( done ) {\n  return function doNextDragTest() {\n    if ( dragTests.length ) {\n      let dragTest = dragTests.shift();\n      dragTest();\n    } else {\n      done();\n    }\n  };\n}\n\n// flickity, dragPositions, index, onSettle, message\nfunction getFakeDragTest( args ) {\n  let assert = args.assert;\n  let flkty = args.flickity;\n  let msgCell = `'slide[${args.index}]'`;\n\n  return function fakeDragTest() {\n    let selectMsg = `${args.message ? args.message + '. ' : ''} selected ${msgCell}`;\n    flkty.once( 'select', function() {\n      assert.equal( flkty.selectedIndex, args.index, selectMsg );\n    } );\n\n    let settleMsg = `${args.message ? args.message + '. ' : ''} settled ${msgCell}`;\n    let target = flkty.slides[ args.index ].target;\n    flkty.once( 'settle', function() {\n      assert.equal( Math.round( -flkty.x ), Math.round( target ), settleMsg );\n      setTimeout( args.onSettle );\n    } );\n\n    fakeDrag( args.flickity, args.dragPositions );\n  };\n}\n\nQUnit.test( 'drag', function( assert ) {\n  // async test\n  let done = assert.async();\n\n  let flkty = new Flickity('#drag');\n\n  let doNextDragTest = getDoNextDragTest( done );\n\n  function getDragTest( args ) {\n    args = Object.assign( args, {\n      assert: assert,\n      flickity: flkty,\n      onSettle: doNextDragTest,\n    } );\n    return getFakeDragTest( args );\n  }\n\n  dragTests = [\n    getDragTest({\n      message: 'drag to 2nd cell',\n      index: 1,\n      dragPositions: [ 0, -10, -20 ],\n    }),\n    getDragTest({\n      message: 'drag back to 1st cell',\n      index: 0,\n      dragPositions: [ 0, 10, 20 ],\n    }),\n    getDragTest({\n      message: 'big flick to 3rd cell',\n      index: 2,\n      dragPositions: [ 0, -10, -80 ],\n    }),\n    // minimal movement to trigger static click\n    function() {\n      flkty.once( 'staticClick', function() {\n        assert.ok( true, 'staticClick fired on non-drag' );\n        assert.equal( flkty.selectedIndex, 2, 'selected index still at 2 after click' );\n        setTimeout( doNextDragTest );\n      } );\n      fakeDrag( flkty, [ 0, 1, 0, -2, -1 ] );\n    },\n    // move out then back to where it started\n    function() {\n      flkty.once( 'settle', function() {\n        assert.equal( flkty.selectedIndex, 2, 'move out then back. same cell' );\n        setTimeout( doNextDragTest );\n      } );\n      fakeDrag( flkty, [ 0, 10, 20, 30, 20 ] );\n    },\n    getDragTest({\n      message: 'drag and try to flick past 6th cell',\n      index: 5,\n      dragPositions: [ 0, -10, -50, -77, -100, -125, -150, -175, -250, -350 ],\n    }),\n  ];\n\n  doNextDragTest();\n\n} );\n\nQUnit.test( 'drag with wrapAround', function( assert ) {\n  // async test\n  let done = assert.async();\n\n  let flkty = new Flickity( '#drag-wrap-around', {\n    wrapAround: true,\n  } );\n\n  let doNextDragTest = getDoNextDragTest( done );\n\n  function getDragTest( args ) {\n    args = Object.assign( args, {\n      assert: assert,\n      flickity: flkty,\n      onSettle: doNextDragTest,\n    } );\n    return getFakeDragTest( args );\n  }\n\n  dragTests = [\n    getDragTest({\n      message: 'drag to last cell via wrap-around',\n      index: 5,\n      dragPositions: [ 0, 10, 20 ],\n    }),\n    getDragTest({\n      message: 'drag to first cell via wrap-around',\n      index: 0,\n      dragPositions: [ 0, -10, -20 ],\n    }),\n    getDragTest({\n      message: 'big flick to 5th cell via wrap-around',\n      index: 4,\n      dragPositions: [ 0, 10, 80 ],\n    }),\n  ];\n\n  doNextDragTest();\n\n} );\n\n} )();\n"
  },
  {
    "path": "test/unit/empty.js",
    "content": "QUnit.test( 'empty', function( assert ) {\n\n  let gallery = document.querySelector('#empty');\n\n  let flkty = new Flickity( gallery );\n\n  assert.ok( true, 'empty gallery ok' );\n  assert.ok( flkty.prevButton.element.disabled, 'previous button disabled' );\n  assert.ok( flkty.nextButton.element.disabled, 'next button disabled' );\n  assert.equal( flkty.pageDots.dots.length, 0, '0 page dots' );\n\n  flkty.resize();\n  assert.ok( true, 'resize with empty gallery ok' );\n\n  function makeCellElem() {\n    let cellElem = document.createElement('div');\n    cellElem.className = 'cell';\n    return cellElem;\n  }\n\n  flkty.append( makeCellElem() );\n  assert.equal( flkty.cells.length, 1, 'added cell to empty gallery' );\n\n  assert.ok( flkty.prevButton.element.disabled, 'previous button disabled' );\n  assert.ok( flkty.nextButton.element.disabled, 'next button disabled' );\n  assert.equal( flkty.pageDots.dots.length, 1, '1 page dots' );\n\n  // destroy and re-init with higher initialIndex\n  flkty.destroy();\n  flkty = new Flickity( gallery, {\n    initialIndex: 2,\n  } );\n\n  // #291\n  assert.ok( true, 'initializing with initialIndex > cells doesnt throw error' );\n\n} );\n"
  },
  {
    "path": "test/unit/get-parent-cell.js",
    "content": "QUnit.test( 'getParentCell', function( assert ) {\n\n  let gallery = document.querySelector('#get-parent-cell');\n  let flkty = new Flickity( gallery );\n\n  // cell1\n  let cell = flkty.getParentCell( gallery.querySelector('.cell1') );\n  assert.ok( cell, 'getParentCell( cell ) ok' );\n  assert.ok( cell instanceof Flickity.Cell, 'cell is Flickity.Cell' );\n  let index = flkty.cells.indexOf( cell );\n  assert.equal( index, 0, 'cell is index 0' );\n  // cell3\n  cell = flkty.getParentCell( gallery.querySelector('.cell3') );\n  assert.ok( cell, 'getParentCell( cell ) ok' );\n  assert.ok( cell instanceof Flickity.Cell, 'cell is Flickity.Cell' );\n  index = flkty.cells.indexOf( cell );\n  assert.equal( index, 2, 'cell is index 2' );\n  // child1\n  cell = flkty.getParentCell( gallery.querySelector('.child1') );\n  assert.ok( cell, 'getParentCell( cell ) ok' );\n  assert.ok( cell instanceof Flickity.Cell, 'cell is Flickity.Cell' );\n  index = flkty.cells.indexOf( cell );\n  assert.equal( index, 0, 'cell is index 0' );\n  // child2\n  cell = flkty.getParentCell( gallery.querySelector('.child2') );\n  assert.ok( cell, 'getParentCell( cell ) ok' );\n  assert.ok( cell instanceof Flickity.Cell, 'cell is Flickity.Cell' );\n  index = flkty.cells.indexOf( cell );\n  assert.equal( index, 1, 'cell is index 1' );\n  // outside\n  cell = flkty.getParentCell( document.querySelector('.outside') );\n  assert.ok( !cell, 'getParentCell( notCell ) not ok' );\n  index = flkty.cells.indexOf( cell );\n  assert.equal( index, -1, 'not cell is index -1' );\n\n} );\n"
  },
  {
    "path": "test/unit/get-wrap-cells.js",
    "content": "QUnit.test( 'getWrapCells', function( assert ) {\n\n  let flkty = new Flickity( '#get-wrap-cells', {\n    wrapAround: true,\n  } );\n  // cells are 25% width\n  // center align, 2 cells on each side\n  assert.equal( flkty.beforeShiftCells.length, 2, 'center align, 2 before shift cells' );\n  assert.equal( flkty.afterShiftCells.length, 2, 'center align, 2 after shift cells' );\n\n  flkty.options.cellAlign = 'left';\n  flkty.resize();\n  // left align, 0, 4\n  assert.equal( flkty.beforeShiftCells.length, 0, 'left align, 1 before shift cells' );\n  assert.equal( flkty.afterShiftCells.length, 4, 'left align, 4 after shift cells' );\n\n  flkty.options.cellAlign = 'right';\n  flkty.resize();\n  // right align, 4, 0\n  assert.equal( flkty.beforeShiftCells.length, 4, 'right align, 4 before shift cells' );\n  assert.equal( flkty.afterShiftCells.length, 0, 'right align, 0 after shift cells' );\n\n} );\n"
  },
  {
    "path": "test/unit/group-cells.js",
    "content": "QUnit.test( 'groupCells', function( assert ) {\n\n  let done = assert.async();\n\n  let flkty = new Flickity( '#group-cells', {\n    groupCells: true,\n  } );\n\n  function getSlideCellsCount() {\n    let counts = flkty.slides.map( function( slide ) {\n      return slide.cells.length;\n    } );\n    return counts.join(',');\n  }\n\n  assert.equal( getSlideCellsCount(), '3,2,2,1,1,3,2', 'groupCells: true' );\n  let targets = flkty.slides.map( function( slide ) {\n    return slide.target;\n  } );\n  assert.deepEqual( targets, [ 200, 600, 1000, 1300, 1600, 2000, 2300 ], 'targets' );\n\n  flkty.selectCell( 6 );\n  assert.equal( flkty.selectedIndex, 2, 'selectCell(6) selects 3rd slide' );\n  flkty.selectCell( flkty.cells[2].element );\n  assert.equal( flkty.selectedIndex, 0, 'selectCell(3rd elem) selects 1st slide' );\n\n  flkty.options.groupCells = 2;\n  flkty.reposition();\n  assert.equal( getSlideCellsCount(), '2,2,2,2,2,2,2', 'groupCells: 2' );\n\n  flkty.options.groupCells = '75%';\n  flkty.reposition();\n  assert.equal( getSlideCellsCount(), '2,1,1,2,1,1,1,2,2,1', 'groupCells: 75%' );\n\n  flkty.once( 'settle', function() {\n    flkty.element.classList.add('is-expanded'); // 600px wide\n    flkty.options.groupCells = true;\n    flkty.resize();\n    assert.equal( getSlideCellsCount(), '3,3,2,3,3',\n        'groupCells: true, container @ 600px' );\n    done();\n  } );\n\n} );\n"
  },
  {
    "path": "test/unit/imagesloaded.js",
    "content": "/* globals imagesLoaded */\n\n( function() {\n\n  // position values can be off by 0.1% or 1px\n  function isPositionApprox( value, expected ) {\n    let isPercent = value.indexOf('%') !== -1;\n    value = parseFloat( value );\n    let diff = Math.abs( expected - value );\n    return isPercent ? diff < 0.1 : diff <= 1;\n  }\n\n  QUnit.test( 'imagesloaded', function( assert ) {\n    let done = assert.async();\n    let gallery = document.querySelector('#imagesloaded');\n\n    let flkty = new Flickity( gallery, {\n      imagesLoaded: true,\n      percentPosition: false,\n    } );\n\n    imagesLoaded( gallery, function() {\n      flkty.cells.forEach( ( cell, i ) => {\n        assert.ok( cell.size.width > 10, `cell ${i} has width` );\n        let transform = cell.element.style.transform;\n        let position = transform.replace( 'translateX(', '' ).replace( ')', '' );\n        let isApprox = isPositionApprox( position, cell.x );\n        assert.ok( isApprox, `cell ${i} at proper position` );\n      } );\n\n      assert.equal( flkty.viewport.style.height, '140px', 'gallery height set' );\n\n      done();\n    } );\n\n  } );\n\n  QUnit.test( 'imagesloaded-in-divs', function( assert ) {\n\n    let done = assert.async();\n    let gallery = document.querySelector('#imagesloaded-in-divs');\n\n    let flkty = new Flickity( gallery, {\n      imagesLoaded: true,\n      percentPosition: false,\n    } );\n\n    imagesLoaded( gallery, function() {\n      flkty.cells.forEach( ( cell, i ) => {\n        assert.ok( cell.size.width > 10, `cell ${i} has width` );\n        let transform = cell.element.style.transform;\n        let position = transform.replace( 'translateX(', '' ).replace( ')', '' );\n        let isApprox = isPositionApprox( position, cell.x );\n        assert.ok( isApprox, `cell ${i} at proper position` );\n      } );\n\n      assert.equal( flkty.viewport.style.height, '140px', 'gallery height set' );\n\n      done();\n    } );\n\n  } );\n\n} )();\n\n"
  },
  {
    "path": "test/unit/init.js",
    "content": "( function() {\n\nQUnit.module('Flickity');\n\nlet utils = window.fizzyUIUtils;\n\nQUnit.test( 'init', function( assert ) {\n\n  let elem = document.querySelector('#init');\n  let flkty = new Flickity( elem );\n\n  for ( let prop in Flickity.defaults ) {\n    assert.equal( flkty.options[ prop ], Flickity.defaults[ prop ],\n        `${prop} option matches default` );\n  }\n\n  assert.equal( flkty.element, elem, '.element is proper element' );\n  let children = utils.makeArray( flkty.element.children );\n  assert.notEqual( children.indexOf( flkty.viewport ), -1,\n      'viewport element is a child element' );\n  assert.equal( flkty.viewport.children[0], flkty.slider, 'slider is in viewport' );\n  assert.equal( flkty.viewport.style.height, '100px', 'viewport height set' );\n\n  assert.ok( flkty.isActive, 'isActive' );\n  assert.ok( elem.matches('.flickity-enabled'), 'flickity-enabled class added' );\n\n  assert.equal( flkty.cells.length, 6, 'has 6 cells' );\n  assert.equal( getComputedStyle( flkty.cells[0].element ).left, '0px',\n      'first cell left: 0px' );\n  assert.equal( flkty.cells[0].element.style.transform,\n      'translateX(0%)', 'first cell translateX: 0%' );\n  assert.equal( flkty.cells[5].element.style.transform,\n      'translateX(500%)', '6th cell translateX: 500%' );\n\n  assert.equal( flkty.selectedIndex, 0, 'selectedIndex = 0' );\n  assert.equal( flkty.cursorPosition, 200, 'cursorPosition = 200' );\n  assert.equal( flkty.x + flkty.cursorPosition, 0, 'x + cursorPosition = 0' );\n\n} );\n\n} )();\n"
  },
  {
    "path": "test/unit/initial-index.js",
    "content": "QUnit.test( 'initialIndex', function( assert ) {\n  // initialIndex number\n  let flkty = new Flickity( '#initial-index', {\n    initialIndex: 3,\n  } );\n  assert.equal( flkty.selectedIndex, 3, 'initialIndex number' );\n  // selectedIndex remains same after reactivation\n  flkty.deactivate();\n  flkty.activate();\n  assert.equal( flkty.selectedIndex, 3, 'reactivated selectedIndex stays the same' );\n  flkty.destroy();\n  // initialIndex selector string\n  flkty = new Flickity( '#initial-index', {\n    initialIndex: '.cell--initial',\n  } );\n  assert.equal( flkty.selectedIndex, 4, 'initialIndex selector string' );\n  flkty.destroy();\n  // initialIndex selector string with groupCells #881\n  flkty = new Flickity( '#initial-index', {\n    groupCells: 3,\n    initialIndex: '.cell--initial',\n  } );\n  assert.equal( flkty.selectedIndex, 1, 'initialIndex selector string with groupCells' );\n\n} );\n"
  },
  {
    "path": "test/unit/lazyload-srcset.js",
    "content": "QUnit.test( 'lazyload srcset', function( assert ) {\n\n  let done = assert.async();\n\n  let gallery = document.querySelector('#lazyload-srcset');\n  let flkty = new Flickity( gallery, {\n    lazyLoad: 1,\n  } );\n\n  let loadCount = 0;\n  flkty.on( 'lazyLoad', function( event, cellElem ) {\n    loadCount++;\n\n    assert.equal( event.type, 'load', 'event.type == load' );\n    assert.ok( event.target.complete, `img ${loadCount} is complete` );\n    assert.ok( cellElem, 'cellElement argument there' );\n    let srcset = event.target.getAttribute('srcset');\n    assert.ok( srcset, 'srcset attribute set' );\n    let lazyAttr = event.target.getAttribute('data-flickity-lazyload-srcset');\n    assert.ok( !lazyAttr, 'data-flickity-lazyload attribute removed' );\n\n    // after first 2 have loaded, select 7th cell\n    if ( loadCount === 2 ) {\n      done();\n    }\n  } );\n\n} );\n"
  },
  {
    "path": "test/unit/lazyload.js",
    "content": "QUnit.test( 'lazyload', function( assert ) {\n\n  let done = assert.async();\n\n  let gallery = document.querySelector('#lazyload');\n  let flkty = new Flickity( gallery, {\n    lazyLoad: 1,\n  } );\n\n  let loadCount = 0;\n  flkty.on( 'lazyLoad', function( event, cellElem ) {\n    loadCount++;\n\n    assert.equal( event.type, 'load', 'event.type == load' );\n    assert.ok( event.target.complete, `img ${loadCount} is complete` );\n    assert.ok( cellElem, 'cellElement argument there' );\n    let lazyAttr = event.target.getAttribute('data-flickity-lazyload');\n    assert.ok( !lazyAttr, 'data-flickity-lazyload attribute removed' );\n\n    // after first 2 have loaded, select 7th cell\n    if ( loadCount === 2 ) {\n      flkty.select( 6 );\n    }\n    if ( loadCount === 5 ) {\n      let loadedImgs = gallery.querySelectorAll('.flickity-lazyloaded');\n      assert.equal( loadedImgs.length, '5', 'only 5 images loaded' );\n      done();\n    }\n  } );\n\n} );\n"
  },
  {
    "path": "test/unit/page-dots.js",
    "content": "QUnit.test( 'pageDots', function( assert ) {\n\n  let elem = document.querySelector('#page-dots');\n  let flkty = new Flickity( elem );\n\n  let dotsHolder = elem.querySelector('.flickity-page-dots');\n  let dotsElems = [ ...dotsHolder.querySelectorAll('.flickity-page-dot') ];\n\n  assert.ok( dotsHolder, 'dots holder in DOM' );\n  assert.equal( flkty.pageDots.holder, dotsHolder,\n      'dots holder element matches flkty.pageDots.holder' );\n  assert.equal( dotsElems.length, flkty.cells.length,\n      'number of dots matches number of cells' );\n\n  function getSelectedDotIndex() {\n    return dotsElems.indexOf( dotsHolder.querySelector('.is-selected') );\n  }\n\n  assert.equal( getSelectedDotIndex(), 0, 'first dot is selected' );\n  flkty.select( 2 );\n  assert.equal( getSelectedDotIndex(), 2, '3rd dot is selected' );\n\n  // fake click\n  flkty.onPageDotsClick({ target: dotsElems[4] });\n  assert.equal( flkty.selectedIndex, 4, 'tap dot selects cell' );\n\n} );\n"
  },
  {
    "path": "test/unit/position-cells.js",
    "content": "( function() {\n\n// position values can be off by 0.1% or 1px\nfunction isPositionApprox( value, expected ) {\n  let isPercent = value.indexOf('%') !== -1;\n  value = parseFloat( value );\n  let diff = Math.abs( expected - value );\n  return isPercent ? diff < 0.1 : diff <= 1;\n}\n\n// loop through cells and check position values against expecteds\nfunction checkCellPositions( flkty, expecteds ) {\n  let isOK;\n  for ( let i = 0; i < expecteds.length; i++ ) {\n    let expected = expecteds[i];\n    let cell = flkty.cells[i];\n    let transform = cell.element.style.transform;\n    let position = transform.replace( 'translateX(', '' ).replace( ')', '' );\n    isOK = isPositionApprox( position, expected );\n    if ( !isOK ) {\n      console.error(`wrong cell position, index: ${i}.\n        expected: ${expected}. position: ${position}`);\n      break;\n    }\n  }\n  return isOK;\n}\n\nQUnit.test( 'position cells', function( assert ) {\n\n  let flkty = new Flickity('#position-cells');\n\n  assert.ok( checkCellPositions( flkty, [ 0, 160, 108.3, 312.5, 275, 900 ] ),\n      'percent cell position' );\n  // .cell { margin: 0 2%; }\n  flkty.element.classList.add('percent-margin');\n  flkty.positionCells();\n  assert.ok( checkCellPositions( flkty, [ 0, 176, 121.67, 342.5, 301.67, 980 ] ),\n      'percent cell position with margin' );\n  flkty.element.classList.remove('percent-margin');\n  // pixel-based position\n  flkty.options.percentPosition = false;\n  flkty.positionCells();\n  assert.ok( checkCellPositions( flkty, [ 0, 160, 260, 500, 660, 900 ] ),\n      'pixel cell position' );\n  // pixel margin, { margin: 0 10px; }\n  flkty.element.classList.add('pixel-margin');\n  flkty.positionCells();\n  assert.ok( checkCellPositions( flkty, [ 0, 180, 300, 560, 740, 1000 ] ),\n      'pixel cell position with margin' );\n\n} );\n\n} )();\n"
  },
  {
    "path": "test/unit/prev-next-buttons.js",
    "content": "QUnit.test( 'prev-next-buttons', function( assert ) {\n\n  let elem = document.querySelector('#prev-next-buttons');\n  let flkty = new Flickity( elem );\n\n  let prevElem = elem.querySelector('.flickity-prev-next-button.previous');\n  let nextElem = elem.querySelector('.flickity-prev-next-button.next');\n  assert.ok( prevElem, 'previous button in DOM' );\n  assert.ok( nextElem, 'next button in DOM' );\n  assert.equal( flkty.prevButton.element, prevElem,\n      'previous button element matches prevButton.element' );\n  assert.equal( flkty.nextButton.element, nextElem,\n      'next button element matches nextButton.element' );\n  assert.ok( prevElem.disabled, 'previous button is disabled at first index' );\n\n  prevElem.focus();\n  prevElem.click();\n  assert.equal( flkty.selectedIndex, 0, 'selectedIndex still at 0' );\n  nextElem.focus();\n  nextElem.click();\n  assert.equal( flkty.selectedIndex, 1, 'next button clicked, selectedIndex at 1' );\n  prevElem.focus();\n  prevElem.click();\n  assert.equal( flkty.selectedIndex, 0,\n      'previous button clicked, selectedIndex back at 0' );\n  flkty.select( 5 );\n  assert.ok( nextElem.disabled, 'next button disabled when at last cell' );\n\n} );\n"
  },
  {
    "path": "test/unit/resize.js",
    "content": "QUnit.test( 'resize', function( assert ) {\n\n  let elem = document.querySelector('#resize');\n  let flkty = new Flickity( elem, {\n    initialIndex: 2,\n  } );\n  elem.style.width = '500px';\n  flkty.resize();\n\n  assert.equal( flkty.selectedIndex, 2, 'selectedIndex = 2' );\n  assert.equal( flkty.cursorPosition, 250, 'cursorPosition = 250' );\n  assert.equal( flkty.x + flkty.cursorPosition, -1000, 'x + cursorPosition = -1000' );\n\n} );\n"
  },
  {
    "path": "test/unit/select-cell.js",
    "content": "QUnit.test( 'selectCell', function( assert ) {\n\n  let gallery = document.querySelector('#select-cell');\n  let cellElems = gallery.querySelectorAll('.cell');\n  let flkty = new Flickity( gallery, {\n    groupCells: true, // groups of 3\n  } );\n\n  flkty.selectCell( 3 );\n  assert.equal( flkty.selectedIndex, 1, 'selectCell number' );\n  flkty.selectCell( cellElems[1] );\n  assert.equal( flkty.selectedIndex, 0, 'selectCell element' );\n  flkty.selectCell('.select-cell__6');\n  assert.equal( flkty.selectedIndex, 2, 'selectCell selector string' );\n  flkty.selectCell('none');\n  assert.equal( flkty.selectedIndex, 2, 'selectCell bad string is okay' );\n} );\n"
  },
  {
    "path": "test/unit/watch.js",
    "content": "QUnit.test( 'watch fallback', function( assert ) {\n\n  let elem = document.querySelector('#watch');\n  let flkty = new Flickity( elem, {\n    watchCSS: true,\n  } );\n\n  assert.ok( !flkty.isActive, 'fallback not active, watchCSS: true' );\n} );\n"
  },
  {
    "path": "test/unit/wrap-around-fill.js",
    "content": "QUnit.test( 'wrapAround: \"fill\"', function( assert ) {\n\n  let elem = document.querySelector('#wrap-around-fill');\n  let flkty = new Flickity( elem, {\n    wrapAround: 'fill',\n  } );\n\n  assert.ok( !flkty.isWrapping, 'total cell width not big enough, not wrapping' );\n\n  let shortCell = elem.querySelector('.cell--wrap-around-short');\n  shortCell.classList.remove('cell--wrap-around-short');\n  flkty.resize();\n  assert.ok( flkty.isWrapping, 'cell width big enough, wrapping' );\n\n} );\n"
  }
]