[
  {
    "path": ".babelrc",
    "content": "{\n    \"retainLines\": true,\n    \"presets\": [\n        [\"@babel/preset-env\", {\n            \"exclude\": [\"transform-typeof-symbol\"],\n            \"modules\": false\n        }]\n    ],\n    \"plugins\": [\n        [\"@babel/plugin-proposal-object-rest-spread\", {\n            \"loose\": true, \n            \"useBuiltIns\": true\n        }],\n        [\"@babel/plugin-transform-template-literals\", {\n            \"loose\": true\n        }]\n    ],\n    \"env\": {\n        \"test\": {\n            \"presets\": [\n                [\"@babel/preset-env\", {\n                    \"targets\": {\n                        \"node\": \"current\"\n                    }\n                }]\n            ]\n        }\n    }\n}"
  },
  {
    "path": ".gitattributes",
    "content": "dist/* linguist-vendored=false\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: ['https://www.buymeacoffee.com/rikschennink']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug report\ntitle: \"[Bug] \"\ndescription: Report an issue with FilePond\nlabels: bug\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: checkboxes\n    attributes:\n      label: Is there an existing issue for this?\n      description: Please search to see if an issue already exists for the bug you encountered.\n      options:\n      - label: I have searched the existing issues\n        required: true\n  - type: checkboxes\n    attributes:\n      label: Have you updated FilePond and its plugins?\n      description: Please update both FilePond and its plugins to the most recent version.\n      options:\n      - label: I have updated FilePond and its plugins\n        required: true\n  - type: textarea\n    attributes:\n      label: Describe the bug\n      description: A concise description of what the bug is.\n      placeholder: Bug description\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Reproduction\n      description: Provide clear steps to reproduce the bug. Please take the time to create a reproduction of the bug by [forking this project on codesandbox.io](https://codesandbox.io/s/filepond-plain-javascript-24i1m)\n      placeholder: Reproduction\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Environment\n      description: |\n        examples:\n          - **Device**: Samsung Galaxy s20, iPhone 12 Mini, Macbook Pro (2020), etc.\n          - **OS**: Android 8, iOS 12, Windows 10, etc.\n          - **Browser**: Firefox 93, Chrome 94, etc.\n      value: |\n          - Device:\n          - OS:\n          - Browser:\n      render: markdown\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Stack Overflow\n    url: https://stackoverflow.com/questions/tagged/filepond\n    about: Ask questions on Stack Overflow and tag with \"filepond\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature request\ntitle: \"[Feature] \"\ndescription: Suggest an idea for this project\nlabels: new feature\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this feature request!\n  - type: checkboxes\n    attributes:\n      label: Is there an existing issue for this?\n      description: Please search to see if an issue already exists for the feature request you want to submit.\n      options:\n      - label: I have searched the existing issues\n        required: true\n  - type: textarea\n    attributes:\n      label: Is your feature request related to a problem? Please describe.\n      description: A clear and concise description of what the problem is you want to solve.\n      placeholder: I'm always frustrated when...\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe the solution you'd like\n      description: A clear and concise description of what you want to happen.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe alternatives you've considered\n      description: A clear and concise description of any alternative solutions or features you've considered.\n    validations:\n      required: true\n"
  },
  {
    "path": ".gitignore",
    "content": "npm-debug.log\nnode_modules/\ncoverage/\n.idea\n.vscode/\nupload/\ntest*.html\n_TODO.md\n_RELEASE.md"
  },
  {
    "path": ".nvmrc",
    "content": "v10.15.3"
  },
  {
    "path": ".prettierignore",
    "content": "dist/*"
  },
  {
    "path": ".prettierrc",
    "content": "{\n    \"svelteSortOrder\": \"scripts-markup-styles\",\n    \"trailingComma\": \"es5\",\n    \"tabWidth\": 4,\n    \"printWidth\": 100,\n    \"singleQuote\": true,\n    \"semi\": true\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 4.32.12\n\n-   Link attribution banner to [filepond.com](https://filepond.com)\n\n## 4.32.11\n\n-   Merge fix file processing aborted and moving to next file. #1065\n\n## 4.32.10\n\n-   Added various new locales.\n-   Merge fix for drop offset mismatch when scrolling.\n\n## 4.32.9\n\n-   Added various new locales.\n\n## 4.32.8\n\n-   Merged multiple PRs with various fixes.\n\n## 4.32.7\n\n-   Fix issue where `checkValidity` would not reset field validity status after removing an invalid file.\n\n## 4.32.6\n\n-   Fix `processfiles` event missing from types.`\n\n## 4.32.5\n\n-   Attempt to fix item dragging issue on Android.\n\n## 4.32.4\n\n-   Make credits link more visible to prevent authors from leaving it in place accidentally.\n\n## 4.32.3\n\n-   Add nofollow to credits link.\n\n## 4.32.2\n\n-   Fix accessibility issue with data fieldset missing a legend.\n\n## 4.32.1\n\n-   Fix types.\n\n## 4.32.0\n\n-   Add `onload` property to chunk patch request, receives `xhr` object, chunk index, and total chunks. #649\n-   Fix role attribute in voice over assistant to improve WCAG compatibility #988\n\n## 4.31.4\n\n-   Fix issue where images pasted in contenteditable elements would be handled by FilePond.\n\n## 4.31.3\n\n-   Fix issue where hidden input fields in `filepond--data` fieldset would stay disabled after enabling FilePond. #1001\n\n## 4.31.2\n\n-   Remove `aria-hidden` from drop label as suggested by Lighthouse.\n-   Fix `tabIndex` attribute on credits link not set correctly, now no longer included in tab flow.\n\n## 4.31.1\n\n-   Fix issue with dragging file items sometimes not working.\n\n## 4.31.0\n\n-   Add support for editing mock files if `item.source` is url.\n\n## 4.30.6\n\n-   Fix issue where using a number as source for a local file would throw a `url.split` error.\n\n## 4.30.5\n\n-   Fix file field value assignment #905\n\n## 4.30.4\n\n-   Fix a bug where the selected file is not replaced #841\n-   Fix a bug where the onwarning event is not triggered #839\n-   Add more translations\n\n## 4.30.3\n\n-   Fix accidental push.\n\n## 4.30.2\n\n-   Remove accidental log statement.\n\n## 4.30.1\n\n-   Prioritize server prop before other props when passed to setOptions #606\n\n## 4.30.0\n\n-   Add `labelFileSizeBytes`, `labelFileSizeKilobytes`, `labelFileSizeMegabytes`, `labelFileSizeGigabytes` #763\n\n## 4.29.1\n\n-   Revert chunked uploads #757\n\n## 4.29.0\n\n-   Enable rejecting images with an error message using the internal `DID_LOAD_ITEM` hook.\n\n## 4.28.2\n\n-   Fix issue where local server files could not be re-uploaded after editing and did not trigger remove of source file.\n\n## 4.28.1\n\n-   Fix CSS error.\n\n## 4.28.0\n\n-   Add `storeAsFile` property, if set to `true` FilePond will attempt to store the file objects in file input elements allowing file submit along with parent form (no need for `server` property). **This only works if the browser [supports the DataTransfer constructor](https://caniuse.com/mdn-api_datatransfer_datatransfer), this is the case on Firefox, Chrome, Chromium powered browsers and Safari version 14.1 and higher.**\n-   Switch to PostCSS for style output.\n\n## 4.27.3\n\n-   Fix issue with file.js component leaking state causing `allowRemove` to impact other instances of FilePond. #713\n\n## 4.27.2\n\n-   Fix issue with fetch and `HEAD` no setting server id to hidden input element.\n\n## 4.27.1\n\n-   Fix issue with `allowMinimumUploadDuration` set to `false` throwing error.\n\n## 4.27.0\n\n-   Add `allowMinimumUploadDuration` set to `false` to prevent a minimum upload time of 750ms.\n\n## 4.26.2\n\n-   `setMetadata` internal `silent` bool now does fire internal `DID_UPDATE_ITEM_METADATA` but doesn't trigger upload or file prepare logic. This fixes an issue with the new image editor and file poster plugins.\n\n## 4.26.1\n\n-   Add metdata change info to internal `SHOULD_PREPARE_OUTPUT` call\n\n## 4.26.0\n\n-   Fix problem with rendering 0 items per row. #676\n-   The `headers` property of the `server.process` end point can now be a function.\n\n## 4.25.3\n\n-   Fix issue with `chunkRetryDelays`. #671\n\n## 4.25.2\n\n-   Fix issue with fixed with file items not row wrapping correctly. #653\n-   Fix file info label when remove button positioned to the right. #620\n\n## 4.25.1\n\n-   Renamed `beforePrepareOutput` hook to `beforePrepareFile`.\n\n## 4.25.0\n\n-   Add `beforePrepareOutput` hook to intercept and prevent preparing a new output file.\n\n## 4.24.0\n\n-   Add action info to internal `SHOULD_PREPARE_OUTPUT` call\n-   Moved edit button CSS to FilePond\n\n## 4.23.1\n\n-   When files are dropped in a folder the file type cannot always be determined, this fix prevents FilePond from creating a Blob if it can't guesstimate the file type.\n\n## 4.23.0\n\n-   Add \"powered by\" footer and [credits prop](https://pqina.nl/filepond/docs/patterns/api/filepond-instance/#disabling-credits).\n\n## 4.22.1\n\n-   Fix problem with locale files.\n\n## 4.22.0\n\n-   Add internal filter for plugins to manipulate dropped files before adding them to the files list.\n\n## 4.21.1\n\n-   Fix calculation of file size when `fileSizeBase` is set to 1024.\n\n## 4.21.0\n\n-   Add `fileSizeBase` use to adjust the way files sizes are displayed. Default is `1000`.\n\n## 4.20.1\n\n-   Add `allowRemove` option so it actually works.\n\n## 4.20.0\n\n-   Add `allowRemove`, set to `false` to disable remove button.\n-   Improve TypeScript definitions.\n-   Fix issue where `removeFiles` would not remove all files.\n\n## 4.19.2\n\n-   Fix problem with locale files not ending up on npm.\n\n## 4.19.1\n\n-   Fix issue where removal of a server file was requested when setting new files to the `files` property.\n\n## 4.19.0\n\n-   Add locale folder, can now import different locales.\n-   Improve `supports` method, now correctly detects MacOS Safari 8.\n-   Improve type definitions file.\n-   Fix issue with `removeFiles({ revert: false })` not working.\n-   Fix issue where content pasted in a textarea would be interpreted as a file.\n\n## 4.18.0\n\n-   Add fallback for `fetch` when loading remote URLs, if no custom fetch supplied, will use default request.\n-   Add TypeScript dynamic label types.\n-   Fix issue where order of files wasn't correct when setting initial files.\n\n## 4.17.1\n\n-   Fix issue where reorder event was fired on each drag interaction, now only fires when order changes.\n\n## 4.17.0\n\n-   Add `allowProcess`, set to `false` to remove processing button and related abort / retry processing controls.\n-   Fix issue where hidden inputs didn't reflect visual order of files in list.\n\n## 4.16.0\n\n-   Add `allowSyncAcceptAttribute`, set to `false` to prevent FilePond from setting the file input field `accept` attribute to the value of the `acceptedFileTypes`.\n\n## 4.15.1\n\n-   Fix issue with abort being called even when not supplied.\n\n## 4.15.0\n\n-   Add support for reording items in grid layout. Thanks @jwsinner ❤︎\n\n## 4.14.0\n\n-   Add `oninitfile`, called when file is first initialised, can be used to immediately set metadata.\n\n## 4.13.7\n\n-   Fix backwards compatibility problem with `4.13.5` and `4.13.6` where removeFile would revert upload.\n-   Add `{ revert: true }` as parameter to `removeFile` and `removeFiles` methods. Where in the previous two fix versions reverting was added to be done automatically this new parameter now needs be set to revert the upload.\n\n## 4.13.6\n\n-   Fix problem where revert wasn't called for user added files.\n\n## 4.13.5\n\n-   Fix trigger of revert handler to `removeFile` API.\n-   Fix problem where circular layout wouldn't work on latest Safari.\n\n## 4.13.4\n\n-   Fix issue where FilePond internal event mechanism would be in slowmotion mode when running in an inactive tab because of `setTimeout` use.\n\n## 4.13.3\n\n-   Fix issue where FilePond would excessivly pause in between processing files while running in an inactive tab.\n\n## 4.13.2\n\n-   Fix issue where FilePond running in an inactive tab would be very slow to pick up new files.\n\n## 4.13.1\n\n-   Fix issue where HEAD fetch request would try turn response into zero byte file.\n\n## 4.13.0\n\n-   Fix issue where hidden file fields were not in the correct order when files were sorted either automatically or manually.\n-   Clean up accidental log statement left in 4.12.2 release.\n\n## 4.12.2\n\n-   Fix issue with re-enabling FilePond field from disabled state not applying the appropriate fields to the browse input.\n\n## 4.12.1\n\n-   Fix issue where browse button wasn't clickable when `styleLayoutMode` was set to `compact`.\n\n## 4.12.0\n\n-   Add `styleButtonRemoveItemAlign` to align remove button to the left side of the file item.\n-   Fix issue where list of files could not be scrolled when FilePond was disabled.\n\n## 4.11.0\n\n-   Add `relativePath` property to file item.\n-   Add `onreorderfiles` callback.\n-   Fix issue where unkown type was `\"null\"` instead of an empty string.\n-   Fix issue where `onactivatefile` was fired on drag end.\n\n## 4.10.0\n\n-   Copy webkitDirectory property to file object.\n\n## 4.9.5\n\n-   Fix issue with error format in TypeScript types.\n\n## 4.9.4\n\n-   Fix problem with API querystring containing multiple questionmarks.\n\n## 4.9.3\n\n-   Fix problem where ending the class attribute on a space would throw an error.\n\n## 4.9.2\n\n-   Add `grab` cursor to items so there's and indicator that items are grabbable.\n\n## 4.9.1\n\n-   Fix issue where Chrome on Android would launch pull-to-refresh when trying to drag a file item.\n\n## 4.9.0\n\n-   Add drag to reorder file items, enable by setting `allowReorder` to `true`.\n    -   Only works in single column mode (for now).\n    -   It also works when the list of files is showing a scrollbar, but dragging + scrolling isn't working correctly at the moment.\n    -   Limited to [browsers supporting Pointer events](https://caniuse.com/#feat=pointer).\n-   Add `moveFile(query, index)` method. Use to move a file to a different index in the file items array.\n\n## 4.8.2\n\n-   Fix problem with 4.8.1 fix not working with SSR.\n\n## 4.8.1\n\n-   Fix IE issue where adding markup would not work.\n\n## 4.8.0\n\n-   Add `prepareFile` and `prepareFiles` methods to the FilePond instance, use to request output files of the current items in the files list.\n\n## 4.7.4\n\n-   UTF-8 encode request headers to prevent issues with weird characters.\n\n## 4.7.3\n\n-   Switch from `setAttribute` to `cssText` for layout changes resulting in better performance and CSP compatibility. [#400](https://github.com/pqina/filepond/pull/400)\n\n## 4.7.2\n\n-   Fix issue where iOS 10 would throw an error when calling `delete` on a dataset property\n-   Fix issue with `onwarning` being called on incorrect element\n\n## 4.7.1\n\n-   Fix problem where directories with over 100 files weren't read correctly.\n\n## 4.7.0\n\n-   Add support for [chunked uploads](https://pqina.nl/filepond/docs/patterns/api/server/#process-chunks). Thanks to Ryan Olson (@ams-ryanolson) Arctic Media for donating the funds to build this.\n\n## 4.6.1\n\n-   Add missing Blob type to TypeScript server config.\n\n## 4.6.0\n\n-   Add TypeScript declarations.\n\n## 4.5.2\n\n-   If `Blob` has `name` attribute use name attribute instead of URL for file name.\n\n## 4.5.1\n\n-   Fix issue where drag-drop from Firefox download list would not add file to drop area\n\n## 4.5.0\n\n-   Add option to set server end point headers on a generic level so they're applied to all end points using `server.headers`.\n\n## 4.4.13\n\n-   Fix problem with CSS overriding image preview markup text size.\n\n## 4.4.12\n\n-   Fix memory leak.\n\n## 4.4.11\n\n-   Fix problem with abort statement in file loader logic.\n\n## 4.4.10\n\n-   Fix issue where Promise returned by `addFile` would not be rejected if file failed to load.\n\n## 4.4.9\n\n-   Fix security issues with dependencies.\n\n## 4.4.8\n\n-   Fix issue where multiple calls to `setMetadata` would result in multiple successive calls to prepare file.\n-   Fix issue where drop area aspect ratio would not update correctly on resize.\n\n## 4.4.7\n\n-   Fix issue where pasting a file would throw an error.\n-   Fix issue where ignored files would be counted as files when dropping a folder.\n\n## 4.4.6\n\n-   Fix issue where `processFiles` would re-process `local` server images.\n\n## 4.4.5\n\n-   Fix issue where FilePond event loop would freeze when tab was inactive.\n\n## 4.4.4\n\n-   Fix issue where FilePond would not render when hidden, resulting in missing input elements and events not firing.\n\n## 4.4.3\n\n-   Fix issue where processing the queue didn't work correctly when files were removed while being in the queue.\n\n## 4.4.2\n\n-   Fix issue where UTF-8 encoded filename was not parsed correctly.\n\n## 4.4.1\n\n-   Fix issue where `Content-Disposition` header filename was not parsed correctly.\n\n## 4.4.0\n\n-   Fix issue where `addFile` did not respect `itemInsertLocation` setting.\n-   Add the `beforeDropFile` hook which can be used to validate a dropped item before it's added, make sure `dropValidation` is set to `true` as well.\n\n## 4.3.9\n\n-   Fix problem where enabling FilePond after being `disabled` would not allow browsing for files.\n\n## 4.3.8\n\n-   Improve accessibility of buttons by moving label from `title` to inner hidden `<span>`.\n\n## 4.3.7\n\n-   Attempt #2 at fixing the issue of release `4.3.6`.\n\n## 4.3.6\n\n-   Fix problem where the `abortAll` call triggered when destroying FilePond would inadvertently trigger the `server.remove` end point for each local file.\n\n## 4.3.5\n\n-   Fix issue where changing the `stylePanelAspectRatio` would not update the container size.\n\n## 4.3.4\n\n-   Add source code.\n-   Add build scripts.\n-   Fix `onremovefile` callback not receiving an error object similar to `onaddfile`.\n\n## 4.3.3\n\n-   Fix issue where aborting a file load while the file was being prepared (for instance, encoded) did not work.\n\n## 4.3.2\n\n-   Fix issue where 0 byte files would not upload to the server.\n\n## 4.3.1\n\n-   Add `status` property to the FilePond instance, use this property to determine the current FilePond status (`EMPTY`, `IDLE`, `ERROR`, `BUSY`, or `READY`).\n\n## 4.3.0\n\n-   Fix problem where `addFiles` would not correctly map passed options to files.\n-   Fix problem where upload error would prevent processing of other files.\n-   Fix problem where the field would not \"exist\" if it had no value. Now if FilePond is empty the internal file input element is given the name attribute, this is removed when a file is added (as the name is then present on the file's hidden input element).\n-   Add `onprocessfiles` which is called when all files have been processed.\n-   Add `onactivatefile` which is called when a user clicks or taps on a file item.\n\n## 4.2.0\n\n-   Add `disabled` property, can be set as an attribute on the file input or as a property in the FilePond options object.\n-   Add catching clicks on the entire pond label element to make it easier to click the label.\n\n## 4.1.4\n\n-   Only hide preview images when resizing the window horizontally, fixes problem with resize events on iOS.\n\n## 4.1.3\n\n-   Improve the way that FilePond resumes drawing when a tab retains focus.\n\n## 4.1.2\n\n-   Fix problem where `onaddfile` callback parameters were reversed when file validation plugins prevented file load\n\n## 4.1.1\n\n-   Fix problem where error shake animation would mess up preview image.\n\n## 4.1.0\n\n-   Add `itemInsertLocationFreedom` property, set to `false` to stop user from picking the location in the file list where the file is added.\n\n## 4.0.2\n\n-   Fix problem with undefine `ItemStatus` object in `processFiles` method\n\n## 4.0.1\n\n-   Fix problem where window resize handler was removed incorrectly resulting in an error.\n\n## 4.0.0\n\nMultiple improvements, small fixes and new features. As updating will result in animation speed changes, changes to the way files are added to the files list, and will require an update of the image preview plugin, the version has been bumped to 4.0.0\n\n-   Add grid layout feature. Assign a fixed width to a filepond item and FilePond will render the items in rows.\n\nThe code below will render a list view on small viewports, a 50/50 grid on medium viewports, and a 33/33/33 grid on wide viewports. The `.5em` in each calc statement is equivalent to the combined left and right margin of each filepond item.\n\n```css\n@media (min-width: 30em) {\n    .filepond--item {\n        width: calc(50% - 0.5em);\n    }\n}\n\n@media (min-width: 50em) {\n    .filepond--item {\n        width: calc(33.33% - 0.5em);\n    }\n}\n```\n\n-   Add `styleItemPanelAspectRatio` to control the item panel aspect ratio and render item panels in a fixed size.\n-   Add `sort` method on FilePond instance for sorting FilePond files.\n-   Add `itemInsertLocation` property to set default insert location of files or sort method.\n-   Add `itemInsertInterval` to control the small delay between adding items to the files list.\n-   Improve drag and drop performance.\n-   Improve file insert logic and performance.\n-   Improve rendering of file previews will now scale correctly when window is resized.\n-   Improve handling of dropped directories on Firefox, file type was missing, now guestimates file type based on file extension.\n-   Small tweaks and changes to file animation durations and intros.\n-   Fixed drag coordinates being slightly out of place.\n-   Multiple small fixes and code improvements.\n\n## 3.9.0\n\n-   Add `checkValidity` which is set to `false` by default. If it's set to `true`, FilePond will set the contents of the `labelInvalidField` property as the field custom validity message if it contains invalid files (files that for instance exceed max file size or fail other tests).\n\n## 3.8.2\n\n-   Fix problem where remove server error message was passed directly to client without label. Set `labelFileRemoveError` to a string to change default error, set it to a function to show custom server error. `{ labelFileRemoveError: serverError => serverError }`\n\n## 3.8.1\n\n-   Expose `dispatch` call to plugin item extensions.\n\n## 3.8.0\n\n-   Add `forceRevert` option, set to `true` to force a revert action to finish before continuing.\n\n## 3.7.7\n\n-   Improve `onlistupdate` event so it can be better synced with adapter components.\n\n## 3.7.6\n\n-   Switched browse text underline to `text-decoration-skip-ink: auto` instead of `text-decoration-skip: ink` to prevent eslint warnings.\n\n## 3.7.5\n\n-   Fix problem where calling `processFiles` without arguments would re-process already processed files.\n\n## 3.7.4\n\n-   Fix problem where subsequent calls to `processFile` would not automatically revert an uploaded file or abort an active upload.\n\n## 3.7.3\n\n-   Fix problem where upload complete indicator would not show when image preview was active.\n\n## 3.7.2\n\n-   Expose `createItemAPI` to plugins.\n\n## 3.7.1\n\n-   Fix problem where URLs would immidiately be in processed state.\n\n## 3.7.0\n\n-   Add `maxParallelUploads` option to limit the amount of files being uploaded in parallel.\n-   Add option to only fetch file head when downloading remote URLs. File is downloaded to the server and server sends a unique file id to the client. Set `server.fetch.method` to `'HEAD'` the server needs to repond with custom header `X-Content-Transfer-Id` and a unique id. See [handle_fetch_remote_file](https://github.com/pqina/filepond-server-php/blob/master/index.php#L91) in FilePond PHP Server for an example implementation.\n\n## 3.6.0\n\n-   Add support for uploading transform plugin variants.\n-   Add `server.process.ondata` which allows adding entries to the formdata before it's sent to the server.\n\n## 3.5.1\n\n-   Fix problem where `processFile` and `processFiles` would reprocess already processed files.\n\n## 3.5.0\n\n-   Add `beforeAddFile` hook, this can be used to quickly validate files before they're being added.\n\n## 3.4.0\n\n-   Add `server.remove` property, this property can be optionally set to a method to call when the remove button is tapped on a `local` file. This allows removing files from the server. Please note that allowing clients to remove files from the server is a potential security risk and requires extra caution.\n\nBy default the property is `null`. The advise is to not use this method and only make changes to the server after the parent form has been submitted. The form POST will contain all the loaded file names and relevant file data, it should be enough to determine the files to remove and the files to keep.\n\n## 3.3.3\n\n-   Fix filename matching of content-disposition header when the filename is not wrapped in quotes.\n-   Fix problem where special characters in filename prevented a file from being added\n\n## 3.3.2\n\n-   Fix problem where revert call would revert wrong file item.\n\n## 3.3.1\n\n-   Fix problem where exceeding the max file limit would not throw an error\n\n## 3.3.0\n\n-   Add feature to silently update metadata so it doesn't trigger an update.\n\n## 3.2.5\n\n-   Fix issue where items would be removed before item sub views were all in rest state.\n\n## 3.2.4\n\n-   Fix problem where server side rendering would not work correctly.\n\n## 3.2.3\n\n-   Fix problem where `beforeRemoveFile` hook was not called when in `instantUpload` mode and reverting an upload.\n\n## 3.2.2\n\n-   Add preparations for queueing file processing.\n-   Improve guards against errors when items are removed.\n-   Improve alignment of drop label.\n\n## 3.2.1\n\n-   Group updateitems callback for better compatibility with React.\n\n## 3.2.0\n\n-   Add global scoped property for painter so multiple libraries can subscribe to read and write DOM operations. This is mostly in preparation for a standalone version of the Image Editor plugin.\n\n## 3.1.6\n\n-   Fix problem where remove callback would no longer work.\n\n## 3.1.5\n\n-   Fix problem with WebWorkers not working correctly on Edge and IE.\n\n## 3.1.4\n\n-   Fix syntax error [#147](https://github.com/pqina/filepond/pull/147)\n\n## 3.1.3\n\n-   Fix additional problem with quick file removals.\n\n## 3.1.2\n\n-   Fix problem where remove call would throw error depending on the state of the upload.\n-   Fix problem where clicking on abort before upload had started would not cancel upload.\n\nPlease note that this update will require installing new versions of the following plugins:\n\n-   File Validate Size\n\n## 3.1.1\n\n-   Fix problem where panel overflow would render incorrectly.\n\n## 3.1.0\n\n-   Improve diffing when updating the `files` property.\n-   Add `onupdatefiles` callback that is triggered when a file is added or removed to a pond instance.\n\n## 3.0.4\n\n-   Fix problem where feature detection would throw error on iOS 8.x\n\n## 3.0.3\n\n-   Fix problem with XMLHttpRequest timeout on Internet Explorer 11.\n-   Fix problem with custom properties on element on Internet Explorer 11.\n\n## 3.0.2\n\n-   Fix problem with label not being clickable while in integrated layout mode.\n\n## 3.0.1\n\n-   Fix problem where timeout would incorrectly trigger for uploads.\n\n## 3.0.0\n\n-   Small internal flow changes to facilitate integration with the Image Editor plugin\n-   Improve performance\n-   Improve file loader so it now supports `blob` URLs\n-   Add `stylePanelLayout` setting to set layout mode for panel\n-   Add `stylePanelAspectRatio` setting to fix aspect ratio of panel\n-   Add `styleButtonRemoveItemPosition` to control remove button position on image preview\n-   Add `styleButtonProcessItemPosition` to control item processing position on image preview\n-   Add `styleLoadIndicatorPosition` to control load indicator position on image preview\n-   Add `styleProgressIndicatorPosition` to control process indicator position on image preview\n-   Add method to automatically update data when file metadata is updated\n-   Fix animation rest state detection\n\nPlease note that this update will require installing new versions of the following plugins:\n\n-   File Encode\n-   Image Crop\n-   Image Preview\n-   Image Transform\n\n## 2.3.1\n\n-   Fix improved browser environment detection.\n\n## 2.3.0\n\n-   Improve browser environment detection [#123](https://github.com/pqina/filepond/pull/123).\n-   Add `beforeRemoveFile` callback to allow user confirmation before actual file removal.\n\n## 2.2.1\n\n-   Fix another problem where list overflow would not render correctly.\n\n## 2.2.0\n\n-   Fix problem where `maxFiles` was not enforced when dropping a set of files, each file was added in sequence till `maxFiles` was reached while the set as a whole should've been invalidated at once.\n\n## 2.1.3\n\n-   Fix problem where max-height of filepond root would not be respected by file list.\n\n## 2.1.2\n\n-   Cleaned up some stray babelHelpers.\n-   Fix bug in render engine style method, should result in less unnecessary redraws.\n\n## 2.1.1\n\n-   Fix problem where the drop indicator would render at the wrong location.\n-   Fix problem where calling `removeFile` directly after `processFile` was resolved would throw an error.\n\n## 2.1.0\n\n-   Labels can now be set as functions, these functions will receive context information, this is useful to customize both he load error and processing error labels based on server response.\n\n## 2.0.1\n\n-   Add additional utilities to plugin API.\n\n## 2.0.0\n\n-   Automatically replace undo button counterclockwise arrow icon with remove button icon when `instantUpload` is set to `true`.\n\n## 1.8.8\n\n-   Add `metadata` handling to `addFile` method.\n\n## 1.8.7\n\n-   Fix problem where setting `allowRevert` to `false` would hide the remove button.\n\n## 1.8.6\n\n-   Fix problem where adding dataURIs would throw an error\n\n## 1.8.5\n\n-   Fix casting of input attributes without value to correct boolean\n\n## 1.8.4\n\n-   Fix problem where response timeout would throw an error\n-   Improve handling of returned value by processing onload function\n\n## 1.8.3\n\n-   Cleaning up some stray code\n\n## 1.8.2\n\n-   Fix problem where element options did not override page level options\n\n## 1.8.1\n\n-   Handle `Blob` with `name` property same as actual `File` object\n-   Attempt to fix a problem where `elementFromPoint` could not be found in Angular component\n\n## 1.8.0\n\n-   Add view filter to file info view\n-   Add option to [mock server files](https://pqina.nl/filepond/docs/patterns/api/filepond-object/#creating-a-filepond-instance)\n-   Add option to [set initial file metadata](https://pqina.nl/filepond/docs/patterns/api/filepond-object/#creating-a-filepond-instance) for server files\n-   Bugfixes\n\n## 1.7.4\n\n-   Fix handling of `Content-Disposition` header to better extract the filename\n\n## 1.7.3\n\n-   Events are now fired asynchronous, this allows internal processes to finish up\n\n## 1.7.2\n\n-   Fix broken links in README\n\n## 1.7.1\n\n-   Add view filter to file status view\n-   Fix problem where attribute object value was not read correctly\n\n## 1.7.0\n\n-   Add `onerror` callback to server configuration to allow custom parsing of error response\n\n## 1.6.2\n\n-   Fix problem where restored temp file would not be removed correctly\n\n## 1.6.1\n\n-   Add `FileOrigin` enum to FilePond object\n\n## 1.6.0\n\n-   Add `fileOrigin` property to file item\n\n## 1.5.4\n\n-   Update README with links to new plugins and adapters\n\n## 1.5.3\n\n-   Accidentally skip over this version number\n\n## 1.5.2\n\n-   Remove max-width on file status view\n\n## 1.5.1\n\n-   Prevent text wrapping for file size label\n\n## 1.5.0\n\n-   Add `onload` method to server configuration\n\n## 1.4.1\n\n-   Fix progress indicator getting stuck on subsequent uploads\n\n## 1.4.0\n\n-   Add `allowRevert` option to disable revert button\n\n## 1.3.0\n\n-   Add `dropValidation` option to enable pre-validating of dropped items\n\n## 1.2.11\n\n-   Improve timing of CPU heavy operations (like file encoding) when a file is added to FilePond\n\n## 1.2.10\n\n-   Fix `removeFiles` method. Did not correctly remove files when called with empty arguments or an array of indexes\n\n## 1.2.9\n\n-   Fix bug where `processFiles` only worked when receiving parameters\n\n## 1.2.8\n\n-   Tiny improvements so can be used when server side rendering\n\n## 1.2.7\n\n-   Improve loading indicator state\n-   Add Angular adapter reference to README\n\n## 1.2.6\n\n-   Add `onprocessfile` callback to options object\n\n## 1.2.5\n\n-   Fix id attribute not being available on FilePond root\n-   Fix FilePond not rendering correctly when initially hidden\n-   Improve render performance\n\n## 1.2.4\n\n-   Fix `setOptions` method not correctly converting value types\n\n## 1.2.3\n\n-   Update the `OptionTypes` property when a plugin is registered\n\n## 1.2.2\n\n-   Fix `setOptions` returning an incorrectly formatted options object\n\n## 1.2.1\n\n-   Add README link to backlog on WIP\n-   Fix problem where `destroy` would not remove FilePond\n-   Switch license from GPL to MIT\n-   Add jQuery to adapters list\n-   Fix error message animation\n-   Improve FilePond event parameters\n\n## 1.1.0\n\n-   Accidentally skip version 1.1.0\n\n## 1.0.8\n\n-   Fix problem where plugins could be registered twice\n-   Improve `files` property, now compares existing files against new files and updates accordingly\n\n## 1.0.7\n\n-   Hide center panel before scaling panel view\n\n## 1.0.6\n\n-   Improve style possibilities for panel views and enforce internal panel layout properties\n\n## 1.0.5\n\n-   Fix problem where loading indicators would not spin for certain requests\n-   Various improvements to README\n\n## 1.0.4\n\n-   Fix render bugs\n-   Improve panel view layout\n\n## 1.0.3\n\n-   Fix processing complete state file item color\n\n## 1.0.2\n\n-   Add support for client side file manipulation\n-   Add support for file metadata\n-   Improve performance\n\n## 1.0.1\n\n-   Add correct banners to library files\n\n## 1.0.0\n\n-   Initial release\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Pqina\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# [<img src=\"https://github.com/pqina/filepond-github-assets/blob/master/logo.svg\" height=\"44\" alt=\"FilePond\"/>](https://pqina.nl/filepond/)\n\nA JavaScript library that can upload anything you throw at it, optimizes images for faster uploads, and offers a great, accessible, silky smooth user experience.\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/pqina/filepond/blob/master/LICENSE)\n[![npm version](https://badge.fury.io/js/filepond.svg)](https://www.npmjs.com/package/filepond)\n![npm](https://img.shields.io/npm/dt/filepond)\n[![minzipped size](https://img.shields.io/bundlephobia/minzip/filepond)](https://bundlephobia.com/package/filepond)\n[![Discord](https://img.shields.io/discord/1422126182924554291?label=discord)](https://discord.gg/KTyymsrTrX)\n\nFilePond adapters are available for **[React](https://github.com/pqina/react-filepond)**, **[Vue](https://github.com/pqina/vue-filepond)**, **[Angular](https://github.com/pqina/ngx-filepond)**, **[Svelte](https://github.com/pqina/svelte-filepond)**, and **[jQuery](https://github.com/pqina/jquery-filepond)**\n\n[FilePond v5 Alpha version now available for testing](https://github.com/pqina/filepond/tree/v5)\n\n[Documentation](https://pqina.nl/filepond/docs) • [Discord](https://discord.gg/KTyymsrTrX) • [Examples](#live-demos)\n\n---\n\n[<img src=\"https://github.com/pqina/filepond-github-assets/blob/master/header.svg\" alt=\"FilePond\"/>](https://www.buymeacoffee.com/rikschennink/)\n\n[Buy me a Coffee](https://www.buymeacoffee.com/rikschennink/) • [Use FilePond with Pintura](https://pqina.nl/pintura/?ref=github-filepond) • [Dev updates](https://rik.schenn.ink)\n\n---\n\n### Core Features\n\n-   Accepts **directories**, **files**, blobs, local URLs, **remote URLs** and Data URIs.\n-   **Drop files**, select on filesystem, **copy and paste files**, or add files using the API.\n-   **Async uploads** with AJAX, supports **chunk uploads**, can encode files as base64 data and send along form post.\n-   **Accessible**, tested with AT software like VoiceOver and JAWS, **navigable by Keyboard**.\n-   **Image optimization**, automatic image resizing, **cropping**, filtering, and **fixes EXIF orientation**.\n-   **Responsive**, automatically scales to available space, is functional on both **mobile and desktop devices**.\n\n[Learn more about FilePond](https://pqina.nl/filepond/)\n\n[<img src=\"https://github.com/pqina/filepond-github-assets/blob/master/filepond-animation-01.gif?raw=true\" width=\"370\" alt=\"\"/>](https://pqina.nl/filepond/)\n\n---\n\n### Also need Image Editing?\n\n**Pintura the modern JavaScript Image Editor** is what you're looking for. Pintura supports setting **crop aspect ratios**, **resizing**, **rotating**, **cropping**, and **flipping** images. Above all, it integrates beautifully with FilePond.\n\n[Learn more about Pintura](https://pqina.nl/pintura/?ref=github-filepond)\n\n[<img src=\"https://github.com/pqina/filepond-github-assets/blob/master/filepond_pintura.gif?raw=true\" width=\"600\" alt=\"\"/>](https://pqina.nl/pintura/?ref=github-filepond)\n\n---\n\n### Live Demos\n\n-   [React](https://stackblitz.com/github/pqina/pintura-example-react?file=src%2FExampleFilePond.js)\n-   [Angular](https://stackblitz.com/github/pqina/pintura-example-angular?file=src%2Fapp%2Ffilepond-example%2Ffilepond-example.component.ts)\n-   [Svelte](https://stackblitz.com/github/pqina/pintura-example-svelte?file=src%2FApp.svelte%3AL152)\n-   [Vue](https://stackblitz.com/github/pqina/pintura-example-vue-3?file=src%2FExampleFilePond.vue)\n\n### Plugins\n\n-   [File encode](https://github.com/pqina/filepond-plugin-file-encode)\n-   [File rename](https://github.com/pqina/filepond-plugin-file-rename)\n-   [File size validation](https://github.com/pqina/filepond-plugin-file-validate-size)\n-   [File type validation](https://github.com/pqina/filepond-plugin-file-validate-type)\n-   [File metadata](https://github.com/pqina/filepond-plugin-file-metadata)\n-   [File poster](https://github.com/pqina/filepond-plugin-file-poster)\n-   [Image editor](https://github.com/pqina/filepond-plugin-image-edit)\n-   [Image size validation](https://github.com/pqina/filepond-plugin-image-validate-size)\n-   [Image preview](https://github.com/pqina/filepond-plugin-image-preview)\n-   [Image crop](https://github.com/pqina/filepond-plugin-image-crop)\n-   [Image filter](https://github.com/pqina/filepond-plugin-image-filter)\n-   [Image resize](https://github.com/pqina/filepond-plugin-image-resize)\n-   [Image transform](https://github.com/pqina/filepond-plugin-image-transform)\n-   [Image EXIF orientation](https://github.com/pqina/filepond-plugin-image-exif-orientation)\n-   [Image overlay](https://github.com/nielsboogaard/filepond-plugin-image-overlay) ([nielsboogaard/filepond-plugin-image-overlay](https://github.com/nielsboogaard/filepond-plugin-image-overlay))\n-   [Media preview](https://github.com/nielsboogaard/filepond-plugin-media-preview) ([nielsboogaard/filepond-plugin-media-preview](https://github.com/nielsboogaard/filepond-plugin-media-preview))\n-   [Media preview + PDF preview](https://github.com/ErnestBrandi/filepond-plugin-media-preview) ([ErnestBrandi/filepond-plugin-media-preview](https://github.com/ErnestBrandi/filepond-plugin-media-preview))\n-   [Get file](https://github.com/nielsboogaard/filepond-plugin-get-file) ([nielsboogaard/filepond-plugin-get-file](https://github.com/nielsboogaard/filepond-plugin-get-file))\n-   [Zip Directory Uploads](https://github.com/tzsk/filepond-plugin-zipper) ([tzsk/filepond-plugin-zipper](https://github.com/tzsk/filepond-plugin-zipper))\n-   [PDF Preview](https://github.com/Adri-Glez/filepond-plugin-pdf-preview) ([Adri-Glez/filepond-plugin-pdf-preview](https://github.com/Adri-Glez/filepond-plugin-pdf-preview))\n-   [PDF Convert](https://github.com/alexandreDavid/filepond-plugin-pdf-convert) ([alexandreDavid/filepond-plugin-pdf-convert](https://github.com/alexandreDavid/filepond-plugin-pdf-convert))\n\n### Adapters\n\n-   [React](https://github.com/pqina/react-filepond)\n-   [Vue](https://github.com/pqina/vue-filepond)\n-   [Svelte](https://github.com/pqina/svelte-filepond)\n-   [jQuery](https://github.com/pqina/jquery-filepond)\n-   [Angular](https://github.com/pqina/ngx-filepond)\n-   [Angular 1](https://github.com/johnnyasantoss/angularjs-filepond) ([johnnyasantoss/angularjs-filepond](https://github.com/johnnyasantoss/angularjs-filepond))\n-   [Blazor](https://github.com/soenneker/soenneker.blazor.filepond) ([soenneker/soenneker.blazor.filepond](https://github.com/soenneker/soenneker.blazor.filepond))\n-   [Ember](https://github.com/alexdiliberto/ember-filepond) ([alexdiliberto/ember-filepond](https://github.com/alexdiliberto/ember-filepond))\n\n### Backend\n\n-   [PHP](https://github.com/pqina/filepond-boilerplate-php)\n-   [Django](https://github.com/ImperialCollegeLondon/django-drf-filepond) ([ImperialCollegeLondon/django-drf-filepond](https://github.com/ImperialCollegeLondon/django-drf-filepond))\n-   [Laravel](https://github.com/Sopamo/laravel-filepond) ([Sopamo/laravel-filepond](https://github.com/Sopamo/laravel-filepond))\n-   [Laravel](https://github.com/Albert221/laravel-filepond) ([Albert221/laravel-filepond](https://github.com/Albert221/laravel-filepond))\n-   [SilverStripe](https://github.com/lekoala/silverstripe-filepond) ([lekoala/silverstripe-filepond](https://github.com/lekoala/silverstripe-filepond))\n-   [Ruby on Rails](https://github.com/Code-With-Rails/filepond-rails) ([Code-With-Rails/filepond-rails](https://github.com/Code-With-Rails/filepond-rails))\n\n## Quick Start\n\nInstall using npm:\n\n```bash\nnpm install filepond\n```\n\nThen import in your project:\n\n```js\nimport * as FilePond from 'filepond';\n\n// Create a multi file upload component\nconst pond = FilePond.create({\n    multiple: true,\n    name: 'filepond',\n});\n\n// Add it to the DOM\ndocument.body.appendChild(pond.element);\n```\n\nOr get it from a CDN:\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>FilePond from CDN</title>\n\n        <!-- Filepond stylesheet -->\n        <link href=\"https://unpkg.com/filepond/dist/filepond.css\" rel=\"stylesheet\" />\n    </head>\n    <body>\n        <!-- We'll transform this input into a pond -->\n        <input type=\"file\" class=\"filepond\" />\n\n        <!-- Load FilePond library -->\n        <script src=\"https://unpkg.com/filepond/dist/filepond.js\"></script>\n\n        <!-- Turn all file input elements into ponds -->\n        <script>\n            FilePond.parse(document.body);\n        </script>\n    </body>\n</html>\n```\n\n[Getting started with FilePond](https://pqina.nl/filepond/docs/patterns/getting-started/)\n\n## Internationalization\n\nThe [locale folder](./locale/) contains different language files, PR's are welcome, you can use locale files like this:\n\n```js\nimport pt_BR from 'filepond/locale/pt-br.js';\n\nFilePond.setOptions(pt_BR);\n```\n\n## Contributing\n\nAt the moment test coverage is not great, it's around 65%. To accept pull requests the tests need to be better, any help to improve them is very much appreciated.\n\nTests are based on Jest and can be run with `npm run test`\n\nTo build the library run `npm run build`\n\n## Publications\n\n-   [Using FilePond with NodeJS](https://www.infoworld.com/article/3627248/how-to-use-filepond-with-nodejs.html)\n-   [Applying Watermarks to Images with FilePond](https://pqina.nl/blog/applying-watermarks-to-images-with-filepond/)\n-   [Generating Image Thumbnails in the Browser using JavaScript and FilePond](https://dev.to/pqina/generating-image-thumbnails-in-the-browser-using-javascript-and-filepond-10b8)\n-   [How to upload files with Vue and FilePond](https://dev.to/pqina/how-to-upload-files-with-vue-and-filepond-1m02)\n-   [Smooth file uploading with React and FilePond](https://itnext.io/uploading-files-with-react-and-filepond-f8a798308557)\n-   [5 interesting technical challenges I faced while building FilePond](https://itnext.io/filepond-frontend-trickery-a3073c934c77)\n-   [Image uploads with Laravel and FilePond](https://devdojo.com/episode/image-uploads-with-laravel-and-filepond)\n-   [Integrating FilePond with Ember](https://alexdiliberto.com/ember-filepond/)\n-   [FilePond launch day post-mortem](https://pqina.nl/blog/filepond-launch-day-post-mortem)\n-   [FilePond on ProductHunt](https://www.producthunt.com/posts/filepond-js)\n\n### Browser Compatibility\n\nFilePond is compatible with a wide range of desktop and mobile browsers, the oldest explicitly supported browser is IE11, for best cross browser support add [FilePond Polyfill](https://github.com/pqina/filepond-polyfill) and [Babel polyfill](https://babeljs.io/docs/en/babel-polyfill) to your project.\n\nFilePond uses [BrowserStack](https://www.browserstack.com/) for compatibility testing.\n\n[<img src=\"https://github.com/pqina/filepond-github-assets/blob/master/browserstack-logo.svg\" height=\"32\" alt=\"BrowserStack\"/>](https://www.browserstack.com/)\n\n## License\n\n**Please don't remove or change the disclaimers in the source files**\n\nMIT License\n\nCopyright (c) 2020 PQINA | [Rik Schennink](mailto:rik@pqina.nl)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "banner-cli.js",
    "content": "const banner = require('./banner');\nconst pkg = require('./package.json');\nconst args = process.argv.slice(2);\nprocess.stdin.resume();\nprocess.stdin.setEncoding('utf8');\nprocess.stdin.on('data', function(data) {\n    process.stdout.write(banner({ id: args[0], ...pkg }) + data);\n});"
  },
  {
    "path": "banner.js",
    "content": "module.exports = ({ id, version, license, homepage }) => `/*!\n * ${ id } ${ version }\n * Licensed under ${ license }, https://opensource.org/licenses/${ license }/\n * Please visit ${ homepage } for details.\n */\n\n/* eslint-disable */\n`;"
  },
  {
    "path": "dist/filepond.css",
    "content": "/*!\n * FilePond 4.32.12\n * Licensed under MIT, https://opensource.org/licenses/MIT/\n * Please visit https://pqina.nl/filepond/ for details.\n */\n\n/* eslint-disable */\n.filepond--assistant {\n    position: absolute;\n    overflow: hidden;\n    height: 1px;\n    width: 1px;\n    padding: 0;\n    border: 0;\n    clip: rect(1px, 1px, 1px, 1px);\n    -webkit-clip-path: inset(50%);\n    clip-path: inset(50%);\n    white-space: nowrap;\n}\n/* Hard to override styles */\n.filepond--browser.filepond--browser {\n    /* is positioned absolute so it is focusable for form validation errors */\n    position: absolute;\n    margin: 0;\n    padding: 0;\n\n    /* is positioned ~behind drop label */\n    left: 1em;\n    top: 1.75em;\n    width: calc(100% - 2em);\n\n    /* hide visually */\n    opacity: 0;\n    font-size: 0; /* removes text cursor in Internet Explorer 11 */\n}\n.filepond--data {\n    position: absolute;\n    width: 0;\n    height: 0;\n    padding: 0;\n    margin: 0;\n    border: none;\n    visibility: hidden;\n    pointer-events: none;\n    contain: strict;\n}\n.filepond--drip {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    overflow: hidden;\n    opacity: 0.1;\n\n    /* can't interact with this element */\n    pointer-events: none;\n\n    /* inherit border radius from parent (needed for drip-blob cut of) */\n    border-radius: 0.5em;\n\n    /* this seems to prevent Chrome from redrawing this layer constantly */\n    background: rgba(0, 0, 0, 0.01);\n}\n.filepond--drip-blob {\n    position: absolute;\n    -webkit-transform-origin: center center;\n    transform-origin: center center;\n    top: 0;\n    left: 0;\n    width: 8em;\n    height: 8em;\n    margin-left: -4em;\n    margin-top: -4em;\n    background: #292625;\n    border-radius: 50%;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n.filepond--drop-label {\n    position: absolute;\n    left: 0;\n    right: 0;\n    top: 0;\n    margin: 0;\n    color: #4f4f4f;\n\n    /* center contents */\n    display: flex;\n    justify-content: center;\n    align-items: center;\n\n    /* fixes IE11 centering problems (is overruled by label min-height) */\n    height: 0px;\n\n    /* dont allow selection */\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n/* Hard to override styles on purpose */\n.filepond--drop-label.filepond--drop-label label {\n    display: block;\n    margin: 0;\n    padding: 0.5em; /* use padding instead of margin so click area is not impacted */\n}\n.filepond--drop-label label {\n    cursor: default;\n    font-size: 0.875em;\n    font-weight: normal;\n    text-align: center;\n    line-height: 1.5;\n}\n.filepond--label-action {\n    text-decoration: underline;\n    -webkit-text-decoration-skip: ink;\n    text-decoration-skip-ink: auto;\n    -webkit-text-decoration-color: #a7a4a4;\n    text-decoration-color: #a7a4a4;\n    cursor: pointer;\n}\n.filepond--root[data-disabled] .filepond--drop-label label {\n    opacity: 0.5;\n}\n/* Hard to override styles */\n.filepond--file-action-button.filepond--file-action-button {\n    font-size: 1em;\n    width: 1.625em;\n    height: 1.625em;\n\n    font-family: inherit;\n    line-height: inherit;\n\n    margin: 0;\n    padding: 0;\n    border: none;\n    outline: none;\n\n    will-change: transform, opacity;\n\n    /* hidden label */\n}\n.filepond--file-action-button.filepond--file-action-button span {\n    position: absolute;\n    overflow: hidden;\n    height: 1px;\n    width: 1px;\n    padding: 0;\n    border: 0;\n    clip: rect(1px, 1px, 1px, 1px);\n    -webkit-clip-path: inset(50%);\n    clip-path: inset(50%);\n    white-space: nowrap;\n}\n.filepond--file-action-button.filepond--file-action-button {\n    /* scale SVG to fill button */\n}\n.filepond--file-action-button.filepond--file-action-button svg {\n    width: 100%;\n    height: 100%;\n}\n.filepond--file-action-button.filepond--file-action-button {\n    /* bigger touch area */\n}\n.filepond--file-action-button.filepond--file-action-button::after {\n    position: absolute;\n    left: -0.75em;\n    right: -0.75em;\n    top: -0.75em;\n    bottom: -0.75em;\n    content: '';\n}\n/* Soft styles */\n.filepond--file-action-button {\n    /* use default arrow cursor */\n    cursor: auto;\n\n    /* reset default button styles */\n    color: #fff;\n\n    /* set default look n feel */\n    border-radius: 50%;\n    background-color: rgba(0, 0, 0, 0.5);\n    background-image: none;\n\n    /* we animate box shadow on focus */\n    /* it's only slightly slower than animating */\n    /* a pseudo-element with transforms and renders */\n    /* a lot better on chrome */\n    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);\n    transition: box-shadow 0.25s ease-in;\n}\n.filepond--file-action-button:hover,\n.filepond--file-action-button:focus {\n    box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.9);\n}\n.filepond--file-action-button[disabled] {\n    color: rgba(255, 255, 255, 0.5);\n    background-color: rgba(0, 0, 0, 0.25);\n}\n.filepond--file-action-button[hidden] {\n    display: none;\n}\n/* edit button */\n.filepond--action-edit-item.filepond--action-edit-item {\n    width: 2em;\n    height: 2em;\n    padding: 0.1875em;\n}\n.filepond--action-edit-item.filepond--action-edit-item[data-align*='center'] {\n    margin-left: -0.1875em;\n}\n.filepond--action-edit-item.filepond--action-edit-item[data-align*='bottom'] {\n    margin-bottom: -0.1875em;\n}\n.filepond--action-edit-item-alt {\n    border: none;\n    line-height: inherit;\n    background: transparent;\n    font-family: inherit;\n    color: inherit;\n    outline: none;\n    padding: 0;\n    margin: 0 0 0 0.25em;\n    pointer-events: all;\n    position: absolute;\n}\n.filepond--action-edit-item-alt svg {\n    width: 1.3125em;\n    height: 1.3125em;\n}\n.filepond--action-edit-item-alt span {\n    font-size: 0;\n    opacity: 0;\n}\n.filepond--file-info {\n    position: static;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    flex: 1;\n    margin: 0 0.5em 0 0;\n    min-width: 0;\n\n    /* will be animated */\n    will-change: transform, opacity;\n\n    /* can't do anything with this info */\n    pointer-events: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n\n    /* no margins on children */\n}\n.filepond--file-info * {\n    margin: 0;\n}\n.filepond--file-info {\n    /* we don't want to have these overrules so these selectors are a bit more specific */\n}\n.filepond--file-info .filepond--file-info-main {\n    font-size: 0.75em;\n    line-height: 1.2;\n\n    /* we want ellipsis if this bar gets too wide */\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n    width: 100%;\n}\n.filepond--file-info .filepond--file-info-sub {\n    font-size: 0.625em;\n    opacity: 0.5;\n    transition: opacity 0.25s ease-in-out;\n    white-space: nowrap;\n}\n.filepond--file-info .filepond--file-info-sub:empty {\n    display: none;\n}\n.filepond--file-status {\n    position: static;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n    flex-grow: 0;\n    flex-shrink: 0;\n\n    margin: 0;\n    min-width: 2.25em;\n    text-align: right;\n\n    /* will be animated */\n    will-change: transform, opacity;\n\n    /* can't do anything with this info */\n    pointer-events: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n\n    /* no margins on children */\n}\n.filepond--file-status * {\n    margin: 0;\n    white-space: nowrap;\n}\n.filepond--file-status {\n    /* font sizes */\n}\n.filepond--file-status .filepond--file-status-main {\n    font-size: 0.75em;\n    line-height: 1.2;\n}\n.filepond--file-status .filepond--file-status-sub {\n    font-size: 0.625em;\n    opacity: 0.5;\n    transition: opacity 0.25s ease-in-out;\n}\n/* Hard to override styles */\n.filepond--file-wrapper.filepond--file-wrapper {\n    border: none;\n    margin: 0;\n    padding: 0;\n    min-width: 0;\n    height: 100%;\n\n    /* hide legend for visual users */\n}\n.filepond--file-wrapper.filepond--file-wrapper > legend {\n    position: absolute;\n    overflow: hidden;\n    height: 1px;\n    width: 1px;\n    padding: 0;\n    border: 0;\n    clip: rect(1px, 1px, 1px, 1px);\n    -webkit-clip-path: inset(50%);\n    clip-path: inset(50%);\n    white-space: nowrap;\n}\n.filepond--file {\n    position: static;\n    display: flex;\n    height: 100%;\n    align-items: flex-start;\n\n    padding: 0.5625em 0.5625em;\n\n    color: #fff;\n    border-radius: 0.5em;\n\n    /* control positions */\n}\n.filepond--file .filepond--file-status {\n    margin-left: auto;\n    margin-right: 2.25em;\n}\n.filepond--file .filepond--processing-complete-indicator {\n    pointer-events: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    z-index: 3;\n}\n.filepond--file .filepond--processing-complete-indicator,\n.filepond--file .filepond--progress-indicator,\n.filepond--file .filepond--file-action-button {\n    position: absolute;\n}\n.filepond--file {\n    /* .filepond--file-action-button */\n}\n.filepond--file [data-align*='left'] {\n    left: 0.5625em;\n}\n.filepond--file [data-align*='right'] {\n    right: 0.5625em;\n}\n.filepond--file [data-align*='center'] {\n    left: calc(50% - 0.8125em); /* .8125 is half of button width */\n}\n.filepond--file [data-align*='bottom'] {\n    bottom: 1.125em;\n}\n.filepond--file [data-align='center'] {\n    top: calc(50% - 0.8125em);\n}\n.filepond--file .filepond--progress-indicator {\n    margin-top: 0.1875em;\n}\n.filepond--file .filepond--progress-indicator[data-align*='right'] {\n    margin-right: 0.1875em;\n}\n.filepond--file .filepond--progress-indicator[data-align*='left'] {\n    margin-left: 0.1875em;\n}\n/* make sure text does not overlap */\n[data-filepond-item-state='cancelled'] .filepond--file-info,\n[data-filepond-item-state*='invalid'] .filepond--file-info,\n[data-filepond-item-state*='error'] .filepond--file-info {\n    margin-right: 2.25em;\n}\n[data-filepond-item-state~='processing'] .filepond--file-status-sub {\n    opacity: 0;\n}\n[data-filepond-item-state~='processing']\n    .filepond--action-abort-item-processing\n    ~ .filepond--file-status\n    .filepond--file-status-sub {\n    opacity: 0.5;\n}\n[data-filepond-item-state='processing-error'] .filepond--file-status-sub {\n    opacity: 0;\n}\n[data-filepond-item-state='processing-error']\n    .filepond--action-retry-item-processing\n    ~ .filepond--file-status\n    .filepond--file-status-sub {\n    opacity: 0.5;\n}\n[data-filepond-item-state='processing-complete'] {\n    /* busy state */\n}\n[data-filepond-item-state='processing-complete'] .filepond--action-revert-item-processing svg {\n    -webkit-animation: fall 0.5s 0.125s linear both;\n    animation: fall 0.5s 0.125s linear both;\n}\n[data-filepond-item-state='processing-complete'] {\n    /* hide details by default, only show when can revert */\n}\n[data-filepond-item-state='processing-complete'] .filepond--file-status-sub {\n    opacity: 0.5;\n}\n[data-filepond-item-state='processing-complete']\n    .filepond--processing-complete-indicator:not([style*='hidden'])\n    ~ .filepond--file-status\n    .filepond--file-status-sub {\n    opacity: 0;\n}\n[data-filepond-item-state='processing-complete'] .filepond--file-info-sub {\n    opacity: 0;\n}\n[data-filepond-item-state='processing-complete']\n    .filepond--action-revert-item-processing\n    ~ .filepond--file-info\n    .filepond--file-info-sub {\n    opacity: 0.5;\n}\n/* file state can be invalid or error, both are visually similar but */\n/* having them as separate states might be useful */\n[data-filepond-item-state*='invalid'] .filepond--panel,\n[data-filepond-item-state*='invalid'] .filepond--file-wrapper,\n[data-filepond-item-state*='error'] .filepond--panel,\n[data-filepond-item-state*='error'] .filepond--file-wrapper {\n    -webkit-animation: shake 0.65s linear both;\n    animation: shake 0.65s linear both;\n}\n/* spins progress indicator when file is marked as busy */\n[data-filepond-item-state*='busy'] .filepond--progress-indicator svg {\n    -webkit-animation: spin 1s linear infinite;\n    animation: spin 1s linear infinite;\n}\n/**\n * States\n */\n@-webkit-keyframes spin {\n    0% {\n        -webkit-transform: rotateZ(0deg);\n        transform: rotateZ(0deg);\n    }\n\n    100% {\n        -webkit-transform: rotateZ(360deg);\n        transform: rotateZ(360deg);\n    }\n}\n@keyframes spin {\n    0% {\n        -webkit-transform: rotateZ(0deg);\n        transform: rotateZ(0deg);\n    }\n\n    100% {\n        -webkit-transform: rotateZ(360deg);\n        transform: rotateZ(360deg);\n    }\n}\n@-webkit-keyframes shake {\n    10%,\n    90% {\n        -webkit-transform: translateX(-0.0625em);\n        transform: translateX(-0.0625em);\n    }\n\n    20%,\n    80% {\n        -webkit-transform: translateX(0.125em);\n        transform: translateX(0.125em);\n    }\n\n    30%,\n    50%,\n    70% {\n        -webkit-transform: translateX(-0.25em);\n        transform: translateX(-0.25em);\n    }\n\n    40%,\n    60% {\n        -webkit-transform: translateX(0.25em);\n        transform: translateX(0.25em);\n    }\n}\n@keyframes shake {\n    10%,\n    90% {\n        -webkit-transform: translateX(-0.0625em);\n        transform: translateX(-0.0625em);\n    }\n\n    20%,\n    80% {\n        -webkit-transform: translateX(0.125em);\n        transform: translateX(0.125em);\n    }\n\n    30%,\n    50%,\n    70% {\n        -webkit-transform: translateX(-0.25em);\n        transform: translateX(-0.25em);\n    }\n\n    40%,\n    60% {\n        -webkit-transform: translateX(0.25em);\n        transform: translateX(0.25em);\n    }\n}\n@-webkit-keyframes fall {\n    0% {\n        opacity: 0;\n        -webkit-transform: scale(0.5);\n        transform: scale(0.5);\n        -webkit-animation-timing-function: ease-out;\n        animation-timing-function: ease-out;\n    }\n\n    70% {\n        opacity: 1;\n        -webkit-transform: scale(1.1);\n        transform: scale(1.1);\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        -webkit-animation-timing-function: ease-out;\n        animation-timing-function: ease-out;\n    }\n}\n@keyframes fall {\n    0% {\n        opacity: 0;\n        -webkit-transform: scale(0.5);\n        transform: scale(0.5);\n        -webkit-animation-timing-function: ease-out;\n        animation-timing-function: ease-out;\n    }\n\n    70% {\n        opacity: 1;\n        -webkit-transform: scale(1.1);\n        transform: scale(1.1);\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        -webkit-animation-timing-function: ease-out;\n        animation-timing-function: ease-out;\n    }\n}\n/* ignore all other interaction elements while dragging a file */\n.filepond--hopper[data-hopper-state='drag-over'] > * {\n    pointer-events: none;\n}\n/* capture all hit tests using a hidden layer, this speeds up the event flow */\n.filepond--hopper[data-hopper-state='drag-over']::after {\n    content: '';\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 100;\n}\n.filepond--progress-indicator {\n    z-index: 103;\n}\n.filepond--file-action-button {\n    z-index: 102;\n}\n.filepond--file-status {\n    z-index: 101;\n}\n.filepond--file-info {\n    z-index: 100;\n}\n.filepond--item {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    z-index: 1;\n\n    padding: 0;\n    margin: 0.25em;\n\n    will-change: transform, opacity;\n\n    touch-action: auto;\n\n    /* item children order */\n}\n.filepond--item > .filepond--panel {\n    z-index: -1;\n}\n/* has a slight shadow */\n.filepond--item > .filepond--panel .filepond--panel-bottom {\n    box-shadow: 0 0.0625em 0.125em -0.0625em rgba(0, 0, 0, 0.25);\n}\n.filepond--item {\n    /* drag related */\n}\n.filepond--item > .filepond--file-wrapper,\n.filepond--item > .filepond--panel {\n    transition: opacity 0.15s ease-out;\n}\n.filepond--item[data-drag-state] {\n    cursor: -webkit-grab;\n    cursor: grab;\n}\n.filepond--item[data-drag-state] > .filepond--panel {\n    transition: box-shadow 0.125s ease-in-out;\n    box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n}\n.filepond--item[data-drag-state='drag'] {\n    cursor: -webkit-grabbing;\n    cursor: grabbing;\n}\n.filepond--item[data-drag-state='drag'] > .filepond--panel {\n    box-shadow: 0 0.125em 0.3125em rgba(0, 0, 0, 0.325);\n}\n.filepond--item[data-drag-state]:not([data-drag-state='idle']) {\n    z-index: 2;\n}\n/* states */\n.filepond--item-panel {\n    background-color: #64605e;\n}\n[data-filepond-item-state='processing-complete'] .filepond--item-panel {\n    background-color: #369763;\n}\n[data-filepond-item-state*='invalid'] .filepond--item-panel,\n[data-filepond-item-state*='error'] .filepond--item-panel {\n    background-color: #c44e47;\n}\n/* style of item panel */\n.filepond--item-panel {\n    border-radius: 0.5em;\n    transition: background-color 0.25s;\n}\n/* normal mode */\n.filepond--list-scroller {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    margin: 0;\n    will-change: transform;\n}\n/* scroll mode */\n.filepond--list-scroller[data-state='overflow'] .filepond--list {\n    bottom: 0;\n    right: 0;\n}\n.filepond--list-scroller[data-state='overflow'] {\n    overflow-y: scroll;\n    overflow-x: hidden;\n    -webkit-overflow-scrolling: touch;\n    -webkit-mask: linear-gradient(to bottom, #000 calc(100% - 0.5em), transparent 100%);\n    mask: linear-gradient(to bottom, #000 calc(100% - 0.5em), transparent 100%);\n}\n/* style scrollbar */\n.filepond--list-scroller::-webkit-scrollbar {\n    background: transparent;\n}\n.filepond--list-scroller::-webkit-scrollbar:vertical {\n    width: 1em;\n}\n.filepond--list-scroller::-webkit-scrollbar:horizontal {\n    height: 0;\n}\n.filepond--list-scroller::-webkit-scrollbar-thumb {\n    background-color: rgba(0, 0, 0, 0.3);\n    border-radius: 99999px;\n    border: 0.3125em solid transparent;\n    background-clip: content-box;\n}\n/* hard to overide styles on purpose */\n.filepond--list.filepond--list {\n    position: absolute;\n    top: 0;\n    margin: 0;\n    padding: 0;\n    list-style-type: none;\n\n    /* prevents endless paint calls on filepond--list-scroller */\n    will-change: transform;\n}\n/* used for padding so allowed to be restyled */\n.filepond--list {\n    left: 0.75em;\n    right: 0.75em;\n}\n.filepond--root[data-style-panel-layout~='integrated'] {\n    width: 100%;\n    height: 100%;\n    max-width: none;\n    margin: 0;\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--panel-root,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--panel-root {\n    border-radius: 0;\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--panel-root > *,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--panel-root > * {\n    display: none;\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--drop-label,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--drop-label {\n    bottom: 0;\n    height: auto;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    z-index: 7;\n}\n.filepond--root[data-style-panel-layout~='circle'],\n.filepond--root[data-style-panel-layout~='integrated'] {\n    /* we're only loading one item, this makes the intro animation a bit nicer */\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--item-panel,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--item-panel {\n    display: none;\n}\n.filepond--root[data-style-panel-layout~='compact'] .filepond--list-scroller,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--list-scroller {\n    overflow: hidden;\n    height: 100%;\n    margin-top: 0;\n    margin-bottom: 0;\n}\n.filepond--root[data-style-panel-layout~='compact'] .filepond--list,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--list {\n    left: 0;\n    right: 0;\n    height: 100%;\n}\n.filepond--root[data-style-panel-layout~='compact'] .filepond--item,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--item {\n    margin: 0;\n}\n.filepond--root[data-style-panel-layout~='compact'] .filepond--file-wrapper,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--file-wrapper {\n    height: 100%;\n}\n.filepond--root[data-style-panel-layout~='compact'] .filepond--drop-label,\n.filepond--root[data-style-panel-layout~='integrated'] .filepond--drop-label {\n    z-index: 7;\n}\n.filepond--root[data-style-panel-layout~='circle'] {\n    border-radius: 99999rem;\n    overflow: hidden;\n}\n.filepond--root[data-style-panel-layout~='circle'] > .filepond--panel {\n    border-radius: inherit;\n}\n.filepond--root[data-style-panel-layout~='circle'] > .filepond--panel > * {\n    display: none;\n}\n.filepond--root[data-style-panel-layout~='circle'] {\n    /* circle cuts of this info, so best to hide it */\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--file-info {\n    display: none;\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--file-status {\n    display: none;\n}\n.filepond--root[data-style-panel-layout~='circle'] .filepond--action-edit-item {\n    opacity: 1 !important;\n    visibility: visible !important;\n}\n/* dirfty way to fix circular overflow issue on safari 11+ */\n@media not all and (min-resolution: 0.001dpcm) {\n    @supports (-webkit-appearance: none) and (stroke-color: transparent) {\n        .filepond--root[data-style-panel-layout~='circle'] {\n            will-change: transform;\n        }\n    }\n}\n.filepond--panel-root {\n    border-radius: 0.5em;\n    background-color: #f1f0ef;\n}\n.filepond--panel {\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    margin: 0;\n\n    /* defaults to 100% height (fixed height mode) this fixes problem with panel height in IE11 */\n    height: 100% !important;\n\n    /* no interaction possible with panel */\n    pointer-events: none;\n}\n.filepond-panel:not([data-scalable='false']) {\n    height: auto !important;\n}\n.filepond--panel[data-scalable='false'] > div {\n    display: none;\n}\n.filepond--panel[data-scalable='true'] {\n    /* this seems to fix Chrome performance issues */\n    /* - when box-shadow is enabled */\n    /* - when multiple ponds are active on the same page */\n    -webkit-transform-style: preserve-3d;\n    transform-style: preserve-3d;\n\n    /* prevent borders and backgrounds */\n    background-color: transparent !important;\n    border: none !important;\n}\n.filepond--panel-top,\n.filepond--panel-bottom,\n.filepond--panel-center {\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    margin: 0;\n    padding: 0;\n}\n.filepond--panel-top,\n.filepond--panel-bottom {\n    height: 0.5em;\n}\n.filepond--panel-top {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n    border-bottom: none !important;\n\n    /* fixes tiny transparant line between top and center panel */\n}\n.filepond--panel-top::after {\n    content: '';\n    position: absolute;\n    height: 2px;\n    left: 0;\n    right: 0;\n    bottom: -1px;\n    background-color: inherit;\n}\n.filepond--panel-center,\n.filepond--panel-bottom {\n    will-change: transform;\n    -webkit-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-transform-origin: left top;\n    transform-origin: left top;\n    -webkit-transform: translate3d(0, 0.5em, 0);\n    transform: translate3d(0, 0.5em, 0);\n}\n.filepond--panel-bottom {\n    border-top-left-radius: 0 !important;\n    border-top-right-radius: 0 !important;\n    border-top: none !important;\n\n    /* fixes tiny transparant line between bottom and center of panel */\n}\n.filepond--panel-bottom::before {\n    content: '';\n    position: absolute;\n    height: 2px;\n    left: 0;\n    right: 0;\n    top: -1px;\n    background-color: inherit;\n}\n.filepond--panel-center {\n    /* the center panel is scaled using scale3d to fit the correct height */\n    /* we use 100px instead of 1px as scaling 1px to a huge height is really laggy on chrome */\n    height: 100px !important;\n    border-top: none !important;\n    border-bottom: none !important;\n    border-radius: 0 !important;\n\n    /* hide if not transformed, prevents a little flash when the panel is at 100px height while attached for first time */\n}\n.filepond--panel-center:not([style]) {\n    visibility: hidden;\n}\n.filepond--progress-indicator {\n    position: static;\n    width: 1.25em;\n    height: 1.25em;\n\n    color: #fff;\n\n    /* can't have margins */\n    margin: 0;\n\n    /* no interaction possible with progress indicator */\n    pointer-events: none;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n.filepond--progress-indicator svg {\n    width: 100%;\n    height: 100%;\n    vertical-align: top;\n    transform-box: fill-box; /* should center the animation correctly when zoomed in */\n}\n.filepond--progress-indicator path {\n    fill: none;\n    stroke: currentColor;\n}\n.filepond--list-scroller {\n    z-index: 6;\n}\n.filepond--drop-label {\n    z-index: 5;\n}\n.filepond--drip {\n    z-index: 3;\n}\n.filepond--root > .filepond--panel {\n    z-index: 2;\n}\n.filepond--browser {\n    z-index: 1;\n}\n.filepond--root {\n    /* layout*/\n    box-sizing: border-box;\n    position: relative;\n    margin-bottom: 1em;\n\n    /* base font size for whole component */\n    font-size: 1rem;\n\n    /* base line height */\n    line-height: normal;\n\n    /* up uses default system font family */\n    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,\n        'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';\n\n    /* will increase font weight a bit on Safari */\n    font-weight: 450;\n\n    /* default text alignment */\n    text-align: left;\n\n    /* better text rendering on Safari */\n    text-rendering: optimizeLegibility;\n\n    /* text direction is ltr for now */\n    direction: ltr;\n\n    /* optimize rendering */\n    /* https://developer.mozilla.org/en-US/docs/Web/CSS/contain */\n    contain: layout style size;\n\n    /* correct box sizing, line-height and positioning on child elements */\n}\n.filepond--root * {\n    box-sizing: inherit;\n    line-height: inherit;\n}\n.filepond--root *:not(text) {\n    font-size: inherit;\n}\n.filepond--root {\n    /* block everything */\n}\n.filepond--root[data-disabled] {\n    pointer-events: none;\n}\n.filepond--root[data-disabled] .filepond--list-scroller {\n    pointer-events: all;\n}\n.filepond--root[data-disabled] .filepond--list {\n    pointer-events: none;\n}\n/**\n * Root element children layout\n */\n.filepond--root .filepond--drop-label {\n    min-height: 4.75em;\n}\n.filepond--root .filepond--list-scroller {\n    margin-top: 1em;\n    margin-bottom: 1em;\n}\n.filepond--root .filepond--credits {\n    position: absolute;\n    right: 0;\n    opacity: 0.4;\n    line-height: 0.85;\n    font-size: 11px;\n    color: inherit;\n    text-decoration: none;\n    z-index: 3;\n    bottom: -14px;\n}\n.filepond--root .filepond--credits[style] {\n    top: 0;\n    bottom: auto;\n    margin-top: 14px;\n}\n"
  },
  {
    "path": "dist/filepond.esm.js",
    "content": "/*!\n * FilePond 4.32.12\n * Licensed under MIT, https://opensource.org/licenses/MIT/\n * Please visit https://pqina.nl/filepond/ for details.\n */\n\n/* eslint-disable */\n\nconst isNode = value => value instanceof HTMLElement;\n\nconst createStore = (initialState, queries = [], actions = []) => {\n    // internal state\n    const state = {\n        ...initialState,\n    };\n\n    // contains all actions for next frame, is clear when actions are requested\n    const actionQueue = [];\n    const dispatchQueue = [];\n\n    // returns a duplicate of the current state\n    const getState = () => ({ ...state });\n\n    // returns a duplicate of the actions array and clears the actions array\n    const processActionQueue = () => {\n        // create copy of actions queue\n        const queue = [...actionQueue];\n\n        // clear actions queue (we don't want no double actions)\n        actionQueue.length = 0;\n\n        return queue;\n    };\n\n    // processes actions that might block the main UI thread\n    const processDispatchQueue = () => {\n        // create copy of actions queue\n        const queue = [...dispatchQueue];\n\n        // clear actions queue (we don't want no double actions)\n        dispatchQueue.length = 0;\n\n        // now dispatch these actions\n        queue.forEach(({ type, data }) => {\n            dispatch(type, data);\n        });\n    };\n\n    // adds a new action, calls its handler and\n    const dispatch = (type, data, isBlocking) => {\n        // is blocking action (should never block if document is hidden)\n        if (isBlocking && !document.hidden) {\n            dispatchQueue.push({ type, data });\n            return;\n        }\n\n        // if this action has a handler, handle the action\n        if (actionHandlers[type]) {\n            actionHandlers[type](data);\n        }\n\n        // now add action\n        actionQueue.push({\n            type,\n            data,\n        });\n    };\n\n    const query = (str, ...args) => (queryHandles[str] ? queryHandles[str](...args) : null);\n\n    const api = {\n        getState,\n        processActionQueue,\n        processDispatchQueue,\n        dispatch,\n        query,\n    };\n\n    let queryHandles = {};\n    queries.forEach(query => {\n        queryHandles = {\n            ...query(state),\n            ...queryHandles,\n        };\n    });\n\n    let actionHandlers = {};\n    actions.forEach(action => {\n        actionHandlers = {\n            ...action(dispatch, query, state),\n            ...actionHandlers,\n        };\n    });\n\n    return api;\n};\n\nconst defineProperty = (obj, property, definition) => {\n    if (typeof definition === 'function') {\n        obj[property] = definition;\n        return;\n    }\n    Object.defineProperty(obj, property, { ...definition });\n};\n\nconst forin = (obj, cb) => {\n    for (const key in obj) {\n        if (!obj.hasOwnProperty(key)) {\n            continue;\n        }\n\n        cb(key, obj[key]);\n    }\n};\n\nconst createObject = definition => {\n    const obj = {};\n    forin(definition, property => {\n        defineProperty(obj, property, definition[property]);\n    });\n    return obj;\n};\n\nconst attr = (node, name, value = null) => {\n    if (value === null) {\n        return node.getAttribute(name) || node.hasAttribute(name);\n    }\n    node.setAttribute(name, value);\n};\n\nconst ns = 'http://www.w3.org/2000/svg';\nconst svgElements = ['svg', 'path']; // only svg elements used\n\nconst isSVGElement = tag => svgElements.includes(tag);\n\nconst createElement = (tag, className, attributes = {}) => {\n    if (typeof className === 'object') {\n        attributes = className;\n        className = null;\n    }\n    const element = isSVGElement(tag)\n        ? document.createElementNS(ns, tag)\n        : document.createElement(tag);\n    if (className) {\n        if (isSVGElement(tag)) {\n            attr(element, 'class', className);\n        } else {\n            element.className = className;\n        }\n    }\n    forin(attributes, (name, value) => {\n        attr(element, name, value);\n    });\n    return element;\n};\n\nconst appendChild = parent => (child, index) => {\n    if (typeof index !== 'undefined' && parent.children[index]) {\n        parent.insertBefore(child, parent.children[index]);\n    } else {\n        parent.appendChild(child);\n    }\n};\n\nconst appendChildView = (parent, childViews) => (view, index) => {\n    if (typeof index !== 'undefined') {\n        childViews.splice(index, 0, view);\n    } else {\n        childViews.push(view);\n    }\n\n    return view;\n};\n\nconst removeChildView = (parent, childViews) => view => {\n    // remove from child views\n    childViews.splice(childViews.indexOf(view), 1);\n\n    // remove the element\n    if (view.element.parentNode) {\n        parent.removeChild(view.element);\n    }\n\n    return view;\n};\n\nconst IS_BROWSER = (() =>\n    typeof window !== 'undefined' && typeof window.document !== 'undefined')();\nconst isBrowser = () => IS_BROWSER;\n\nconst testElement = isBrowser() ? createElement('svg') : {};\nconst getChildCount =\n    'children' in testElement ? el => el.children.length : el => el.childNodes.length;\n\nconst getViewRect = (elementRect, childViews, offset, scale) => {\n    const left = offset[0] || elementRect.left;\n    const top = offset[1] || elementRect.top;\n    const right = left + elementRect.width;\n    const bottom = top + elementRect.height * (scale[1] || 1);\n\n    const rect = {\n        // the rectangle of the element itself\n        element: {\n            ...elementRect,\n        },\n\n        // the rectangle of the element expanded to contain its children, does not include any margins\n        inner: {\n            left: elementRect.left,\n            top: elementRect.top,\n            right: elementRect.right,\n            bottom: elementRect.bottom,\n        },\n\n        // the rectangle of the element expanded to contain its children including own margin and child margins\n        // margins will be added after we've recalculated the size\n        outer: {\n            left,\n            top,\n            right,\n            bottom,\n        },\n    };\n\n    // expand rect to fit all child rectangles\n    childViews\n        .filter(childView => !childView.isRectIgnored())\n        .map(childView => childView.rect)\n        .forEach(childViewRect => {\n            expandRect(rect.inner, { ...childViewRect.inner });\n            expandRect(rect.outer, { ...childViewRect.outer });\n        });\n\n    // calculate inner width and height\n    calculateRectSize(rect.inner);\n\n    // append additional margin (top and left margins are included in top and left automatically)\n    rect.outer.bottom += rect.element.marginBottom;\n    rect.outer.right += rect.element.marginRight;\n\n    // calculate outer width and height\n    calculateRectSize(rect.outer);\n\n    return rect;\n};\n\nconst expandRect = (parent, child) => {\n    // adjust for parent offset\n    child.top += parent.top;\n    child.right += parent.left;\n    child.bottom += parent.top;\n    child.left += parent.left;\n\n    if (child.bottom > parent.bottom) {\n        parent.bottom = child.bottom;\n    }\n\n    if (child.right > parent.right) {\n        parent.right = child.right;\n    }\n};\n\nconst calculateRectSize = rect => {\n    rect.width = rect.right - rect.left;\n    rect.height = rect.bottom - rect.top;\n};\n\nconst isNumber = value => typeof value === 'number';\n\n/**\n * Determines if position is at destination\n * @param position\n * @param destination\n * @param velocity\n * @param errorMargin\n * @returns {boolean}\n */\nconst thereYet = (position, destination, velocity, errorMargin = 0.001) => {\n    return Math.abs(position - destination) < errorMargin && Math.abs(velocity) < errorMargin;\n};\n\n/**\n * Spring animation\n */\nconst spring =\n    // default options\n    ({ stiffness = 0.5, damping = 0.75, mass = 10 } = {}) =>\n        // method definition\n        {\n            let target = null;\n            let position = null;\n            let velocity = 0;\n            let resting = false;\n\n            // updates spring state\n            const interpolate = (ts, skipToEndState) => {\n                // in rest, don't animate\n                if (resting) return;\n\n                // need at least a target or position to do springy things\n                if (!(isNumber(target) && isNumber(position))) {\n                    resting = true;\n                    velocity = 0;\n                    return;\n                }\n\n                // calculate spring force\n                const f = -(position - target) * stiffness;\n\n                // update velocity by adding force based on mass\n                velocity += f / mass;\n\n                // update position by adding velocity\n                position += velocity;\n\n                // slow down based on amount of damping\n                velocity *= damping;\n\n                // we've arrived if we're near target and our velocity is near zero\n                if (thereYet(position, target, velocity) || skipToEndState) {\n                    position = target;\n                    velocity = 0;\n                    resting = true;\n\n                    // we done\n                    api.onupdate(position);\n                    api.oncomplete(position);\n                } else {\n                    // progress update\n                    api.onupdate(position);\n                }\n            };\n\n            /**\n             * Set new target value\n             * @param value\n             */\n            const setTarget = value => {\n                // if currently has no position, set target and position to this value\n                if (isNumber(value) && !isNumber(position)) {\n                    position = value;\n                }\n\n                // next target value will not be animated to\n                if (target === null) {\n                    target = value;\n                    position = value;\n                }\n\n                // let start moving to target\n                target = value;\n\n                // already at target\n                if (position === target || typeof target === 'undefined') {\n                    // now resting as target is current position, stop moving\n                    resting = true;\n                    velocity = 0;\n\n                    // done!\n                    api.onupdate(position);\n                    api.oncomplete(position);\n\n                    return;\n                }\n\n                resting = false;\n            };\n\n            // need 'api' to call onupdate callback\n            const api = createObject({\n                interpolate,\n                target: {\n                    set: setTarget,\n                    get: () => target,\n                },\n                resting: {\n                    get: () => resting,\n                },\n                onupdate: value => {},\n                oncomplete: value => {},\n            });\n\n            return api;\n        };\n\nconst easeLinear = t => t;\nconst easeInOutQuad = t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t);\n\nconst tween =\n    // default values\n    ({ duration = 500, easing = easeInOutQuad, delay = 0 } = {}) =>\n        // method definition\n        {\n            let start = null;\n            let t;\n            let p;\n            let resting = true;\n            let reverse = false;\n            let target = null;\n\n            const interpolate = (ts, skipToEndState) => {\n                if (resting || target === null) return;\n\n                if (start === null) {\n                    start = ts;\n                }\n\n                if (ts - start < delay) return;\n\n                t = ts - start - delay;\n\n                if (t >= duration || skipToEndState) {\n                    t = 1;\n                    p = reverse ? 0 : 1;\n                    api.onupdate(p * target);\n                    api.oncomplete(p * target);\n                    resting = true;\n                } else {\n                    p = t / duration;\n                    api.onupdate((t >= 0 ? easing(reverse ? 1 - p : p) : 0) * target);\n                }\n            };\n\n            // need 'api' to call onupdate callback\n            const api = createObject({\n                interpolate,\n                target: {\n                    get: () => (reverse ? 0 : target),\n                    set: value => {\n                        // is initial value\n                        if (target === null) {\n                            target = value;\n                            api.onupdate(value);\n                            api.oncomplete(value);\n                            return;\n                        }\n\n                        // want to tween to a smaller value and have a current value\n                        if (value < target) {\n                            target = 1;\n                            reverse = true;\n                        } else {\n                            // not tweening to a smaller value\n                            reverse = false;\n                            target = value;\n                        }\n\n                        // let's go!\n                        resting = false;\n                        start = null;\n                    },\n                },\n                resting: {\n                    get: () => resting,\n                },\n                onupdate: value => {},\n                oncomplete: value => {},\n            });\n\n            return api;\n        };\n\nconst animator = {\n    spring,\n    tween,\n};\n\n/*\n { type: 'spring', stiffness: .5, damping: .75, mass: 10 };\n { translation: { type: 'spring', ... }, ... }\n { translation: { x: { type: 'spring', ... } } }\n*/\nconst createAnimator = (definition, category, property) => {\n    // default is single definition\n    // we check if transform is set, if so, we check if property is set\n    const def =\n        definition[category] && typeof definition[category][property] === 'object'\n            ? definition[category][property]\n            : definition[category] || definition;\n\n    const type = typeof def === 'string' ? def : def.type;\n    const props = typeof def === 'object' ? { ...def } : {};\n\n    return animator[type] ? animator[type](props) : null;\n};\n\nconst addGetSet = (keys, obj, props, overwrite = false) => {\n    obj = Array.isArray(obj) ? obj : [obj];\n    obj.forEach(o => {\n        keys.forEach(key => {\n            let name = key;\n            let getter = () => props[key];\n            let setter = value => (props[key] = value);\n\n            if (typeof key === 'object') {\n                name = key.key;\n                getter = key.getter || getter;\n                setter = key.setter || setter;\n            }\n\n            if (o[name] && !overwrite) {\n                return;\n            }\n\n            o[name] = {\n                get: getter,\n                set: setter,\n            };\n        });\n    });\n};\n\n// add to state,\n// add getters and setters to internal and external api (if not set)\n// setup animators\n\nconst animations = ({ mixinConfig, viewProps, viewInternalAPI, viewExternalAPI }) => {\n    // initial properties\n    const initialProps = { ...viewProps };\n\n    // list of all active animations\n    const animations = [];\n\n    // setup animators\n    forin(mixinConfig, (property, animation) => {\n        const animator = createAnimator(animation);\n        if (!animator) {\n            return;\n        }\n\n        // when the animator updates, update the view state value\n        animator.onupdate = value => {\n            viewProps[property] = value;\n        };\n\n        // set animator target\n        animator.target = initialProps[property];\n\n        // when value is set, set the animator target value\n        const prop = {\n            key: property,\n            setter: value => {\n                // if already at target, we done!\n                if (animator.target === value) {\n                    return;\n                }\n\n                animator.target = value;\n            },\n            getter: () => viewProps[property],\n        };\n\n        // add getters and setters\n        addGetSet([prop], [viewInternalAPI, viewExternalAPI], viewProps, true);\n\n        // add it to the list for easy updating from the _write method\n        animations.push(animator);\n    });\n\n    // expose internal write api\n    return {\n        write: ts => {\n            let skipToEndState = document.hidden;\n            let resting = true;\n            animations.forEach(animation => {\n                if (!animation.resting) resting = false;\n                animation.interpolate(ts, skipToEndState);\n            });\n            return resting;\n        },\n        destroy: () => {},\n    };\n};\n\nconst addEvent = element => (type, fn) => {\n    element.addEventListener(type, fn);\n};\n\nconst removeEvent = element => (type, fn) => {\n    element.removeEventListener(type, fn);\n};\n\n// mixin\nconst listeners = ({\n    mixinConfig,\n    viewProps,\n    viewInternalAPI,\n    viewExternalAPI,\n    viewState,\n    view,\n}) => {\n    const events = [];\n\n    const add = addEvent(view.element);\n    const remove = removeEvent(view.element);\n\n    viewExternalAPI.on = (type, fn) => {\n        events.push({\n            type,\n            fn,\n        });\n        add(type, fn);\n    };\n\n    viewExternalAPI.off = (type, fn) => {\n        events.splice(events.findIndex(event => event.type === type && event.fn === fn), 1);\n        remove(type, fn);\n    };\n\n    return {\n        write: () => {\n            // not busy\n            return true;\n        },\n        destroy: () => {\n            events.forEach(event => {\n                remove(event.type, event.fn);\n            });\n        },\n    };\n};\n\n// add to external api and link to props\n\nconst apis = ({ mixinConfig, viewProps, viewExternalAPI }) => {\n    addGetSet(mixinConfig, viewExternalAPI, viewProps);\n};\n\nconst isDefined = value => value != null;\n\n// add to state,\n// add getters and setters to internal and external api (if not set)\n// set initial state based on props in viewProps\n// apply as transforms each frame\n\nconst defaults = {\n    opacity: 1,\n    scaleX: 1,\n    scaleY: 1,\n    translateX: 0,\n    translateY: 0,\n    rotateX: 0,\n    rotateY: 0,\n    rotateZ: 0,\n    originX: 0,\n    originY: 0,\n};\n\nconst styles = ({ mixinConfig, viewProps, viewInternalAPI, viewExternalAPI, view }) => {\n    // initial props\n    const initialProps = { ...viewProps };\n\n    // current props\n    const currentProps = {};\n\n    // we will add those properties to the external API and link them to the viewState\n    addGetSet(mixinConfig, [viewInternalAPI, viewExternalAPI], viewProps);\n\n    // override rect on internal and external rect getter so it takes in account transforms\n    const getOffset = () => [viewProps['translateX'] || 0, viewProps['translateY'] || 0];\n    const getScale = () => [viewProps['scaleX'] || 0, viewProps['scaleY'] || 0];\n    const getRect = () =>\n        view.rect ? getViewRect(view.rect, view.childViews, getOffset(), getScale()) : null;\n    viewInternalAPI.rect = { get: getRect };\n    viewExternalAPI.rect = { get: getRect };\n\n    // apply view props\n    mixinConfig.forEach(key => {\n        viewProps[key] =\n            typeof initialProps[key] === 'undefined' ? defaults[key] : initialProps[key];\n    });\n\n    // expose api\n    return {\n        write: () => {\n            // see if props have changed\n            if (!propsHaveChanged(currentProps, viewProps)) {\n                return;\n            }\n\n            // moves element to correct position on screen\n            applyStyles(view.element, viewProps);\n\n            // store new transforms\n            Object.assign(currentProps, { ...viewProps });\n\n            // no longer busy\n            return true;\n        },\n        destroy: () => {},\n    };\n};\n\nconst propsHaveChanged = (currentProps, newProps) => {\n    // different amount of keys\n    if (Object.keys(currentProps).length !== Object.keys(newProps).length) {\n        return true;\n    }\n\n    // lets analyze the individual props\n    for (const prop in newProps) {\n        if (newProps[prop] !== currentProps[prop]) {\n            return true;\n        }\n    }\n\n    return false;\n};\n\nconst applyStyles = (\n    element,\n    {\n        opacity,\n        perspective,\n        translateX,\n        translateY,\n        scaleX,\n        scaleY,\n        rotateX,\n        rotateY,\n        rotateZ,\n        originX,\n        originY,\n        width,\n        height,\n    }\n) => {\n    let transforms = '';\n    let styles = '';\n\n    // handle transform origin\n    if (isDefined(originX) || isDefined(originY)) {\n        styles += `transform-origin: ${originX || 0}px ${originY || 0}px;`;\n    }\n\n    // transform order is relevant\n    // 0. perspective\n    if (isDefined(perspective)) {\n        transforms += `perspective(${perspective}px) `;\n    }\n\n    // 1. translate\n    if (isDefined(translateX) || isDefined(translateY)) {\n        transforms += `translate3d(${translateX || 0}px, ${translateY || 0}px, 0) `;\n    }\n\n    // 2. scale\n    if (isDefined(scaleX) || isDefined(scaleY)) {\n        transforms += `scale3d(${isDefined(scaleX) ? scaleX : 1}, ${\n            isDefined(scaleY) ? scaleY : 1\n        }, 1) `;\n    }\n\n    // 3. rotate\n    if (isDefined(rotateZ)) {\n        transforms += `rotateZ(${rotateZ}rad) `;\n    }\n\n    if (isDefined(rotateX)) {\n        transforms += `rotateX(${rotateX}rad) `;\n    }\n\n    if (isDefined(rotateY)) {\n        transforms += `rotateY(${rotateY}rad) `;\n    }\n\n    // add transforms\n    if (transforms.length) {\n        styles += `transform:${transforms};`;\n    }\n\n    // add opacity\n    if (isDefined(opacity)) {\n        styles += `opacity:${opacity};`;\n\n        // if we reach zero, we make the element inaccessible\n        if (opacity === 0) {\n            styles += `visibility:hidden;`;\n        }\n\n        // if we're below 100% opacity this element can't be clicked\n        if (opacity < 1) {\n            styles += `pointer-events:none;`;\n        }\n    }\n\n    // add height\n    if (isDefined(height)) {\n        styles += `height:${height}px;`;\n    }\n\n    // add width\n    if (isDefined(width)) {\n        styles += `width:${width}px;`;\n    }\n\n    // apply styles\n    const elementCurrentStyle = element.elementCurrentStyle || '';\n\n    // if new styles does not match current styles, lets update!\n    if (styles.length !== elementCurrentStyle.length || styles !== elementCurrentStyle) {\n        element.style.cssText = styles;\n        // store current styles so we can compare them to new styles later on\n        // _not_ getting the style value is faster\n        element.elementCurrentStyle = styles;\n    }\n};\n\nconst Mixins = {\n    styles,\n    listeners,\n    animations,\n    apis,\n};\n\nconst updateRect = (rect = {}, element = {}, style = {}) => {\n    if (!element.layoutCalculated) {\n        rect.paddingTop = parseInt(style.paddingTop, 10) || 0;\n        rect.marginTop = parseInt(style.marginTop, 10) || 0;\n        rect.marginRight = parseInt(style.marginRight, 10) || 0;\n        rect.marginBottom = parseInt(style.marginBottom, 10) || 0;\n        rect.marginLeft = parseInt(style.marginLeft, 10) || 0;\n        element.layoutCalculated = true;\n    }\n\n    rect.left = element.offsetLeft || 0;\n    rect.top = element.offsetTop || 0;\n    rect.width = element.offsetWidth || 0;\n    rect.height = element.offsetHeight || 0;\n\n    rect.right = rect.left + rect.width;\n    rect.bottom = rect.top + rect.height;\n\n    rect.scrollTop = element.scrollTop;\n\n    rect.hidden = element.offsetParent === null;\n\n    return rect;\n};\n\nconst createView =\n    // default view definition\n    ({\n        // element definition\n        tag = 'div',\n        name = null,\n        attributes = {},\n\n        // view interaction\n        read = () => {},\n        write = () => {},\n        create = () => {},\n        destroy = () => {},\n\n        // hooks\n        filterFrameActionsForChild = (child, actions) => actions,\n        didCreateView = () => {},\n        didWriteView = () => {},\n\n        // rect related\n        ignoreRect = false,\n        ignoreRectUpdate = false,\n\n        // mixins\n        mixins = [],\n    } = {}) => (\n        // each view requires reference to store\n        store,\n        // specific properties for this view\n        props = {}\n    ) => {\n        // root element should not be changed\n        const element = createElement(tag, `filepond--${name}`, attributes);\n\n        // style reference should also not be changed\n        const style = window.getComputedStyle(element, null);\n\n        // element rectangle\n        const rect = updateRect();\n        let frameRect = null;\n\n        // rest state\n        let isResting = false;\n\n        // pretty self explanatory\n        const childViews = [];\n\n        // loaded mixins\n        const activeMixins = [];\n\n        // references to created children\n        const ref = {};\n\n        // state used for each instance\n        const state = {};\n\n        // list of writers that will be called to update this view\n        const writers = [\n            write, // default writer\n        ];\n\n        const readers = [\n            read, // default reader\n        ];\n\n        const destroyers = [\n            destroy, // default destroy\n        ];\n\n        // core view methods\n        const getElement = () => element;\n        const getChildViews = () => childViews.concat();\n        const getReference = () => ref;\n        const createChildView = store => (view, props) => view(store, props);\n        const getRect = () => {\n            if (frameRect) {\n                return frameRect;\n            }\n            frameRect = getViewRect(rect, childViews, [0, 0], [1, 1]);\n            return frameRect;\n        };\n        const getStyle = () => style;\n\n        /**\n         * Read data from DOM\n         * @private\n         */\n        const _read = () => {\n            frameRect = null;\n\n            // read child views\n            childViews.forEach(child => child._read());\n\n            const shouldUpdate = !(ignoreRectUpdate && rect.width && rect.height);\n            if (shouldUpdate) {\n                updateRect(rect, element, style);\n            }\n\n            // readers\n            const api = { root: internalAPI, props, rect };\n            readers.forEach(reader => reader(api));\n        };\n\n        /**\n         * Write data to DOM\n         * @private\n         */\n        const _write = (ts, frameActions, shouldOptimize) => {\n            // if no actions, we assume that the view is resting\n            let resting = frameActions.length === 0;\n\n            // writers\n            writers.forEach(writer => {\n                const writerResting = writer({\n                    props,\n                    root: internalAPI,\n                    actions: frameActions,\n                    timestamp: ts,\n                    shouldOptimize,\n                });\n                if (writerResting === false) {\n                    resting = false;\n                }\n            });\n\n            // run mixins\n            activeMixins.forEach(mixin => {\n                // if one of the mixins is still busy after write operation, we are not resting\n                const mixinResting = mixin.write(ts);\n                if (mixinResting === false) {\n                    resting = false;\n                }\n            });\n\n            // updates child views that are currently attached to the DOM\n            childViews\n                .filter(child => !!child.element.parentNode)\n                .forEach(child => {\n                    // if a child view is not resting, we are not resting\n                    const childResting = child._write(\n                        ts,\n                        filterFrameActionsForChild(child, frameActions),\n                        shouldOptimize\n                    );\n                    if (!childResting) {\n                        resting = false;\n                    }\n                });\n\n            // append new elements to DOM and update those\n            childViews\n                //.filter(child => !child.element.parentNode)\n                .forEach((child, index) => {\n                    // skip\n                    if (child.element.parentNode) {\n                        return;\n                    }\n\n                    // append to DOM\n                    internalAPI.appendChild(child.element, index);\n\n                    // call read (need to know the size of these elements)\n                    child._read();\n\n                    // re-call write\n                    child._write(\n                        ts,\n                        filterFrameActionsForChild(child, frameActions),\n                        shouldOptimize\n                    );\n\n                    // we just added somthing to the dom, no rest\n                    resting = false;\n                });\n\n            // update resting state\n            isResting = resting;\n\n            didWriteView({\n                props,\n                root: internalAPI,\n                actions: frameActions,\n                timestamp: ts,\n            });\n\n            // let parent know if we are resting\n            return resting;\n        };\n\n        const _destroy = () => {\n            activeMixins.forEach(mixin => mixin.destroy());\n            destroyers.forEach(destroyer => {\n                destroyer({ root: internalAPI, props });\n            });\n            childViews.forEach(child => child._destroy());\n        };\n\n        // sharedAPI\n        const sharedAPIDefinition = {\n            element: {\n                get: getElement,\n            },\n            style: {\n                get: getStyle,\n            },\n            childViews: {\n                get: getChildViews,\n            },\n        };\n\n        // private API definition\n        const internalAPIDefinition = {\n            ...sharedAPIDefinition,\n            rect: {\n                get: getRect,\n            },\n\n            // access to custom children references\n            ref: {\n                get: getReference,\n            },\n\n            // dom modifiers\n            is: needle => name === needle,\n            appendChild: appendChild(element),\n            createChildView: createChildView(store),\n            linkView: view => {\n                childViews.push(view);\n                return view;\n            },\n            unlinkView: view => {\n                childViews.splice(childViews.indexOf(view), 1);\n            },\n            appendChildView: appendChildView(element, childViews),\n            removeChildView: removeChildView(element, childViews),\n            registerWriter: writer => writers.push(writer),\n            registerReader: reader => readers.push(reader),\n            registerDestroyer: destroyer => destroyers.push(destroyer),\n            invalidateLayout: () => (element.layoutCalculated = false),\n\n            // access to data store\n            dispatch: store.dispatch,\n            query: store.query,\n        };\n\n        // public view API methods\n        const externalAPIDefinition = {\n            element: {\n                get: getElement,\n            },\n            childViews: {\n                get: getChildViews,\n            },\n            rect: {\n                get: getRect,\n            },\n            resting: {\n                get: () => isResting,\n            },\n            isRectIgnored: () => ignoreRect,\n            _read,\n            _write,\n            _destroy,\n        };\n\n        // mixin API methods\n        const mixinAPIDefinition = {\n            ...sharedAPIDefinition,\n            rect: {\n                get: () => rect,\n            },\n        };\n\n        // add mixin functionality\n        Object.keys(mixins)\n            .sort((a, b) => {\n                // move styles to the back of the mixin list (so adjustments of other mixins are applied to the props correctly)\n                if (a === 'styles') {\n                    return 1;\n                } else if (b === 'styles') {\n                    return -1;\n                }\n                return 0;\n            })\n            .forEach(key => {\n                const mixinAPI = Mixins[key]({\n                    mixinConfig: mixins[key],\n                    viewProps: props,\n                    viewState: state,\n                    viewInternalAPI: internalAPIDefinition,\n                    viewExternalAPI: externalAPIDefinition,\n                    view: createObject(mixinAPIDefinition),\n                });\n\n                if (mixinAPI) {\n                    activeMixins.push(mixinAPI);\n                }\n            });\n\n        // construct private api\n        const internalAPI = createObject(internalAPIDefinition);\n\n        // create the view\n        create({\n            root: internalAPI,\n            props,\n        });\n\n        // append created child views to root node\n        const childCount = getChildCount(element); // need to know the current child count so appending happens in correct order\n        childViews.forEach((child, index) => {\n            internalAPI.appendChild(child.element, childCount + index);\n        });\n\n        // call did create\n        didCreateView(internalAPI);\n\n        // expose public api\n        return createObject(externalAPIDefinition);\n    };\n\nconst createPainter = (read, write, fps = 60) => {\n    const name = '__framePainter';\n\n    // set global painter\n    if (window[name]) {\n        window[name].readers.push(read);\n        window[name].writers.push(write);\n        return;\n    }\n\n    window[name] = {\n        readers: [read],\n        writers: [write],\n    };\n\n    const painter = window[name];\n\n    const interval = 1000 / fps;\n    let last = null;\n    let id = null;\n    let requestTick = null;\n    let cancelTick = null;\n\n    const setTimerType = () => {\n        if (document.hidden) {\n            requestTick = () => window.setTimeout(() => tick(performance.now()), interval);\n            cancelTick = () => window.clearTimeout(id);\n        } else {\n            requestTick = () => window.requestAnimationFrame(tick);\n            cancelTick = () => window.cancelAnimationFrame(id);\n        }\n    };\n\n    document.addEventListener('visibilitychange', () => {\n        if (cancelTick) cancelTick();\n        setTimerType();\n        tick(performance.now());\n    });\n\n    const tick = ts => {\n        // queue next tick\n        id = requestTick(tick);\n\n        // limit fps\n        if (!last) {\n            last = ts;\n        }\n\n        const delta = ts - last;\n\n        if (delta <= interval) {\n            // skip frame\n            return;\n        }\n\n        // align next frame\n        last = ts - (delta % interval);\n\n        // update view\n        painter.readers.forEach(read => read());\n        painter.writers.forEach(write => write(ts));\n    };\n\n    setTimerType();\n    tick(performance.now());\n\n    return {\n        pause: () => {\n            cancelTick(id);\n        },\n    };\n};\n\nconst createRoute = (routes, fn) => ({ root, props, actions = [], timestamp, shouldOptimize }) => {\n    actions\n        .filter(action => routes[action.type])\n        .forEach(action =>\n            routes[action.type]({ root, props, action: action.data, timestamp, shouldOptimize })\n        );\n    if (fn) {\n        fn({ root, props, actions, timestamp, shouldOptimize });\n    }\n};\n\nconst insertBefore = (newNode, referenceNode) =>\n    referenceNode.parentNode.insertBefore(newNode, referenceNode);\n\nconst insertAfter = (newNode, referenceNode) => {\n    return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);\n};\n\nconst isArray = value => Array.isArray(value);\n\nconst isEmpty = value => value == null;\n\nconst trim = str => str.trim();\n\nconst toString = value => '' + value;\n\nconst toArray = (value, splitter = ',') => {\n    if (isEmpty(value)) {\n        return [];\n    }\n    if (isArray(value)) {\n        return value;\n    }\n    return toString(value)\n        .split(splitter)\n        .map(trim)\n        .filter(str => str.length);\n};\n\nconst isBoolean = value => typeof value === 'boolean';\n\nconst toBoolean = value => (isBoolean(value) ? value : value === 'true');\n\nconst isString = value => typeof value === 'string';\n\nconst toNumber = value =>\n    isNumber(value) ? value : isString(value) ? toString(value).replace(/[a-z]+/gi, '') : 0;\n\nconst toInt = value => parseInt(toNumber(value), 10);\n\nconst toFloat = value => parseFloat(toNumber(value));\n\nconst isInt = value => isNumber(value) && isFinite(value) && Math.floor(value) === value;\n\nconst toBytes = (value, base = 1000) => {\n    // is in bytes\n    if (isInt(value)) {\n        return value;\n    }\n\n    // is natural file size\n    let naturalFileSize = toString(value).trim();\n\n    // if is value in megabytes\n    if (/MB$/i.test(naturalFileSize)) {\n        naturalFileSize = naturalFileSize.replace(/MB$i/, '').trim();\n        return toInt(naturalFileSize) * base * base;\n    }\n\n    // if is value in kilobytes\n    if (/KB/i.test(naturalFileSize)) {\n        naturalFileSize = naturalFileSize.replace(/KB$i/, '').trim();\n        return toInt(naturalFileSize) * base;\n    }\n\n    return toInt(naturalFileSize);\n};\n\nconst isFunction = value => typeof value === 'function';\n\nconst toFunctionReference = string => {\n    let ref = self;\n    let levels = string.split('.');\n    let level = null;\n    while ((level = levels.shift())) {\n        ref = ref[level];\n        if (!ref) {\n            return null;\n        }\n    }\n    return ref;\n};\n\nconst methods = {\n    process: 'POST',\n    patch: 'PATCH',\n    revert: 'DELETE',\n    fetch: 'GET',\n    restore: 'GET',\n    load: 'GET',\n};\n\nconst createServerAPI = outline => {\n    const api = {};\n\n    api.url = isString(outline) ? outline : outline.url || '';\n    api.timeout = outline.timeout ? parseInt(outline.timeout, 10) : 0;\n    api.headers = outline.headers ? outline.headers : {};\n\n    forin(methods, key => {\n        api[key] = createAction(key, outline[key], methods[key], api.timeout, api.headers);\n    });\n\n    // remove process if no url or process on outline\n    api.process = outline.process || isString(outline) || outline.url ? api.process : null;\n\n    // special treatment for remove\n    api.remove = outline.remove || null;\n\n    // remove generic headers from api object\n    delete api.headers;\n\n    return api;\n};\n\nconst createAction = (name, outline, method, timeout, headers) => {\n    // is explicitely set to null so disable\n    if (outline === null) {\n        return null;\n    }\n\n    // if is custom function, done! Dev handles everything.\n    if (typeof outline === 'function') {\n        return outline;\n    }\n\n    // build action object\n    const action = {\n        url: method === 'GET' || method === 'PATCH' ? `?${name}=` : '',\n        method,\n        headers,\n        withCredentials: false,\n        timeout,\n        onload: null,\n        ondata: null,\n        onerror: null,\n    };\n\n    // is a single url\n    if (isString(outline)) {\n        action.url = outline;\n        return action;\n    }\n\n    // overwrite\n    Object.assign(action, outline);\n\n    // see if should reformat headers;\n    if (isString(action.headers)) {\n        const parts = action.headers.split(/:(.+)/);\n        action.headers = {\n            header: parts[0],\n            value: parts[1],\n        };\n    }\n\n    // if is bool withCredentials\n    action.withCredentials = toBoolean(action.withCredentials);\n\n    return action;\n};\n\nconst toServerAPI = value => createServerAPI(value);\n\nconst isNull = value => value === null;\n\nconst isObject = value => typeof value === 'object' && value !== null;\n\nconst isAPI = value => {\n    return (\n        isObject(value) &&\n        isString(value.url) &&\n        isObject(value.process) &&\n        isObject(value.revert) &&\n        isObject(value.restore) &&\n        isObject(value.fetch)\n    );\n};\n\nconst getType = value => {\n    if (isArray(value)) {\n        return 'array';\n    }\n\n    if (isNull(value)) {\n        return 'null';\n    }\n\n    if (isInt(value)) {\n        return 'int';\n    }\n\n    if (/^[0-9]+ ?(?:GB|MB|KB)$/gi.test(value)) {\n        return 'bytes';\n    }\n\n    if (isAPI(value)) {\n        return 'api';\n    }\n\n    return typeof value;\n};\n\nconst replaceSingleQuotes = str =>\n    str\n        .replace(/{\\s*'/g, '{\"')\n        .replace(/'\\s*}/g, '\"}')\n        .replace(/'\\s*:/g, '\":')\n        .replace(/:\\s*'/g, ':\"')\n        .replace(/,\\s*'/g, ',\"')\n        .replace(/'\\s*,/g, '\",');\n\nconst conversionTable = {\n    array: toArray,\n    boolean: toBoolean,\n    int: value => (getType(value) === 'bytes' ? toBytes(value) : toInt(value)),\n    number: toFloat,\n    float: toFloat,\n    bytes: toBytes,\n    string: value => (isFunction(value) ? value : toString(value)),\n    function: value => toFunctionReference(value),\n    serverapi: toServerAPI,\n    object: value => {\n        try {\n            return JSON.parse(replaceSingleQuotes(value));\n        } catch (e) {\n            return null;\n        }\n    },\n};\n\nconst convertTo = (value, type) => conversionTable[type](value);\n\nconst getValueByType = (newValue, defaultValue, valueType) => {\n    // can always assign default value\n    if (newValue === defaultValue) {\n        return newValue;\n    }\n\n    // get the type of the new value\n    let newValueType = getType(newValue);\n\n    // is valid type?\n    if (newValueType !== valueType) {\n        // is string input, let's attempt to convert\n        const convertedValue = convertTo(newValue, valueType);\n\n        // what is the type now\n        newValueType = getType(convertedValue);\n\n        // no valid conversions found\n        if (convertedValue === null) {\n            throw `Trying to assign value with incorrect type to \"${option}\", allowed type: \"${valueType}\"`;\n        } else {\n            newValue = convertedValue;\n        }\n    }\n\n    // assign new value\n    return newValue;\n};\n\nconst createOption = (defaultValue, valueType) => {\n    let currentValue = defaultValue;\n    return {\n        enumerable: true,\n        get: () => currentValue,\n        set: newValue => {\n            currentValue = getValueByType(newValue, defaultValue, valueType);\n        },\n    };\n};\n\nconst createOptions = options => {\n    const obj = {};\n    forin(options, prop => {\n        const optionDefinition = options[prop];\n        obj[prop] = createOption(optionDefinition[0], optionDefinition[1]);\n    });\n    return createObject(obj);\n};\n\nconst createInitialState = options => ({\n    // model\n    items: [],\n\n    // timeout used for calling update items\n    listUpdateTimeout: null,\n\n    // timeout used for stacking metadata updates\n    itemUpdateTimeout: null,\n\n    // queue of items waiting to be processed\n    processingQueue: [],\n\n    // options\n    options: createOptions(options),\n});\n\nconst fromCamels = (string, separator = '-') =>\n    string\n        .split(/(?=[A-Z])/)\n        .map(part => part.toLowerCase())\n        .join(separator);\n\nconst createOptionAPI = (store, options) => {\n    const obj = {};\n    forin(options, key => {\n        obj[key] = {\n            get: () => store.getState().options[key],\n            set: value => {\n                store.dispatch(`SET_${fromCamels(key, '_').toUpperCase()}`, {\n                    value,\n                });\n            },\n        };\n    });\n    return obj;\n};\n\nconst createOptionActions = options => (dispatch, query, state) => {\n    const obj = {};\n    forin(options, key => {\n        const name = fromCamels(key, '_').toUpperCase();\n\n        obj[`SET_${name}`] = action => {\n            try {\n                state.options[key] = action.value;\n            } catch (e) {\n                // nope, failed\n            }\n\n            // we successfully set the value of this option\n            dispatch(`DID_SET_${name}`, { value: state.options[key] });\n        };\n    });\n    return obj;\n};\n\nconst createOptionQueries = options => state => {\n    const obj = {};\n    forin(options, key => {\n        obj[`GET_${fromCamels(key, '_').toUpperCase()}`] = action => state.options[key];\n    });\n    return obj;\n};\n\nconst InteractionMethod = {\n    API: 1,\n    DROP: 2,\n    BROWSE: 3,\n    PASTE: 4,\n    NONE: 5,\n};\n\nconst getUniqueId = () =>\n    Math.random()\n        .toString(36)\n        .substring(2, 11);\n\nconst arrayRemove = (arr, index) => arr.splice(index, 1);\n\nconst run = (cb, sync) => {\n    if (sync) {\n        cb();\n    } else if (document.hidden) {\n        Promise.resolve(1).then(cb);\n    } else {\n        setTimeout(cb, 0);\n    }\n};\n\nconst on = () => {\n    const listeners = [];\n    const off = (event, cb) => {\n        arrayRemove(\n            listeners,\n            listeners.findIndex(listener => listener.event === event && (listener.cb === cb || !cb))\n        );\n    };\n    const fire = (event, args, sync) => {\n        listeners\n            .filter(listener => listener.event === event)\n            .map(listener => listener.cb)\n            .forEach(cb => run(() => cb(...args), sync));\n    };\n    return {\n        fireSync: (event, ...args) => {\n            fire(event, args, true);\n        },\n        fire: (event, ...args) => {\n            fire(event, args, false);\n        },\n        on: (event, cb) => {\n            listeners.push({ event, cb });\n        },\n        onOnce: (event, cb) => {\n            listeners.push({\n                event,\n                cb: (...args) => {\n                    off(event, cb);\n                    cb(...args);\n                },\n            });\n        },\n        off,\n    };\n};\n\nconst copyObjectPropertiesToObject = (src, target, excluded) => {\n    Object.getOwnPropertyNames(src)\n        .filter(property => !excluded.includes(property))\n        .forEach(key =>\n            Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(src, key))\n        );\n};\n\nconst PRIVATE = [\n    'fire',\n    'process',\n    'revert',\n    'load',\n    'on',\n    'off',\n    'onOnce',\n    'retryLoad',\n    'extend',\n    'archive',\n    'archived',\n    'release',\n    'released',\n    'requestProcessing',\n    'freeze',\n];\n\nconst createItemAPI = item => {\n    const api = {};\n    copyObjectPropertiesToObject(item, api, PRIVATE);\n    return api;\n};\n\nconst removeReleasedItems = items => {\n    items.forEach((item, index) => {\n        if (item.released) {\n            arrayRemove(items, index);\n        }\n    });\n};\n\nconst ItemStatus = {\n    INIT: 1,\n    IDLE: 2,\n    PROCESSING_QUEUED: 9,\n    PROCESSING: 3,\n    PROCESSING_COMPLETE: 5,\n    PROCESSING_ERROR: 6,\n    PROCESSING_REVERT_ERROR: 10,\n    LOADING: 7,\n    LOAD_ERROR: 8,\n};\n\nconst FileOrigin = {\n    INPUT: 1,\n    LIMBO: 2,\n    LOCAL: 3,\n};\n\nconst getNonNumeric = str => /[^0-9]+/.exec(str);\n\nconst getDecimalSeparator = () => getNonNumeric((1.1).toLocaleString())[0];\n\nconst getThousandsSeparator = () => {\n    // Added for browsers that do not return the thousands separator (happend on native browser Android 4.4.4)\n    // We check against the normal toString output and if they're the same return a comma when decimal separator is a dot\n    const decimalSeparator = getDecimalSeparator();\n    const thousandsStringWithSeparator = (1000.0).toLocaleString();\n    const thousandsStringWithoutSeparator = (1000.0).toString();\n    if (thousandsStringWithSeparator !== thousandsStringWithoutSeparator) {\n        return getNonNumeric(thousandsStringWithSeparator)[0];\n    }\n    return decimalSeparator === '.' ? ',' : '.';\n};\n\nconst Type = {\n    BOOLEAN: 'boolean',\n    INT: 'int',\n    NUMBER: 'number',\n    STRING: 'string',\n    ARRAY: 'array',\n    OBJECT: 'object',\n    FUNCTION: 'function',\n    ACTION: 'action',\n    SERVER_API: 'serverapi',\n    REGEX: 'regex',\n};\n\n// all registered filters\nconst filters = [];\n\n// loops over matching filters and passes options to each filter, returning the mapped results\nconst applyFilterChain = (key, value, utils) =>\n    new Promise((resolve, reject) => {\n        // find matching filters for this key\n        const matchingFilters = filters.filter(f => f.key === key).map(f => f.cb);\n\n        // resolve now\n        if (matchingFilters.length === 0) {\n            resolve(value);\n            return;\n        }\n\n        // first filter to kick things of\n        const initialFilter = matchingFilters.shift();\n\n        // chain filters\n        matchingFilters\n            .reduce(\n                // loop over promises passing value to next promise\n                (current, next) => current.then(value => next(value, utils)),\n\n                // call initial filter, will return a promise\n                initialFilter(value, utils)\n\n                // all executed\n            )\n            .then(value => resolve(value))\n            .catch(error => reject(error));\n    });\n\nconst applyFilters = (key, value, utils) =>\n    filters.filter(f => f.key === key).map(f => f.cb(value, utils));\n\n// adds a new filter to the list\nconst addFilter = (key, cb) => filters.push({ key, cb });\n\nconst extendDefaultOptions = additionalOptions => Object.assign(defaultOptions, additionalOptions);\n\nconst getOptions = () => ({ ...defaultOptions });\n\nconst setOptions = opts => {\n    forin(opts, (key, value) => {\n        // key does not exist, so this option cannot be set\n        if (!defaultOptions[key]) {\n            return;\n        }\n        defaultOptions[key][0] = getValueByType(\n            value,\n            defaultOptions[key][0],\n            defaultOptions[key][1]\n        );\n    });\n};\n\n// default options on app\nconst defaultOptions = {\n    // the id to add to the root element\n    id: [null, Type.STRING],\n\n    // input field name to use\n    name: ['filepond', Type.STRING],\n\n    // disable the field\n    disabled: [false, Type.BOOLEAN],\n\n    // classname to put on wrapper\n    className: [null, Type.STRING],\n\n    // is the field required\n    required: [false, Type.BOOLEAN],\n\n    // Allow media capture when value is set\n    captureMethod: [null, Type.STRING],\n    // - \"camera\", \"microphone\" or \"camcorder\",\n    // - Does not work with multiple on apple devices\n    // - If set, acceptedFileTypes must be made to match with media wildcard \"image/*\", \"audio/*\" or \"video/*\"\n\n    // sync `acceptedFileTypes` property with `accept` attribute\n    allowSyncAcceptAttribute: [true, Type.BOOLEAN],\n\n    // Feature toggles\n    allowDrop: [true, Type.BOOLEAN], // Allow dropping of files\n    allowBrowse: [true, Type.BOOLEAN], // Allow browsing the file system\n    allowPaste: [true, Type.BOOLEAN], // Allow pasting files\n    allowMultiple: [false, Type.BOOLEAN], // Allow multiple files (disabled by default, as multiple attribute is also required on input to allow multiple)\n    allowReplace: [true, Type.BOOLEAN], // Allow dropping a file on other file to replace it (only works when multiple is set to false)\n    allowRevert: [true, Type.BOOLEAN], // Allows user to revert file upload\n    allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file\n    allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button\n    allowReorder: [false, Type.BOOLEAN], // Allow reordering of files\n    allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)\n\n    // Try store file if `server` not set\n    storeAsFile: [false, Type.BOOLEAN],\n\n    // Revert mode\n    forceRevert: [false, Type.BOOLEAN], // Set to 'force' to require the file to be reverted before removal\n\n    // Input requirements\n    maxFiles: [null, Type.INT], // Max number of files\n    checkValidity: [false, Type.BOOLEAN], // Enables custom validity messages\n\n    // Where to put file\n    itemInsertLocationFreedom: [true, Type.BOOLEAN], // Set to false to always add items to begin or end of list\n    itemInsertLocation: ['before', Type.STRING], // Default index in list to add items that have been dropped at the top of the list\n    itemInsertInterval: [75, Type.INT],\n\n    // Drag 'n Drop related\n    dropOnPage: [false, Type.BOOLEAN], // Allow dropping of files anywhere on page (prevents browser from opening file if dropped outside of Up)\n    dropOnElement: [true, Type.BOOLEAN], // Drop needs to happen on element (set to false to also load drops outside of Up)\n    dropValidation: [false, Type.BOOLEAN], // Enable or disable validating files on drop\n    ignoredFiles: [['.ds_store', 'thumbs.db', 'desktop.ini'], Type.ARRAY],\n\n    // Upload related\n    instantUpload: [true, Type.BOOLEAN], // Should upload files immediately on drop\n    maxParallelUploads: [2, Type.INT], // Maximum files to upload in parallel\n    allowMinimumUploadDuration: [true, Type.BOOLEAN], // if true uploads take at least 750 ms, this ensures the user sees the upload progress giving trust the upload actually happened\n\n    // Chunks\n    chunkUploads: [false, Type.BOOLEAN], // Enable chunked uploads\n    chunkForce: [false, Type.BOOLEAN], // Force use of chunk uploads even for files smaller than chunk size\n    chunkSize: [5000000, Type.INT], // Size of chunks (5MB default)\n    chunkRetryDelays: [[500, 1000, 3000], Type.ARRAY], // Amount of times to retry upload of a chunk when it fails\n\n    // The server api end points to use for uploading (see docs)\n    server: [null, Type.SERVER_API],\n\n    // File size calculations, can set to 1024, this is only used for display, properties use file size base 1000\n    fileSizeBase: [1000, Type.INT],\n\n    // Labels and status messages\n    labelFileSizeBytes: ['bytes', Type.STRING],\n    labelFileSizeKilobytes: ['KB', Type.STRING],\n    labelFileSizeMegabytes: ['MB', Type.STRING],\n    labelFileSizeGigabytes: ['GB', Type.STRING],\n\n    labelDecimalSeparator: [getDecimalSeparator(), Type.STRING], // Default is locale separator\n    labelThousandsSeparator: [getThousandsSeparator(), Type.STRING], // Default is locale separator\n\n    labelIdle: [\n        'Drag & Drop your files or <span class=\"filepond--label-action\">Browse</span>',\n        Type.STRING,\n    ],\n    labelInvalidField: ['Field contains invalid files', Type.STRING],\n    labelFileWaitingForSize: ['Waiting for size', Type.STRING],\n    labelFileSizeNotAvailable: ['Size not available', Type.STRING],\n    labelFileCountSingular: ['file in list', Type.STRING],\n    labelFileCountPlural: ['files in list', Type.STRING],\n    labelFileLoading: ['Loading', Type.STRING],\n    labelFileAdded: ['Added', Type.STRING], // assistive only\n    labelFileLoadError: ['Error during load', Type.STRING],\n    labelFileRemoved: ['Removed', Type.STRING], // assistive only\n    labelFileRemoveError: ['Error during remove', Type.STRING],\n    labelFileProcessing: ['Uploading', Type.STRING],\n    labelFileProcessingComplete: ['Upload complete', Type.STRING],\n    labelFileProcessingAborted: ['Upload cancelled', Type.STRING],\n    labelFileProcessingError: ['Error during upload', Type.STRING],\n    labelFileProcessingRevertError: ['Error during revert', Type.STRING],\n\n    labelTapToCancel: ['tap to cancel', Type.STRING],\n    labelTapToRetry: ['tap to retry', Type.STRING],\n    labelTapToUndo: ['tap to undo', Type.STRING],\n\n    labelButtonRemoveItem: ['Remove', Type.STRING],\n    labelButtonAbortItemLoad: ['Abort', Type.STRING],\n    labelButtonRetryItemLoad: ['Retry', Type.STRING],\n    labelButtonAbortItemProcessing: ['Cancel', Type.STRING],\n    labelButtonUndoItemProcessing: ['Undo', Type.STRING],\n    labelButtonRetryItemProcessing: ['Retry', Type.STRING],\n    labelButtonProcessItem: ['Upload', Type.STRING],\n\n    // make sure width and height plus viewpox are even numbers so icons are nicely centered\n    iconRemove: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.586 13l-2.293 2.293a1 1 0 0 0 1.414 1.414L13 14.414l2.293 2.293a1 1 0 0 0 1.414-1.414L14.414 13l2.293-2.293a1 1 0 0 0-1.414-1.414L13 11.586l-2.293-2.293a1 1 0 0 0-1.414 1.414L11.586 13z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconProcess: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M14 10.414v3.585a1 1 0 0 1-2 0v-3.585l-1.293 1.293a1 1 0 0 1-1.414-1.415l3-3a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1-1.414 1.415L14 10.414zM9 18a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2H9z\" fill=\"currentColor\" fill-rule=\"evenodd\"/></svg>',\n        Type.STRING,\n    ],\n    iconRetry: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10.81 9.185l-.038.02A4.997 4.997 0 0 0 8 13.683a5 5 0 0 0 5 5 5 5 0 0 0 5-5 1 1 0 0 1 2 0A7 7 0 1 1 9.722 7.496l-.842-.21a.999.999 0 1 1 .484-1.94l3.23.806c.535.133.86.675.73 1.21l-.804 3.233a.997.997 0 0 1-1.21.73.997.997 0 0 1-.73-1.21l.23-.928v-.002z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconUndo: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.185 10.81l.02-.038A4.997 4.997 0 0 1 13.683 8a5 5 0 0 1 5 5 5 5 0 0 1-5 5 1 1 0 0 0 0 2A7 7 0 1 0 7.496 9.722l-.21-.842a.999.999 0 1 0-1.94.484l.806 3.23c.133.535.675.86 1.21.73l3.233-.803a.997.997 0 0 0 .73-1.21.997.997 0 0 0-1.21-.73l-.928.23-.002-.001z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconDone: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M18.293 9.293a1 1 0 0 1 1.414 1.414l-7.002 7a1 1 0 0 1-1.414 0l-3.998-4a1 1 0 1 1 1.414-1.414L12 15.586l6.294-6.293z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n\n    // event handlers\n    oninit: [null, Type.FUNCTION],\n    onwarning: [null, Type.FUNCTION],\n    onerror: [null, Type.FUNCTION],\n    onactivatefile: [null, Type.FUNCTION],\n    oninitfile: [null, Type.FUNCTION],\n    onaddfilestart: [null, Type.FUNCTION],\n    onaddfileprogress: [null, Type.FUNCTION],\n    onaddfile: [null, Type.FUNCTION],\n    onprocessfilestart: [null, Type.FUNCTION],\n    onprocessfileprogress: [null, Type.FUNCTION],\n    onprocessfileabort: [null, Type.FUNCTION],\n    onprocessfilerevert: [null, Type.FUNCTION],\n    onprocessfile: [null, Type.FUNCTION],\n    onprocessfiles: [null, Type.FUNCTION],\n    onremovefile: [null, Type.FUNCTION],\n    onpreparefile: [null, Type.FUNCTION],\n    onupdatefiles: [null, Type.FUNCTION],\n    onreorderfiles: [null, Type.FUNCTION],\n\n    // hooks\n    beforeDropFile: [null, Type.FUNCTION],\n    beforeAddFile: [null, Type.FUNCTION],\n    beforeRemoveFile: [null, Type.FUNCTION],\n    beforePrepareFile: [null, Type.FUNCTION],\n\n    // styles\n    stylePanelLayout: [null, Type.STRING], // null 'integrated', 'compact', 'circle'\n    stylePanelAspectRatio: [null, Type.STRING], // null or '3:2' or 1\n    styleItemPanelAspectRatio: [null, Type.STRING],\n    styleButtonRemoveItemPosition: ['left', Type.STRING],\n    styleButtonProcessItemPosition: ['right', Type.STRING],\n    styleLoadIndicatorPosition: ['right', Type.STRING],\n    styleProgressIndicatorPosition: ['right', Type.STRING],\n    styleButtonRemoveItemAlign: [false, Type.BOOLEAN],\n\n    // custom initial files array\n    files: [[], Type.ARRAY],\n\n    // show support by displaying credits\n    credits: [['https://filepond.com', 'Powered by FilePond'], Type.ARRAY],\n};\n\nconst getItemByQuery = (items, query) => {\n    // just return first index\n    if (isEmpty(query)) {\n        return items[0] || null;\n    }\n\n    // query is index\n    if (isInt(query)) {\n        return items[query] || null;\n    }\n\n    // if query is item, get the id\n    if (typeof query === 'object') {\n        query = query.id;\n    }\n\n    // assume query is a string and return item by id\n    return items.find(item => item.id === query) || null;\n};\n\nconst getNumericAspectRatioFromString = aspectRatio => {\n    if (isEmpty(aspectRatio)) {\n        return aspectRatio;\n    }\n    if (/:/.test(aspectRatio)) {\n        const parts = aspectRatio.split(':');\n        return parts[1] / parts[0];\n    }\n    return parseFloat(aspectRatio);\n};\n\nconst getActiveItems = items => items.filter(item => !item.archived);\n\nconst Status = {\n    EMPTY: 0,\n    IDLE: 1, // waiting\n    ERROR: 2, // a file is in error state\n    BUSY: 3, // busy processing or loading\n    READY: 4, // all files uploaded\n};\n\nlet res = null;\nconst canUpdateFileInput = () => {\n    if (res === null) {\n        try {\n            const dataTransfer = new DataTransfer();\n            dataTransfer.items.add(new File(['hello world'], 'This_Works.txt'));\n            const el = document.createElement('input');\n            el.setAttribute('type', 'file');\n            el.files = dataTransfer.files;\n            res = el.files.length === 1;\n        } catch (err) {\n            res = false;\n        }\n    }\n    return res;\n};\n\nconst ITEM_ERROR = [\n    ItemStatus.LOAD_ERROR,\n    ItemStatus.PROCESSING_ERROR,\n    ItemStatus.PROCESSING_REVERT_ERROR,\n];\nconst ITEM_BUSY = [\n    ItemStatus.LOADING,\n    ItemStatus.PROCESSING,\n    ItemStatus.PROCESSING_QUEUED,\n    ItemStatus.INIT,\n];\nconst ITEM_READY = [ItemStatus.PROCESSING_COMPLETE];\n\nconst isItemInErrorState = item => ITEM_ERROR.includes(item.status);\nconst isItemInBusyState = item => ITEM_BUSY.includes(item.status);\nconst isItemInReadyState = item => ITEM_READY.includes(item.status);\n\nconst isAsync = state =>\n    isObject(state.options.server) &&\n    (isObject(state.options.server.process) || isFunction(state.options.server.process));\n\nconst queries = state => ({\n    GET_STATUS: () => {\n        const items = getActiveItems(state.items);\n\n        const { EMPTY, ERROR, BUSY, IDLE, READY } = Status;\n\n        if (items.length === 0) return EMPTY;\n\n        if (items.some(isItemInErrorState)) return ERROR;\n\n        if (items.some(isItemInBusyState)) return BUSY;\n\n        if (items.some(isItemInReadyState)) return READY;\n\n        return IDLE;\n    },\n\n    GET_ITEM: query => getItemByQuery(state.items, query),\n\n    GET_ACTIVE_ITEM: query => getItemByQuery(getActiveItems(state.items), query),\n\n    GET_ACTIVE_ITEMS: () => getActiveItems(state.items),\n\n    GET_ITEMS: () => state.items,\n\n    GET_ITEM_NAME: query => {\n        const item = getItemByQuery(state.items, query);\n        return item ? item.filename : null;\n    },\n\n    GET_ITEM_SIZE: query => {\n        const item = getItemByQuery(state.items, query);\n        return item ? item.fileSize : null;\n    },\n\n    GET_STYLES: () =>\n        Object.keys(state.options)\n            .filter(key => /^style/.test(key))\n            .map(option => ({\n                name: option,\n                value: state.options[option],\n            })),\n\n    GET_PANEL_ASPECT_RATIO: () => {\n        const isShapeCircle = /circle/.test(state.options.stylePanelLayout);\n        const aspectRatio = isShapeCircle\n            ? 1\n            : getNumericAspectRatioFromString(state.options.stylePanelAspectRatio);\n        return aspectRatio;\n    },\n\n    GET_ITEM_PANEL_ASPECT_RATIO: () => state.options.styleItemPanelAspectRatio,\n\n    GET_ITEMS_BY_STATUS: status =>\n        getActiveItems(state.items).filter(item => item.status === status),\n\n    GET_TOTAL_ITEMS: () => getActiveItems(state.items).length,\n\n    SHOULD_UPDATE_FILE_INPUT: () =>\n        state.options.storeAsFile && canUpdateFileInput() && !isAsync(state),\n\n    IS_ASYNC: () => isAsync(state),\n\n    GET_FILE_SIZE_LABELS: query => ({\n        labelBytes: query('GET_LABEL_FILE_SIZE_BYTES') || undefined,\n        labelKilobytes: query('GET_LABEL_FILE_SIZE_KILOBYTES') || undefined,\n        labelMegabytes: query('GET_LABEL_FILE_SIZE_MEGABYTES') || undefined,\n        labelGigabytes: query('GET_LABEL_FILE_SIZE_GIGABYTES') || undefined,\n    }),\n});\n\nconst hasRoomForItem = state => {\n    const count = getActiveItems(state.items).length;\n\n    // if cannot have multiple items, to add one item it should currently not contain items\n    if (!state.options.allowMultiple) {\n        return count === 0;\n    }\n\n    // if allows multiple items, we check if a max item count has been set, if not, there's no limit\n    const maxFileCount = state.options.maxFiles;\n    if (maxFileCount === null) {\n        return true;\n    }\n\n    // we check if the current count is smaller than the max count, if so, another file can still be added\n    if (count < maxFileCount) {\n        return true;\n    }\n\n    // no more room for another file\n    return false;\n};\n\nconst limit = (value, min, max) => Math.max(Math.min(max, value), min);\n\nconst arrayInsert = (arr, index, item) => arr.splice(index, 0, item);\n\nconst insertItem = (items, item, index) => {\n    if (isEmpty(item)) {\n        return null;\n    }\n\n    // if index is undefined, append\n    if (typeof index === 'undefined') {\n        items.push(item);\n        return item;\n    }\n\n    // limit the index to the size of the items array\n    index = limit(index, 0, items.length);\n\n    // add item to array\n    arrayInsert(items, index, item);\n\n    // expose\n    return item;\n};\n\nconst isBase64DataURI = str =>\n    /^\\s*data:([a-z]+\\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\\-._~:@\\/?%\\s]*)\\s*$/i.test(\n        str\n    );\n\nconst getFilenameFromURL = url =>\n    `${url}`\n        .split('/')\n        .pop()\n        .split('?')\n        .shift();\n\nconst getExtensionFromFilename = name => name.split('.').pop();\n\nconst guesstimateExtension = type => {\n    // if no extension supplied, exit here\n    if (typeof type !== 'string') {\n        return '';\n    }\n\n    // get subtype\n    const subtype = type.split('/').pop();\n\n    // is svg subtype\n    if (/svg/.test(subtype)) {\n        return 'svg';\n    }\n\n    if (/zip|compressed/.test(subtype)) {\n        return 'zip';\n    }\n\n    if (/plain/.test(subtype)) {\n        return 'txt';\n    }\n\n    if (/msword/.test(subtype)) {\n        return 'doc';\n    }\n\n    // if is valid subtype\n    if (/[a-z]+/.test(subtype)) {\n        // always use jpg extension\n        if (subtype === 'jpeg') {\n            return 'jpg';\n        }\n\n        // return subtype\n        return subtype;\n    }\n\n    return '';\n};\n\nconst leftPad = (value, padding = '') => (padding + value).slice(-padding.length);\n\nconst getDateString = (date = new Date()) =>\n    `${date.getFullYear()}-${leftPad(date.getMonth() + 1, '00')}-${leftPad(\n        date.getDate(),\n        '00'\n    )}_${leftPad(date.getHours(), '00')}-${leftPad(date.getMinutes(), '00')}-${leftPad(\n        date.getSeconds(),\n        '00'\n    )}`;\n\nconst getFileFromBlob = (blob, filename, type = null, extension = null) => {\n    const file =\n        typeof type === 'string'\n            ? blob.slice(0, blob.size, type)\n            : blob.slice(0, blob.size, blob.type);\n    file.lastModifiedDate = new Date();\n\n    // copy relative path\n    if (blob._relativePath) file._relativePath = blob._relativePath;\n\n    // if blob has name property, use as filename if no filename supplied\n    if (!isString(filename)) {\n        filename = getDateString();\n    }\n\n    // if filename supplied but no extension and filename has extension\n    if (filename && extension === null && getExtensionFromFilename(filename)) {\n        file.name = filename;\n    } else {\n        extension = extension || guesstimateExtension(file.type);\n        file.name = filename + (extension ? '.' + extension : '');\n    }\n\n    return file;\n};\n\nconst getBlobBuilder = () => {\n    return (window.BlobBuilder =\n        window.BlobBuilder ||\n        window.WebKitBlobBuilder ||\n        window.MozBlobBuilder ||\n        window.MSBlobBuilder);\n};\n\nconst createBlob = (arrayBuffer, mimeType) => {\n    const BB = getBlobBuilder();\n\n    if (BB) {\n        const bb = new BB();\n        bb.append(arrayBuffer);\n        return bb.getBlob(mimeType);\n    }\n\n    return new Blob([arrayBuffer], {\n        type: mimeType,\n    });\n};\n\nconst getBlobFromByteStringWithMimeType = (byteString, mimeType) => {\n    const ab = new ArrayBuffer(byteString.length);\n    const ia = new Uint8Array(ab);\n\n    for (let i = 0; i < byteString.length; i++) {\n        ia[i] = byteString.charCodeAt(i);\n    }\n\n    return createBlob(ab, mimeType);\n};\n\nconst getMimeTypeFromBase64DataURI = dataURI => {\n    return (/^data:(.+);/.exec(dataURI) || [])[1] || null;\n};\n\nconst getBase64DataFromBase64DataURI = dataURI => {\n    // get data part of string (remove data:image/jpeg...,)\n    const data = dataURI.split(',')[1];\n\n    // remove any whitespace as that causes InvalidCharacterError in IE\n    return data.replace(/\\s/g, '');\n};\n\nconst getByteStringFromBase64DataURI = dataURI => {\n    return atob(getBase64DataFromBase64DataURI(dataURI));\n};\n\nconst getBlobFromBase64DataURI = dataURI => {\n    const mimeType = getMimeTypeFromBase64DataURI(dataURI);\n    const byteString = getByteStringFromBase64DataURI(dataURI);\n\n    return getBlobFromByteStringWithMimeType(byteString, mimeType);\n};\n\nconst getFileFromBase64DataURI = (dataURI, filename, extension) => {\n    return getFileFromBlob(getBlobFromBase64DataURI(dataURI), filename, null, extension);\n};\n\nconst getFileNameFromHeader = header => {\n    // test if is content disposition header, if not exit\n    if (!/^content-disposition:/i.test(header)) return null;\n\n    // get filename parts\n    const matches = header\n        .split(/filename=|filename\\*=.+''/)\n        .splice(1)\n        .map(name => name.trim().replace(/^[\"']|[;\"']{0,2}$/g, ''))\n        .filter(name => name.length);\n\n    return matches.length ? decodeURI(matches[matches.length - 1]) : null;\n};\n\nconst getFileSizeFromHeader = header => {\n    if (/content-length:/i.test(header)) {\n        const size = header.match(/[0-9]+/)[0];\n        return size ? parseInt(size, 10) : null;\n    }\n    return null;\n};\n\nconst getTranfserIdFromHeader = header => {\n    if (/x-content-transfer-id:/i.test(header)) {\n        const id = (header.split(':')[1] || '').trim();\n        return id || null;\n    }\n    return null;\n};\n\nconst getFileInfoFromHeaders = headers => {\n    const info = {\n        source: null,\n        name: null,\n        size: null,\n    };\n\n    const rows = headers.split('\\n');\n    for (let header of rows) {\n        const name = getFileNameFromHeader(header);\n        if (name) {\n            info.name = name;\n            continue;\n        }\n\n        const size = getFileSizeFromHeader(header);\n        if (size) {\n            info.size = size;\n            continue;\n        }\n\n        const source = getTranfserIdFromHeader(header);\n        if (source) {\n            info.source = source;\n            continue;\n        }\n    }\n\n    return info;\n};\n\nconst createFileLoader = fetchFn => {\n    const state = {\n        source: null,\n        complete: false,\n        progress: 0,\n        size: null,\n        timestamp: null,\n        duration: 0,\n        request: null,\n    };\n\n    const getProgress = () => state.progress;\n    const abort = () => {\n        if (state.request && state.request.abort) {\n            state.request.abort();\n        }\n    };\n\n    // load source\n    const load = () => {\n        // get quick reference\n        const source = state.source;\n\n        api.fire('init', source);\n\n        // Load Files\n        if (source instanceof File) {\n            api.fire('load', source);\n        } else if (source instanceof Blob) {\n            // Load blobs, set default name to current date\n            api.fire('load', getFileFromBlob(source, source.name));\n        } else if (isBase64DataURI(source)) {\n            // Load base 64, set default name to current date\n            api.fire('load', getFileFromBase64DataURI(source));\n        } else {\n            // Deal as if is external URL, let's load it!\n            loadURL(source);\n        }\n    };\n\n    // loads a url\n    const loadURL = url => {\n        // is remote url and no fetch method supplied\n        if (!fetchFn) {\n            api.fire('error', {\n                type: 'error',\n                body: \"Can't load URL\",\n                code: 400,\n            });\n            return;\n        }\n\n        // set request start\n        state.timestamp = Date.now();\n\n        // load file\n        state.request = fetchFn(\n            url,\n            response => {\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // done!\n                state.complete = true;\n\n                // turn blob response into a file\n                if (response instanceof Blob) {\n                    response = getFileFromBlob(response, response.name || getFilenameFromURL(url));\n                }\n\n                api.fire(\n                    'load',\n                    // if has received blob, we go with blob, if no response, we return null\n                    response instanceof Blob ? response : response ? response.body : null\n                );\n            },\n            error => {\n                api.fire(\n                    'error',\n                    typeof error === 'string'\n                        ? {\n                              type: 'error',\n                              code: 0,\n                              body: error,\n                          }\n                        : error\n                );\n            },\n            (computable, current, total) => {\n                // collected some meta data already\n                if (total) {\n                    state.size = total;\n                }\n\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // if we can't compute progress, we're not going to fire progress events\n                if (!computable) {\n                    state.progress = null;\n                    return;\n                }\n\n                // update progress percentage\n                state.progress = current / total;\n\n                // expose\n                api.fire('progress', state.progress);\n            },\n            () => {\n                api.fire('abort');\n            },\n            response => {\n                const fileinfo = getFileInfoFromHeaders(\n                    typeof response === 'string' ? response : response.headers\n                );\n                api.fire('meta', {\n                    size: state.size || fileinfo.size,\n                    filename: fileinfo.name,\n                    source: fileinfo.source,\n                });\n            }\n        );\n    };\n\n    const api = {\n        ...on(),\n        setSource: source => (state.source = source),\n        getProgress, // file load progress\n        abort, // abort file load\n        load, // start load\n    };\n\n    return api;\n};\n\nconst isGet = method => /GET|HEAD/.test(method);\n\nconst sendRequest = (data, url, options) => {\n    const api = {\n        onheaders: () => {},\n        onprogress: () => {},\n        onload: () => {},\n        ontimeout: () => {},\n        onerror: () => {},\n        onabort: () => {},\n        abort: () => {\n            aborted = true;\n            xhr.abort();\n        },\n    };\n\n    // timeout identifier, only used when timeout is defined\n    let aborted = false;\n    let headersReceived = false;\n\n    // set default options\n    options = {\n        method: 'POST',\n        headers: {},\n        withCredentials: false,\n        ...options,\n    };\n\n    // encode url\n    url = encodeURI(url);\n\n    // if method is GET, add any received data to url\n\n    if (isGet(options.method) && data) {\n        url = `${url}${encodeURIComponent(typeof data === 'string' ? data : JSON.stringify(data))}`;\n    }\n\n    // create request\n    const xhr = new XMLHttpRequest();\n\n    // progress of load\n    const process = isGet(options.method) ? xhr : xhr.upload;\n    process.onprogress = e => {\n        // no progress event when aborted ( onprogress is called once after abort() )\n        if (aborted) {\n            return;\n        }\n\n        api.onprogress(e.lengthComputable, e.loaded, e.total);\n    };\n\n    // tries to get header info to the app as fast as possible\n    xhr.onreadystatechange = () => {\n        // not interesting in these states ('unsent' and 'openend' as they don't give us any additional info)\n        if (xhr.readyState < 2) {\n            return;\n        }\n\n        // no server response\n        if (xhr.readyState === 4 && xhr.status === 0) {\n            return;\n        }\n\n        if (headersReceived) {\n            return;\n        }\n\n        headersReceived = true;\n\n        // we've probably received some useful data in response headers\n        api.onheaders(xhr);\n    };\n\n    // load successful\n    xhr.onload = () => {\n        // is classified as valid response\n        if (xhr.status >= 200 && xhr.status < 300) {\n            api.onload(xhr);\n        } else {\n            api.onerror(xhr);\n        }\n    };\n\n    // error during load\n    xhr.onerror = () => api.onerror(xhr);\n\n    // request aborted\n    xhr.onabort = () => {\n        aborted = true;\n        api.onabort();\n    };\n\n    // request timeout\n    xhr.ontimeout = () => api.ontimeout(xhr);\n\n    // open up open up!\n    xhr.open(options.method, url, true);\n\n    // set timeout if defined (do it after open so IE11 plays ball)\n    if (isInt(options.timeout)) {\n        xhr.timeout = options.timeout;\n    }\n\n    // add headers\n    Object.keys(options.headers).forEach(key => {\n        const value = unescape(encodeURIComponent(options.headers[key]));\n        xhr.setRequestHeader(key, value);\n    });\n\n    // set type of response\n    if (options.responseType) {\n        xhr.responseType = options.responseType;\n    }\n\n    // set credentials\n    if (options.withCredentials) {\n        xhr.withCredentials = true;\n    }\n\n    // let's send our data\n    xhr.send(data);\n\n    return api;\n};\n\nconst createResponse = (type, code, body, headers) => ({\n    type,\n    code,\n    body,\n    headers,\n});\n\nconst createTimeoutResponse = cb => xhr => {\n    cb(createResponse('error', 0, 'Timeout', xhr.getAllResponseHeaders()));\n};\n\nconst hasQS = str => /\\?/.test(str);\nconst buildURL = (...parts) => {\n    let url = '';\n    parts.forEach(part => {\n        url += hasQS(url) && hasQS(part) ? part.replace(/\\?/, '&') : part;\n    });\n    return url;\n};\n\nconst createFetchFunction = (apiUrl = '', action) => {\n    // custom handler (should also handle file, load, error, progress and abort)\n    if (typeof action === 'function') {\n        return action;\n    }\n\n    // no action supplied\n    if (!action || !isString(action.url)) {\n        return null;\n    }\n\n    // set onload hanlder\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    // internal handler\n    return (url, load, error, progress, abort, headers) => {\n        // do local or remote request based on if the url is external\n        const request = sendRequest(url, buildURL(apiUrl, action.url), {\n            ...action,\n            responseType: 'blob',\n        });\n\n        request.onload = xhr => {\n            // get headers\n            const headers = xhr.getAllResponseHeaders();\n\n            // get filename\n            const filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n            // create response\n            load(\n                createResponse(\n                    'load',\n                    xhr.status,\n                    action.method === 'HEAD'\n                        ? null\n                        : getFileFromBlob(onload(xhr.response), filename),\n                    headers\n                )\n            );\n        };\n\n        request.onerror = xhr => {\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n        };\n\n        request.onheaders = xhr => {\n            headers(createResponse('headers', xhr.status, null, xhr.getAllResponseHeaders()));\n        };\n\n        request.ontimeout = createTimeoutResponse(error);\n        request.onprogress = progress;\n        request.onabort = abort;\n\n        // should return request\n        return request;\n    };\n};\n\nconst ChunkStatus = {\n    QUEUED: 0,\n    COMPLETE: 1,\n    PROCESSING: 2,\n    ERROR: 3,\n    WAITING: 4,\n};\n\n/*\nfunction signature:\n  (file, metadata, load, error, progress, abort, transfer, options) => {\n    return {\n    abort:() => {}\n  }\n}\n*/\n\n// apiUrl, action, name, file, metadata, load, error, progress, abort, transfer, options\nconst processFileChunked = (\n    apiUrl,\n    action,\n    name,\n    file,\n    metadata,\n    load,\n    error,\n    progress,\n    abort,\n    transfer,\n    options\n) => {\n    // all chunks\n    const chunks = [];\n    const { chunkTransferId, chunkServer, chunkSize, chunkRetryDelays } = options;\n\n    // default state\n    const state = {\n        serverId: chunkTransferId,\n        aborted: false,\n    };\n\n    // set onload handlers\n    const ondata = action.ondata || (fd => fd);\n    const onload =\n        action.onload ||\n        ((xhr, method) =>\n            method === 'HEAD' ? xhr.getResponseHeader('Upload-Offset') : xhr.response);\n    const onerror = action.onerror || (res => null);\n\n    // create server hook\n    const requestTransferId = cb => {\n        const formData = new FormData();\n\n        // add metadata under same name\n        if (isObject(metadata)) formData.append(name, JSON.stringify(metadata));\n\n        const headers =\n            typeof action.headers === 'function'\n                ? action.headers(file, metadata)\n                : {\n                      ...action.headers,\n                      'Upload-Length': file.size,\n                  };\n\n        const requestParams = {\n            ...action,\n            headers,\n        };\n\n        // send request object\n        const request = sendRequest(ondata(formData), buildURL(apiUrl, action.url), requestParams);\n\n        request.onload = xhr => cb(onload(xhr, requestParams.method));\n\n        request.onerror = xhr =>\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n\n        request.ontimeout = createTimeoutResponse(error);\n    };\n\n    const requestTransferOffset = cb => {\n        const requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n        const headers =\n            typeof action.headers === 'function'\n                ? action.headers(state.serverId)\n                : {\n                      ...action.headers,\n                  };\n\n        const requestParams = {\n            headers,\n            method: 'HEAD',\n        };\n\n        const request = sendRequest(null, requestUrl, requestParams);\n\n        request.onload = xhr => cb(onload(xhr, requestParams.method));\n\n        request.onerror = xhr =>\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n\n        request.ontimeout = createTimeoutResponse(error);\n    };\n\n    // create chunks\n    const lastChunkIndex = Math.floor(file.size / chunkSize);\n    for (let i = 0; i <= lastChunkIndex; i++) {\n        const offset = i * chunkSize;\n        const data = file.slice(offset, offset + chunkSize, 'application/offset+octet-stream');\n        chunks[i] = {\n            index: i,\n            size: data.size,\n            offset,\n            data,\n            file,\n            progress: 0,\n            retries: [...chunkRetryDelays],\n            status: ChunkStatus.QUEUED,\n            error: null,\n            request: null,\n            timeout: null,\n        };\n    }\n\n    const completeProcessingChunks = () => load(state.serverId);\n\n    const canProcessChunk = chunk =>\n        chunk.status === ChunkStatus.QUEUED || chunk.status === ChunkStatus.ERROR;\n\n    const processChunk = chunk => {\n        // processing is paused, wait here\n        if (state.aborted) return;\n\n        // get next chunk to process\n        chunk = chunk || chunks.find(canProcessChunk);\n\n        // no more chunks to process\n        if (!chunk) {\n            // all done?\n            if (chunks.every(chunk => chunk.status === ChunkStatus.COMPLETE)) {\n                completeProcessingChunks();\n            }\n\n            // no chunk to handle\n            return;\n        }\n\n        // now processing this chunk\n        chunk.status = ChunkStatus.PROCESSING;\n        chunk.progress = null;\n\n        // allow parsing of formdata\n        const ondata = chunkServer.ondata || (fd => fd);\n        const onerror = chunkServer.onerror || (res => null);\n        const onload = chunkServer.onload || (() => {});\n\n        // send request object\n        const requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n        const headers =\n            typeof chunkServer.headers === 'function'\n                ? chunkServer.headers(chunk)\n                : {\n                      ...chunkServer.headers,\n                      'Content-Type': 'application/offset+octet-stream',\n                      'Upload-Offset': chunk.offset,\n                      'Upload-Length': file.size,\n                      'Upload-Name': file.name,\n                  };\n\n        const request = (chunk.request = sendRequest(ondata(chunk.data), requestUrl, {\n            ...chunkServer,\n            headers,\n        }));\n\n        request.onload = xhr => {\n            // allow hooking into request result\n            onload(xhr, chunk.index, chunks.length);\n\n            // done!\n            chunk.status = ChunkStatus.COMPLETE;\n\n            // remove request reference\n            chunk.request = null;\n\n            // start processing more chunks\n            processChunks();\n        };\n\n        request.onprogress = (lengthComputable, loaded, total) => {\n            chunk.progress = lengthComputable ? loaded : null;\n            updateTotalProgress();\n        };\n\n        request.onerror = xhr => {\n            chunk.status = ChunkStatus.ERROR;\n            chunk.request = null;\n            chunk.error = onerror(xhr.response) || xhr.statusText;\n            if (!retryProcessChunk(chunk)) {\n                error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            }\n        };\n\n        request.ontimeout = xhr => {\n            chunk.status = ChunkStatus.ERROR;\n            chunk.request = null;\n            if (!retryProcessChunk(chunk)) {\n                createTimeoutResponse(error)(xhr);\n            }\n        };\n\n        request.onabort = () => {\n            chunk.status = ChunkStatus.QUEUED;\n            chunk.request = null;\n            abort();\n        };\n    };\n\n    const retryProcessChunk = chunk => {\n        // no more retries left\n        if (chunk.retries.length === 0) return false;\n\n        // new retry\n        chunk.status = ChunkStatus.WAITING;\n        clearTimeout(chunk.timeout);\n        chunk.timeout = setTimeout(() => {\n            processChunk(chunk);\n        }, chunk.retries.shift());\n\n        // we're going to retry\n        return true;\n    };\n\n    const updateTotalProgress = () => {\n        // calculate total progress fraction\n        const totalBytesTransfered = chunks.reduce((p, chunk) => {\n            if (p === null || chunk.progress === null) return null;\n            return p + chunk.progress;\n        }, 0);\n\n        // can't compute progress\n        if (totalBytesTransfered === null) return progress(false, 0, 0);\n\n        // calculate progress values\n        const totalSize = chunks.reduce((total, chunk) => total + chunk.size, 0);\n\n        // can update progress indicator\n        progress(true, totalBytesTransfered, totalSize);\n    };\n\n    // process new chunks\n    const processChunks = () => {\n        const totalProcessing = chunks.filter(chunk => chunk.status === ChunkStatus.PROCESSING)\n            .length;\n        if (totalProcessing >= 1) return;\n        processChunk();\n    };\n\n    const abortChunks = () => {\n        chunks.forEach(chunk => {\n            clearTimeout(chunk.timeout);\n            if (chunk.request) {\n                chunk.request.abort();\n            }\n        });\n    };\n\n    // let's go!\n    if (!state.serverId) {\n        requestTransferId(serverId => {\n            // stop here if aborted, might have happened in between request and callback\n            if (state.aborted) return;\n\n            // pass back to item so we can use it if something goes wrong\n            transfer(serverId);\n\n            // store internally\n            state.serverId = serverId;\n            processChunks();\n        });\n    } else {\n        requestTransferOffset(offset => {\n            // stop here if aborted, might have happened in between request and callback\n            if (state.aborted) return;\n\n            // mark chunks with lower offset as complete\n            chunks\n                .filter(chunk => chunk.offset < offset)\n                .forEach(chunk => {\n                    chunk.status = ChunkStatus.COMPLETE;\n                    chunk.progress = chunk.size;\n                });\n\n            // continue processing\n            processChunks();\n        });\n    }\n\n    return {\n        abort: () => {\n            state.aborted = true;\n            abortChunks();\n        },\n    };\n};\n\n/*\nfunction signature:\n  (file, metadata, load, error, progress, abort) => {\n    return {\n    abort:() => {}\n  }\n}\n*/\nconst createFileProcessorFunction = (apiUrl, action, name, options) => (\n    file,\n    metadata,\n    load,\n    error,\n    progress,\n    abort,\n    transfer\n) => {\n    // no file received\n    if (!file) return;\n\n    // if was passed a file, and we can chunk it, exit here\n    const canChunkUpload = options.chunkUploads;\n    const shouldChunkUpload = canChunkUpload && file.size > options.chunkSize;\n    const willChunkUpload = canChunkUpload && (shouldChunkUpload || options.chunkForce);\n    if (file instanceof Blob && willChunkUpload)\n        return processFileChunked(\n            apiUrl,\n            action,\n            name,\n            file,\n            metadata,\n            load,\n            error,\n            progress,\n            abort,\n            transfer,\n            options\n        );\n\n    // set handlers\n    const ondata = action.ondata || (fd => fd);\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    const headers =\n        typeof action.headers === 'function'\n            ? action.headers(file, metadata) || {}\n            : {\n                  ...action.headers,\n              };\n\n    const requestParams = {\n        ...action,\n        headers,\n    };\n\n    // create formdata object\n    var formData = new FormData();\n\n    // add metadata under same name\n    if (isObject(metadata)) {\n        formData.append(name, JSON.stringify(metadata));\n    }\n\n    // Turn into an array of objects so no matter what the input, we can handle it the same way\n    (file instanceof Blob ? [{ name: null, file }] : file).forEach(item => {\n        formData.append(\n            name,\n            item.file,\n            item.name === null ? item.file.name : `${item.name}${item.file.name}`\n        );\n    });\n\n    // send request object\n    const request = sendRequest(ondata(formData), buildURL(apiUrl, action.url), requestParams);\n    request.onload = xhr => {\n        load(createResponse('load', xhr.status, onload(xhr.response), xhr.getAllResponseHeaders()));\n    };\n\n    request.onerror = xhr => {\n        error(\n            createResponse(\n                'error',\n                xhr.status,\n                onerror(xhr.response) || xhr.statusText,\n                xhr.getAllResponseHeaders()\n            )\n        );\n    };\n\n    request.ontimeout = createTimeoutResponse(error);\n    request.onprogress = progress;\n    request.onabort = abort;\n\n    // should return request\n    return request;\n};\n\nconst createProcessorFunction = (apiUrl = '', action, name, options) => {\n    // custom handler (should also handle file, load, error, progress and abort)\n    if (typeof action === 'function') return (...params) => action(name, ...params, options);\n\n    // no action supplied\n    if (!action || !isString(action.url)) return null;\n\n    // internal handler\n    return createFileProcessorFunction(apiUrl, action, name, options);\n};\n\n/*\n function signature:\n (uniqueFileId, load, error) => { }\n */\nconst createRevertFunction = (apiUrl = '', action) => {\n    // is custom implementation\n    if (typeof action === 'function') {\n        return action;\n    }\n\n    // no action supplied, return stub function, interface will work, but file won't be removed\n    if (!action || !isString(action.url)) {\n        return (uniqueFileId, load) => load();\n    }\n\n    // set onload hanlder\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    // internal implementation\n    return (uniqueFileId, load, error) => {\n        const request = sendRequest(\n            uniqueFileId,\n            apiUrl + action.url,\n            action // contains method, headers and withCredentials properties\n        );\n        request.onload = xhr => {\n            load(\n                createResponse(\n                    'load',\n                    xhr.status,\n                    onload(xhr.response),\n                    xhr.getAllResponseHeaders()\n                )\n            );\n        };\n\n        request.onerror = xhr => {\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n        };\n\n        request.ontimeout = createTimeoutResponse(error);\n\n        return request;\n    };\n};\n\nconst getRandomNumber = (min = 0, max = 1) => min + Math.random() * (max - min);\n\nconst createPerceivedPerformanceUpdater = (\n    cb,\n    duration = 1000,\n    offset = 0,\n    tickMin = 25,\n    tickMax = 250\n) => {\n    let timeout = null;\n    const start = Date.now();\n\n    const tick = () => {\n        let runtime = Date.now() - start;\n        let delay = getRandomNumber(tickMin, tickMax);\n\n        if (runtime + delay > duration) {\n            delay = runtime + delay - duration;\n        }\n\n        let progress = runtime / duration;\n        if (progress >= 1 || document.hidden) {\n            cb(1);\n            return;\n        }\n\n        cb(progress);\n\n        timeout = setTimeout(tick, delay);\n    };\n\n    if (duration > 0) tick();\n\n    return {\n        clear: () => {\n            clearTimeout(timeout);\n        },\n    };\n};\n\nconst createFileProcessor = (processFn, options) => {\n    const state = {\n        complete: false,\n        perceivedProgress: 0,\n        perceivedPerformanceUpdater: null,\n        progress: null,\n        timestamp: null,\n        perceivedDuration: 0,\n        duration: 0,\n        request: null,\n        response: null,\n    };\n\n    const { allowMinimumUploadDuration } = options;\n\n    const process = (file, metadata) => {\n        const progressFn = () => {\n            // we've not yet started the real download, stop here\n            // the request might not go through, for instance, there might be some server trouble\n            // if state.progress is null, the server does not allow computing progress and we show the spinner instead\n            if (state.duration === 0 || state.progress === null) return;\n\n            // as we're now processing, fire the progress event\n            api.fire('progress', api.getProgress());\n        };\n\n        const completeFn = () => {\n            state.complete = true;\n            api.fire('load-perceived', state.response.body);\n        };\n\n        // let's start processing\n        api.fire('start');\n\n        // set request start\n        state.timestamp = Date.now();\n\n        // create perceived performance progress indicator\n        state.perceivedPerformanceUpdater = createPerceivedPerformanceUpdater(\n            progress => {\n                state.perceivedProgress = progress;\n                state.perceivedDuration = Date.now() - state.timestamp;\n\n                progressFn();\n\n                // if fake progress is done, and a response has been received,\n                // and we've not yet called the complete method\n                if (state.response && state.perceivedProgress === 1 && !state.complete) {\n                    // we done!\n                    completeFn();\n                }\n            },\n            // random delay as in a list of files you start noticing\n            // files uploading at the exact same speed\n            allowMinimumUploadDuration ? getRandomNumber(750, 1500) : 0\n        );\n\n        // remember request so we can abort it later\n        state.request = processFn(\n            // the file to process\n            file,\n\n            // the metadata to send along\n            metadata,\n\n            // callbacks (load, error, progress, abort, transfer)\n            // load expects the body to be a server id if\n            // you want to make use of revert\n            response => {\n                // we put the response in state so we can access\n                // it outside of this method\n                state.response = isObject(response)\n                    ? response\n                    : {\n                          type: 'load',\n                          code: 200,\n                          body: `${response}`,\n                          headers: {},\n                      };\n\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // force progress to 1 as we're now done\n                state.progress = 1;\n\n                // actual load is done let's share results\n                api.fire('load', state.response.body);\n\n                // we are really done\n                // if perceived progress is 1 ( wait for perceived progress to complete )\n                // or if server does not support progress ( null )\n                if (\n                    !allowMinimumUploadDuration ||\n                    (allowMinimumUploadDuration && state.perceivedProgress === 1)\n                ) {\n                    completeFn();\n                }\n            },\n\n            // error is expected to be an object with type, code, body\n            error => {\n                // cancel updater\n                state.perceivedPerformanceUpdater.clear();\n\n                // update others about this error\n                api.fire(\n                    'error',\n                    isObject(error)\n                        ? error\n                        : {\n                              type: 'error',\n                              code: 0,\n                              body: `${error}`,\n                          }\n                );\n            },\n\n            // actual processing progress\n            (computable, current, total) => {\n                // update actual duration\n                state.duration = Date.now() - state.timestamp;\n\n                // update actual progress\n                state.progress = computable ? current / total : null;\n\n                progressFn();\n            },\n\n            // abort does not expect a value\n            () => {\n                // stop updater\n                state.perceivedPerformanceUpdater.clear();\n\n                // fire the abort event so we can switch visuals\n                api.fire('abort', state.response ? state.response.body : null);\n            },\n\n            // register the id for this transfer\n            transferId => {\n                api.fire('transfer', transferId);\n            }\n        );\n    };\n\n    const abort = () => {\n        // no request running, can't abort\n        if (!state.request) return;\n\n        // stop updater\n        state.perceivedPerformanceUpdater.clear();\n\n        // abort actual request\n        if (state.request.abort) state.request.abort();\n\n        // if has response object, we've completed the request\n        state.complete = true;\n    };\n\n    const reset = () => {\n        abort();\n        state.complete = false;\n        state.perceivedProgress = 0;\n        state.progress = 0;\n        state.timestamp = null;\n        state.perceivedDuration = 0;\n        state.duration = 0;\n        state.request = null;\n        state.response = null;\n    };\n\n    const getProgress = allowMinimumUploadDuration\n        ? () => (state.progress ? Math.min(state.progress, state.perceivedProgress) : null)\n        : () => state.progress || null;\n\n    const getDuration = allowMinimumUploadDuration\n        ? () => Math.min(state.duration, state.perceivedDuration)\n        : () => state.duration;\n\n    const api = {\n        ...on(),\n        process, // start processing file\n        abort, // abort active process request\n        getProgress,\n        getDuration,\n        reset,\n    };\n\n    return api;\n};\n\nconst getFilenameWithoutExtension = name => name.substring(0, name.lastIndexOf('.')) || name;\n\nconst createFileStub = source => {\n    let data = [source.name, source.size, source.type];\n\n    // is blob or base64, then we need to set the name\n    if (source instanceof Blob || isBase64DataURI(source)) {\n        data[0] = source.name || getDateString();\n    } else if (isBase64DataURI(source)) {\n        // if is base64 data uri we need to determine the average size and type\n        data[1] = source.length;\n        data[2] = getMimeTypeFromBase64DataURI(source);\n    } else if (isString(source)) {\n        // url\n        data[0] = getFilenameFromURL(source);\n        data[1] = 0;\n        data[2] = 'application/octet-stream';\n    }\n\n    return {\n        name: data[0],\n        size: data[1],\n        type: data[2],\n    };\n};\n\nconst isFile = value => !!(value instanceof File || (value instanceof Blob && value.name));\n\nconst deepCloneObject = src => {\n    if (!isObject(src)) return src;\n    const target = isArray(src) ? [] : {};\n    for (const key in src) {\n        if (!src.hasOwnProperty(key)) continue;\n        const v = src[key];\n        target[key] = v && isObject(v) ? deepCloneObject(v) : v;\n    }\n    return target;\n};\n\nconst createItem = (origin = null, serverFileReference = null, file = null) => {\n    // unique id for this item, is used to identify the item across views\n    const id = getUniqueId();\n\n    /**\n     * Internal item state\n     */\n    const state = {\n        // is archived\n        archived: false,\n\n        // if is frozen, no longer fires events\n        frozen: false,\n\n        // removed from view\n        released: false,\n\n        // original source\n        source: null,\n\n        // file model reference\n        file,\n\n        // id of file on server\n        serverFileReference,\n\n        // id of file transfer on server\n        transferId: null,\n\n        // is aborted\n        processingAborted: false,\n\n        // current item status\n        status: serverFileReference ? ItemStatus.PROCESSING_COMPLETE : ItemStatus.INIT,\n\n        // active processes\n        activeLoader: null,\n        activeProcessor: null,\n    };\n\n    // callback used when abort processing is called to link back to the resolve method\n    let abortProcessingRequestComplete = null;\n\n    /**\n     * Externally added item metadata\n     */\n    const metadata = {};\n\n    // item data\n    const setStatus = status => (state.status = status);\n\n    // fire event unless the item has been archived\n    const fire = (event, ...params) => {\n        if (state.released || state.frozen) return;\n        api.fire(event, ...params);\n    };\n\n    // file data\n    const getFileExtension = () => getExtensionFromFilename(state.file.name);\n    const getFileType = () => state.file.type;\n    const getFileSize = () => state.file.size;\n    const getFile = () => state.file;\n\n    //\n    // logic to load a file\n    //\n    const load = (source, loader, onload) => {\n        // remember the original item source\n        state.source = source;\n\n        // source is known\n        api.fireSync('init');\n\n        // file stub is already there\n        if (state.file) {\n            api.fireSync('load-skip');\n            return;\n        }\n\n        // set a stub file object while loading the actual data\n        state.file = createFileStub(source);\n\n        // starts loading\n        loader.on('init', () => {\n            fire('load-init');\n        });\n\n        // we'eve received a size indication, let's update the stub\n        loader.on('meta', meta => {\n            // set size of file stub\n            state.file.size = meta.size;\n\n            // set name of file stub\n            state.file.filename = meta.filename;\n\n            // if has received source, we done\n            if (meta.source) {\n                origin = FileOrigin.LIMBO;\n                state.serverFileReference = meta.source;\n                state.status = ItemStatus.PROCESSING_COMPLETE;\n            }\n\n            // size has been updated\n            fire('load-meta');\n        });\n\n        // the file is now loading we need to update the progress indicators\n        loader.on('progress', progress => {\n            setStatus(ItemStatus.LOADING);\n\n            fire('load-progress', progress);\n        });\n\n        // an error was thrown while loading the file, we need to switch to error state\n        loader.on('error', error => {\n            setStatus(ItemStatus.LOAD_ERROR);\n\n            fire('load-request-error', error);\n        });\n\n        // user or another process aborted the file load (cannot retry)\n        loader.on('abort', () => {\n            setStatus(ItemStatus.INIT);\n            fire('load-abort');\n        });\n\n        // done loading\n        loader.on('load', file => {\n            // as we've now loaded the file the loader is no longer required\n            state.activeLoader = null;\n\n            // called when file has loaded succesfully\n            const success = result => {\n                // set (possibly) transformed file\n                state.file = isFile(result) ? result : state.file;\n\n                // file received\n                if (origin === FileOrigin.LIMBO && state.serverFileReference) {\n                    setStatus(ItemStatus.PROCESSING_COMPLETE);\n                } else {\n                    setStatus(ItemStatus.IDLE);\n                }\n\n                fire('load');\n            };\n\n            const error = result => {\n                // set original file\n                state.file = file;\n                fire('load-meta');\n\n                setStatus(ItemStatus.LOAD_ERROR);\n                fire('load-file-error', result);\n            };\n\n            // if we already have a server file reference, we don't need to call the onload method\n            if (state.serverFileReference) {\n                success(file);\n                return;\n            }\n\n            // no server id, let's give this file the full treatment\n            onload(file, success, error);\n        });\n\n        // set loader source data\n        loader.setSource(source);\n\n        // set as active loader\n        state.activeLoader = loader;\n\n        // load the source data\n        loader.load();\n    };\n\n    const retryLoad = () => {\n        if (!state.activeLoader) {\n            return;\n        }\n        state.activeLoader.load();\n    };\n\n    const abortLoad = () => {\n        if (state.activeLoader) {\n            state.activeLoader.abort();\n            return;\n        }\n        setStatus(ItemStatus.INIT);\n        fire('load-abort');\n    };\n\n    //\n    // logic to process a file\n    //\n    const process = (processor, onprocess) => {\n        // processing was aborted\n        if (state.processingAborted) {\n            state.processingAborted = false;\n            return;\n        }\n\n        // now processing\n        setStatus(ItemStatus.PROCESSING);\n\n        // reset abort callback\n        abortProcessingRequestComplete = null;\n\n        // if no file loaded we'll wait for the load event\n        if (!(state.file instanceof Blob)) {\n            api.on('load', () => {\n                process(processor, onprocess);\n            });\n            return;\n        }\n\n        // setup processor\n        processor.on('load', serverFileReference => {\n            // need this id to be able to revert the upload\n            state.transferId = null;\n            state.serverFileReference = serverFileReference;\n        });\n\n        // register transfer id\n        processor.on('transfer', transferId => {\n            // need this id to be able to revert the upload\n            state.transferId = transferId;\n        });\n\n        processor.on('load-perceived', serverFileReference => {\n            // no longer required\n            state.activeProcessor = null;\n\n            // need this id to be able to rever the upload\n            state.transferId = null;\n            state.serverFileReference = serverFileReference;\n\n            setStatus(ItemStatus.PROCESSING_COMPLETE);\n            fire('process-complete', serverFileReference);\n        });\n\n        processor.on('start', () => {\n            fire('process-start');\n        });\n\n        processor.on('error', error => {\n            state.activeProcessor = null;\n            setStatus(ItemStatus.PROCESSING_ERROR);\n            fire('process-error', error);\n        });\n\n        processor.on('abort', serverFileReference => {\n            state.activeProcessor = null;\n\n            // if file was uploaded but processing was cancelled during perceived processor time store file reference\n            state.serverFileReference = serverFileReference;\n\n            setStatus(ItemStatus.IDLE);\n            fire('process-abort');\n\n            // has timeout so doesn't interfere with remove action\n            if (abortProcessingRequestComplete) {\n                abortProcessingRequestComplete();\n            }\n        });\n\n        processor.on('progress', progress => {\n            fire('process-progress', progress);\n        });\n\n        // when successfully transformed\n        const success = file => {\n            // if was archived in the mean time, don't process\n            if (state.archived) return;\n\n            // process file!\n            processor.process(file, { ...metadata });\n        };\n\n        // something went wrong during transform phase\n        const error = console.error;\n\n        // start processing the file\n        onprocess(state.file, success, error);\n\n        // set as active processor\n        state.activeProcessor = processor;\n    };\n\n    const requestProcessing = () => {\n        state.processingAborted = false;\n        setStatus(ItemStatus.PROCESSING_QUEUED);\n    };\n\n    const abortProcessing = () =>\n        new Promise(resolve => {\n            if (!state.activeProcessor) {\n                state.processingAborted = true;\n\n                setStatus(ItemStatus.IDLE);\n                fire('process-abort');\n\n                resolve();\n                return;\n            }\n\n            abortProcessingRequestComplete = () => {\n                resolve();\n            };\n\n            state.activeProcessor.abort();\n        });\n\n    //\n    // logic to revert a processed file\n    //\n    const revert = (revertFileUpload, forceRevert) =>\n        new Promise((resolve, reject) => {\n            // a completed upload will have a serverFileReference, a failed chunked upload where\n            // getting a serverId succeeded but >=0 chunks have been uploaded will have transferId set\n            const serverTransferId =\n                state.serverFileReference !== null ? state.serverFileReference : state.transferId;\n\n            // cannot revert without a server id for this process\n            if (serverTransferId === null) {\n                resolve();\n                return;\n            }\n\n            // revert the upload (fire and forget)\n            revertFileUpload(\n                serverTransferId,\n                () => {\n                    // reset file server id and transfer id as now it's not available on the server\n                    state.serverFileReference = null;\n                    state.transferId = null;\n                    resolve();\n                },\n                error => {\n                    // don't set error state when reverting is optional, it will always resolve\n                    if (!forceRevert) {\n                        resolve();\n                        return;\n                    }\n\n                    // oh no errors\n                    setStatus(ItemStatus.PROCESSING_REVERT_ERROR);\n                    fire('process-revert-error');\n                    reject(error);\n                }\n            );\n\n            // fire event\n            setStatus(ItemStatus.IDLE);\n            fire('process-revert');\n        });\n\n    // exposed methods\n    const setMetadata = (key, value, silent) => {\n        const keys = key.split('.');\n        const root = keys[0];\n        const last = keys.pop();\n        let data = metadata;\n        keys.forEach(key => (data = data[key]));\n\n        // compare old value against new value, if they're the same, we're not updating\n        if (JSON.stringify(data[last]) === JSON.stringify(value)) return;\n\n        // update value\n        data[last] = value;\n\n        // fire update\n        fire('metadata-update', {\n            key: root,\n            value: metadata[root],\n            silent,\n        });\n    };\n\n    const getMetadata = key => deepCloneObject(key ? metadata[key] : metadata);\n\n    const api = {\n        id: { get: () => id },\n        origin: { get: () => origin, set: value => (origin = value) },\n        serverId: { get: () => state.serverFileReference },\n        transferId: { get: () => state.transferId },\n        status: { get: () => state.status },\n        filename: { get: () => state.file.name },\n        filenameWithoutExtension: { get: () => getFilenameWithoutExtension(state.file.name) },\n        fileExtension: { get: getFileExtension },\n        fileType: { get: getFileType },\n        fileSize: { get: getFileSize },\n        file: { get: getFile },\n        relativePath: { get: () => state.file._relativePath },\n\n        source: { get: () => state.source },\n\n        getMetadata,\n        setMetadata: (key, value, silent) => {\n            if (isObject(key)) {\n                const data = key;\n                Object.keys(data).forEach(key => {\n                    setMetadata(key, data[key], value);\n                });\n                return key;\n            }\n            setMetadata(key, value, silent);\n            return value;\n        },\n\n        extend: (name, handler) => (itemAPI[name] = handler),\n\n        abortLoad,\n        retryLoad,\n        requestProcessing,\n        abortProcessing,\n\n        load,\n        process,\n        revert,\n\n        ...on(),\n\n        freeze: () => (state.frozen = true),\n\n        release: () => (state.released = true),\n        released: { get: () => state.released },\n\n        archive: () => (state.archived = true),\n        archived: { get: () => state.archived },\n\n        // replace source and file object\n        setFile: file => (state.file = file),\n    };\n\n    // create it here instead of returning it instantly so we can extend it later\n    const itemAPI = createObject(api);\n\n    return itemAPI;\n};\n\nconst getItemIndexByQuery = (items, query) => {\n    // just return first index\n    if (isEmpty(query)) {\n        return 0;\n    }\n\n    // invalid queries\n    if (!isString(query)) {\n        return -1;\n    }\n\n    // return item by id (or -1 if not found)\n    return items.findIndex(item => item.id === query);\n};\n\nconst getItemById = (items, itemId) => {\n    const index = getItemIndexByQuery(items, itemId);\n    if (index < 0) {\n        return;\n    }\n    return items[index] || null;\n};\n\nconst fetchBlob = (url, load, error, progress, abort, headers) => {\n    const request = sendRequest(null, url, {\n        method: 'GET',\n        responseType: 'blob',\n    });\n\n    request.onload = xhr => {\n        // get headers\n        const headers = xhr.getAllResponseHeaders();\n\n        // get filename\n        const filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n        // create response\n        load(createResponse('load', xhr.status, getFileFromBlob(xhr.response, filename), headers));\n    };\n\n    request.onerror = xhr => {\n        error(createResponse('error', xhr.status, xhr.statusText, xhr.getAllResponseHeaders()));\n    };\n\n    request.onheaders = xhr => {\n        headers(createResponse('headers', xhr.status, null, xhr.getAllResponseHeaders()));\n    };\n\n    request.ontimeout = createTimeoutResponse(error);\n    request.onprogress = progress;\n    request.onabort = abort;\n\n    // should return request\n    return request;\n};\n\nconst getDomainFromURL = url => {\n    if (url.indexOf('//') === 0) {\n        url = location.protocol + url;\n    }\n    return url\n        .toLowerCase()\n        .replace('blob:', '')\n        .replace(/([a-z])?:\\/\\//, '$1')\n        .split('/')[0];\n};\n\nconst isExternalURL = url =>\n    (url.indexOf(':') > -1 || url.indexOf('//') > -1) &&\n    getDomainFromURL(location.href) !== getDomainFromURL(url);\n\nconst dynamicLabel = label => (...params) => (isFunction(label) ? label(...params) : label);\n\nconst isMockItem = item => !isFile(item.file);\n\nconst listUpdated = (dispatch, state) => {\n    clearTimeout(state.listUpdateTimeout);\n    state.listUpdateTimeout = setTimeout(() => {\n        dispatch('DID_UPDATE_ITEMS', { items: getActiveItems(state.items) });\n    }, 0);\n};\n\nconst optionalPromise = (fn, ...params) =>\n    new Promise(resolve => {\n        if (!fn) {\n            return resolve(true);\n        }\n\n        const result = fn(...params);\n\n        if (result == null) {\n            return resolve(true);\n        }\n\n        if (typeof result === 'boolean') {\n            return resolve(result);\n        }\n\n        if (typeof result.then === 'function') {\n            result.then(resolve);\n        }\n    });\n\nconst sortItems = (state, compare) => {\n    state.items.sort((a, b) => compare(createItemAPI(a), createItemAPI(b)));\n};\n\n// returns item based on state\nconst getItemByQueryFromState = (state, itemHandler) => ({\n    query,\n    success = () => {},\n    failure = () => {},\n    ...options\n} = {}) => {\n    const item = getItemByQuery(state.items, query);\n    if (!item) {\n        failure({\n            error: createResponse('error', 0, 'Item not found'),\n            file: null,\n        });\n        return;\n    }\n    itemHandler(item, success, failure, options || {});\n};\n\nconst actions = (dispatch, query, state) => ({\n    /**\n     * Aborts all ongoing processes\n     */\n    ABORT_ALL: () => {\n        getActiveItems(state.items).forEach(item => {\n            item.freeze();\n            item.abortLoad();\n            item.abortProcessing();\n        });\n    },\n\n    /**\n     * Sets initial files\n     */\n    DID_SET_FILES: ({ value = [] }) => {\n        // map values to file objects\n        const files = value.map(file => ({\n            source: file.source ? file.source : file,\n            options: file.options,\n        }));\n\n        // loop over files, if file is in list, leave it be, if not, remove\n        // test if items should be moved\n        let activeItems = getActiveItems(state.items);\n\n        activeItems.forEach(item => {\n            // if item not is in new value, remove\n            if (!files.find(file => file.source === item.source || file.source === item.file)) {\n                dispatch('REMOVE_ITEM', { query: item, remove: false });\n            }\n        });\n\n        // add new files\n        activeItems = getActiveItems(state.items);\n        files.forEach((file, index) => {\n            // if file is already in list\n            if (activeItems.find(item => item.source === file.source || item.file === file.source))\n                return;\n\n            // not in list, add\n            dispatch('ADD_ITEM', {\n                ...file,\n                interactionMethod: InteractionMethod.NONE,\n                index,\n            });\n        });\n    },\n\n    DID_UPDATE_ITEM_METADATA: ({ id, action, change }) => {\n        // don't do anything\n        if (change.silent) return;\n\n        // if is called multiple times in close succession we combined all calls together to save resources\n        clearTimeout(state.itemUpdateTimeout);\n        state.itemUpdateTimeout = setTimeout(() => {\n            const item = getItemById(state.items, id);\n\n            // only revert and attempt to upload when we're uploading to a server\n            if (!query('IS_ASYNC')) {\n                // should we update the output data\n                applyFilterChain('SHOULD_PREPARE_OUTPUT', false, {\n                    item,\n                    query,\n                    action,\n                    change,\n                }).then(shouldPrepareOutput => {\n                    // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                    const beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                    if (beforePrepareFile)\n                        shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                    if (!shouldPrepareOutput) return;\n\n                    dispatch(\n                        'REQUEST_PREPARE_OUTPUT',\n                        {\n                            query: id,\n                            item,\n                            success: file => {\n                                dispatch('DID_PREPARE_OUTPUT', { id, file });\n                            },\n                        },\n                        true\n                    );\n                });\n\n                return;\n            }\n\n            // if is local item we need to enable upload button so change can be propagated to server\n            if (item.origin === FileOrigin.LOCAL) {\n                dispatch('DID_LOAD_ITEM', {\n                    id: item.id,\n                    error: null,\n                    serverFileReference: item.source,\n                });\n            }\n\n            // for async scenarios\n            const upload = () => {\n                // we push this forward a bit so the interface is updated correctly\n                setTimeout(() => {\n                    dispatch('REQUEST_ITEM_PROCESSING', { query: id });\n                }, 32);\n            };\n\n            const revert = doUpload => {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                )\n                    .then(doUpload ? upload : () => {})\n                    .catch(() => {});\n            };\n\n            const abort = doUpload => {\n                item.abortProcessing().then(doUpload ? upload : () => {});\n            };\n\n            // if we should re-upload the file immediately\n            if (item.status === ItemStatus.PROCESSING_COMPLETE) {\n                return revert(state.options.instantUpload);\n            }\n\n            // if currently uploading, cancel upload\n            if (item.status === ItemStatus.PROCESSING) {\n                return abort(state.options.instantUpload);\n            }\n\n            if (state.options.instantUpload) {\n                upload();\n            }\n        }, 0);\n    },\n\n    MOVE_ITEM: ({ query, index }) => {\n        const item = getItemByQuery(state.items, query);\n        if (!item) return;\n        const currentIndex = state.items.indexOf(item);\n        index = limit(index, 0, state.items.length - 1);\n        if (currentIndex === index) return;\n        state.items.splice(index, 0, state.items.splice(currentIndex, 1)[0]);\n    },\n\n    SORT: ({ compare }) => {\n        sortItems(state, compare);\n        dispatch('DID_SORT_ITEMS', {\n            items: query('GET_ACTIVE_ITEMS'),\n        });\n    },\n\n    ADD_ITEMS: ({ items, index, interactionMethod, success = () => {}, failure = () => {} }) => {\n        let currentIndex = index;\n\n        if (index === -1 || typeof index === 'undefined') {\n            const insertLocation = query('GET_ITEM_INSERT_LOCATION');\n            const totalItems = query('GET_TOTAL_ITEMS');\n            currentIndex = insertLocation === 'before' ? 0 : totalItems;\n        }\n\n        const ignoredFiles = query('GET_IGNORED_FILES');\n        const isValidFile = source =>\n            isFile(source) ? !ignoredFiles.includes(source.name.toLowerCase()) : !isEmpty(source);\n        const validItems = items.filter(isValidFile);\n\n        const promises = validItems.map(\n            source =>\n                new Promise((resolve, reject) => {\n                    dispatch('ADD_ITEM', {\n                        interactionMethod,\n                        source: source.source || source,\n                        success: resolve,\n                        failure: reject,\n                        index: currentIndex++,\n                        options: source.options || {},\n                    });\n                })\n        );\n\n        Promise.all(promises)\n            .then(success)\n            .catch(failure);\n    },\n\n    /**\n     * @param source\n     * @param index\n     * @param interactionMethod\n     */\n    ADD_ITEM: ({\n        source,\n        index = -1,\n        interactionMethod,\n        success = () => {},\n        failure = () => {},\n        options = {},\n    }) => {\n        // if no source supplied\n        if (isEmpty(source)) {\n            failure({\n                error: createResponse('error', 0, 'No source'),\n                file: null,\n            });\n            return;\n        }\n\n        // filter out invalid file items, used to filter dropped directory contents\n        if (isFile(source) && state.options.ignoredFiles.includes(source.name.toLowerCase())) {\n            // fail silently\n            return;\n        }\n\n        // test if there's still room in the list of files\n        if (!hasRoomForItem(state)) {\n            // if multiple allowed, we can't replace\n            // or if only a single item is allowed but we're not allowed to replace it we exit\n            if (\n                state.options.allowMultiple ||\n                (!state.options.allowMultiple && !state.options.allowReplace)\n            ) {\n                const error = createResponse('warning', 0, 'Max files');\n\n                dispatch('DID_THROW_MAX_FILES', {\n                    source,\n                    error,\n                });\n\n                failure({ error, file: null });\n\n                return;\n            }\n\n            // let's replace the item\n            // id of first item we're about to remove\n            const item = getActiveItems(state.items)[0];\n\n            // if has been processed remove it from the server as well\n            if (\n                item.status === ItemStatus.PROCESSING_COMPLETE ||\n                item.status === ItemStatus.PROCESSING_REVERT_ERROR\n            ) {\n                const forceRevert = query('GET_FORCE_REVERT');\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    forceRevert\n                )\n                    .then(() => {\n                        if (!forceRevert) return;\n\n                        // try to add now\n                        dispatch('ADD_ITEM', {\n                            source,\n                            index,\n                            interactionMethod,\n                            success,\n                            failure,\n                            options,\n                        });\n                    })\n                    .catch(() => {}); // no need to handle this catch state for now\n\n                if (forceRevert) return;\n            }\n\n            // remove first item as it will be replaced by this item\n            dispatch('REMOVE_ITEM', { query: item.id });\n        }\n\n        // where did the file originate\n        const origin =\n            options.type === 'local'\n                ? FileOrigin.LOCAL\n                : options.type === 'limbo'\n                ? FileOrigin.LIMBO\n                : FileOrigin.INPUT;\n\n        // create a new blank item\n        const item = createItem(\n            // where did this file come from\n            origin,\n\n            // an input file never has a server file reference\n            origin === FileOrigin.INPUT ? null : source,\n\n            // file mock data, if defined\n            options.file\n        );\n\n        // set initial meta data\n        Object.keys(options.metadata || {}).forEach(key => {\n            item.setMetadata(key, options.metadata[key]);\n        });\n\n        // created the item, let plugins add methods\n        applyFilters('DID_CREATE_ITEM', item, { query, dispatch });\n\n        // where to insert new items\n        const itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n\n        // adjust index if is not allowed to pick location\n        if (!state.options.itemInsertLocationFreedom) {\n            index = itemInsertLocation === 'before' ? -1 : state.items.length;\n        }\n\n        // add item to list\n        insertItem(state.items, item, index);\n\n        // sort items in list\n        if (isFunction(itemInsertLocation) && source) {\n            sortItems(state, itemInsertLocation);\n        }\n\n        // get a quick reference to the item id\n        const id = item.id;\n\n        // observe item events\n        item.on('init', () => {\n            dispatch('DID_INIT_ITEM', { id });\n        });\n\n        item.on('load-init', () => {\n            dispatch('DID_START_ITEM_LOAD', { id });\n        });\n\n        item.on('load-meta', () => {\n            dispatch('DID_UPDATE_ITEM_META', { id });\n        });\n\n        item.on('load-progress', progress => {\n            dispatch('DID_UPDATE_ITEM_LOAD_PROGRESS', { id, progress });\n        });\n\n        item.on('load-request-error', error => {\n            const mainStatus = dynamicLabel(state.options.labelFileLoadError)(error);\n\n            // is client error, no way to recover\n            if (error.code >= 400 && error.code < 500) {\n                dispatch('DID_THROW_ITEM_INVALID', {\n                    id,\n                    error,\n                    status: {\n                        main: mainStatus,\n                        sub: `${error.code} (${error.body})`,\n                    },\n                });\n\n                // reject the file so can be dealt with through API\n                failure({ error, file: createItemAPI(item) });\n                return;\n            }\n\n            // is possible server error, so might be possible to retry\n            dispatch('DID_THROW_ITEM_LOAD_ERROR', {\n                id,\n                error,\n                status: {\n                    main: mainStatus,\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('load-file-error', error => {\n            dispatch('DID_THROW_ITEM_INVALID', {\n                id,\n                error: error.status,\n                status: error.status,\n            });\n            failure({ error: error.status, file: createItemAPI(item) });\n        });\n\n        item.on('load-abort', () => {\n            dispatch('REMOVE_ITEM', { query: id });\n        });\n\n        item.on('load-skip', () => {\n            item.on('metadata-update', change => {\n                if (!isFile(item.file)) return;\n                dispatch('DID_UPDATE_ITEM_METADATA', { id, change });\n            });\n\n            dispatch('COMPLETE_LOAD_ITEM', {\n                query: id,\n                item,\n                data: {\n                    source,\n                    success,\n                },\n            });\n        });\n\n        item.on('load', () => {\n            const handleAdd = shouldAdd => {\n                // no should not add this file\n                if (!shouldAdd) {\n                    dispatch('REMOVE_ITEM', {\n                        query: id,\n                    });\n                    return;\n                }\n\n                // now interested in metadata updates\n                item.on('metadata-update', change => {\n                    dispatch('DID_UPDATE_ITEM_METADATA', { id, change });\n                });\n\n                // let plugins decide if the output data should be prepared at this point\n                // means we'll do this and wait for idle state\n                applyFilterChain('SHOULD_PREPARE_OUTPUT', false, { item, query }).then(\n                    shouldPrepareOutput => {\n                        // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                        const beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                        if (beforePrepareFile)\n                            shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                        const loadComplete = () => {\n                            dispatch('COMPLETE_LOAD_ITEM', {\n                                query: id,\n                                item,\n                                data: {\n                                    source,\n                                    success,\n                                },\n                            });\n\n                            listUpdated(dispatch, state);\n                        };\n\n                        // exit\n                        if (shouldPrepareOutput) {\n                            // wait for idle state and then run PREPARE_OUTPUT\n                            dispatch(\n                                'REQUEST_PREPARE_OUTPUT',\n                                {\n                                    query: id,\n                                    item,\n                                    success: file => {\n                                        dispatch('DID_PREPARE_OUTPUT', { id, file });\n                                        loadComplete();\n                                    },\n                                },\n                                true\n                            );\n\n                            return;\n                        }\n\n                        loadComplete();\n                    }\n                );\n            };\n\n            // item loaded, allow plugins to\n            // - read data (quickly)\n            // - add metadata\n            applyFilterChain('DID_LOAD_ITEM', item, { query, dispatch })\n                .then(() => {\n                    optionalPromise(query('GET_BEFORE_ADD_FILE'), createItemAPI(item)).then(\n                        handleAdd\n                    );\n                })\n                .catch(e => {\n                    if (!e || !e.error || !e.status) return handleAdd(false);\n                    dispatch('DID_THROW_ITEM_INVALID', {\n                        id,\n                        error: e.error,\n                        status: e.status,\n                    });\n                });\n        });\n\n        item.on('process-start', () => {\n            dispatch('DID_START_ITEM_PROCESSING', { id });\n        });\n\n        item.on('process-progress', progress => {\n            dispatch('DID_UPDATE_ITEM_PROCESS_PROGRESS', { id, progress });\n        });\n\n        item.on('process-error', error => {\n            dispatch('DID_THROW_ITEM_PROCESSING_ERROR', {\n                id,\n                error,\n                status: {\n                    main: dynamicLabel(state.options.labelFileProcessingError)(error),\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('process-revert-error', error => {\n            dispatch('DID_THROW_ITEM_PROCESSING_REVERT_ERROR', {\n                id,\n                error,\n                status: {\n                    main: dynamicLabel(state.options.labelFileProcessingRevertError)(error),\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('process-complete', serverFileReference => {\n            dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                id,\n                error: null,\n                serverFileReference,\n            });\n            dispatch('DID_DEFINE_VALUE', { id, value: serverFileReference });\n        });\n\n        item.on('process-abort', () => {\n            dispatch('DID_ABORT_ITEM_PROCESSING', { id });\n        });\n\n        item.on('process-revert', () => {\n            dispatch('DID_REVERT_ITEM_PROCESSING', { id });\n            dispatch('DID_DEFINE_VALUE', { id, value: null });\n        });\n\n        // let view know the item has been inserted\n        dispatch('DID_ADD_ITEM', { id, index, interactionMethod });\n\n        listUpdated(dispatch, state);\n\n        // start loading the source\n        const { url, load, restore, fetch } = state.options.server || {};\n\n        item.load(\n            source,\n\n            // this creates a function that loads the file based on the type of file (string, base64, blob, file) and location of file (local, remote, limbo)\n            createFileLoader(\n                origin === FileOrigin.INPUT\n                    ? // input, if is remote, see if should use custom fetch, else use default fetchBlob\n                      isString(source) && isExternalURL(source)\n                        ? fetch\n                            ? createFetchFunction(url, fetch)\n                            : fetchBlob // remote url\n                        : fetchBlob // try to fetch url\n                    : // limbo or local\n                    origin === FileOrigin.LIMBO\n                    ? createFetchFunction(url, restore) // limbo\n                    : createFetchFunction(url, load) // local\n            ),\n\n            // called when the file is loaded so it can be piped through the filters\n            (file, success, error) => {\n                // let's process the file\n                applyFilterChain('LOAD_FILE', file, { query })\n                    .then(success)\n                    .catch(error);\n            }\n        );\n    },\n\n    REQUEST_PREPARE_OUTPUT: ({ item, success, failure = () => {} }) => {\n        // error response if item archived\n        const err = {\n            error: createResponse('error', 0, 'Item not found'),\n            file: null,\n        };\n\n        // don't handle archived items, an item could have been archived (load aborted) while waiting to be prepared\n        if (item.archived) return failure(err);\n\n        // allow plugins to alter the file data\n        applyFilterChain('PREPARE_OUTPUT', item.file, { query, item }).then(result => {\n            applyFilterChain('COMPLETE_PREPARE_OUTPUT', result, { query, item }).then(result => {\n                // don't handle archived items, an item could have been archived (load aborted) while being prepared\n                if (item.archived) return failure(err);\n\n                // we done!\n                success(result);\n            });\n        });\n    },\n\n    COMPLETE_LOAD_ITEM: ({ item, data }) => {\n        const { success, source } = data;\n\n        // sort items in list\n        const itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n        if (isFunction(itemInsertLocation) && source) {\n            sortItems(state, itemInsertLocation);\n        }\n\n        // let interface know the item has loaded\n        dispatch('DID_LOAD_ITEM', {\n            id: item.id,\n            error: null,\n            serverFileReference: item.origin === FileOrigin.INPUT ? null : source,\n        });\n\n        // item has been successfully loaded and added to the\n        // list of items so can now be safely returned for use\n        success(createItemAPI(item));\n\n        // if this is a local server file we need to show a different state\n        if (item.origin === FileOrigin.LOCAL) {\n            dispatch('DID_LOAD_LOCAL_ITEM', { id: item.id });\n            return;\n        }\n\n        // if is a temp server file we prevent async upload call here (as the file is already on the server)\n        if (item.origin === FileOrigin.LIMBO) {\n            dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                id: item.id,\n                error: null,\n                serverFileReference: source,\n            });\n\n            dispatch('DID_DEFINE_VALUE', {\n                id: item.id,\n                value: item.serverId || source,\n            });\n            return;\n        }\n\n        // id we are allowed to upload the file immediately, lets do it\n        if (query('IS_ASYNC') && state.options.instantUpload) {\n            dispatch('REQUEST_ITEM_PROCESSING', { query: item.id });\n        }\n    },\n\n    RETRY_ITEM_LOAD: getItemByQueryFromState(state, item => {\n        // try loading the source one more time\n        item.retryLoad();\n    }),\n\n    REQUEST_ITEM_PREPARE: getItemByQueryFromState(state, (item, success, failure) => {\n        dispatch(\n            'REQUEST_PREPARE_OUTPUT',\n            {\n                query: item.id,\n                item,\n                success: file => {\n                    dispatch('DID_PREPARE_OUTPUT', { id: item.id, file });\n                    success({\n                        file: item,\n                        output: file,\n                    });\n                },\n                failure,\n            },\n            true\n        );\n    }),\n\n    REQUEST_ITEM_PROCESSING: getItemByQueryFromState(state, (item, success, failure) => {\n        // cannot be queued (or is already queued)\n        const itemCanBeQueuedForProcessing =\n            // waiting for something\n            item.status === ItemStatus.IDLE ||\n            // processing went wrong earlier\n            item.status === ItemStatus.PROCESSING_ERROR;\n\n        // not ready to be processed\n        if (!itemCanBeQueuedForProcessing) {\n            const processNow = () =>\n                dispatch('REQUEST_ITEM_PROCESSING', { query: item, success, failure });\n\n            const process = () => (document.hidden ? processNow() : setTimeout(processNow, 32));\n\n            // if already done processing or tried to revert but didn't work, try again\n            if (\n                item.status === ItemStatus.PROCESSING_COMPLETE ||\n                item.status === ItemStatus.PROCESSING_REVERT_ERROR\n            ) {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                )\n                    .then(process)\n                    .catch(() => {}); // don't continue with processing if something went wrong\n            } else if (item.status === ItemStatus.PROCESSING) {\n                item.abortProcessing().then(process);\n            }\n\n            return;\n        }\n\n        // already queued for processing\n        if (item.status === ItemStatus.PROCESSING_QUEUED) return;\n\n        item.requestProcessing();\n\n        dispatch('DID_REQUEST_ITEM_PROCESSING', { id: item.id });\n\n        dispatch('PROCESS_ITEM', { query: item, success, failure }, true);\n    }),\n\n    PROCESS_ITEM: getItemByQueryFromState(state, (item, success, failure) => {\n        const maxParallelUploads = query('GET_MAX_PARALLEL_UPLOADS');\n        const totalCurrentUploads = query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING).length;\n\n        // queue and wait till queue is freed up\n        if (totalCurrentUploads === maxParallelUploads) {\n            // queue for later processing\n            state.processingQueue.push({\n                id: item.id,\n                success,\n                failure,\n            });\n\n            // stop it!\n            return;\n        }\n\n        // if was not queued or is already processing exit here\n        if (item.status === ItemStatus.PROCESSING) return;\n\n        const processNext = () => {\n            // process queueud items\n            const queueEntry = state.processingQueue.shift();\n\n            // no items left\n            if (!queueEntry) return;\n\n            // get item reference\n            const { id, success, failure } = queueEntry;\n            const itemReference = getItemByQuery(state.items, id);\n\n            // if item was archived while in queue, jump to next\n            if (!itemReference || itemReference.archived) {\n                processNext();\n                return;\n            }\n\n            // process queued item\n            dispatch('PROCESS_ITEM', { query: id, success, failure }, true);\n        };\n\n        // we done function\n        item.onOnce('process-complete', () => {\n            success(createItemAPI(item));\n            processNext();\n\n            // if origin is local, and we're instant uploading, trigger remove of original\n            // as revert will remove file from list\n            const server = state.options.server;\n            const instantUpload = state.options.instantUpload;\n            if (instantUpload && item.origin === FileOrigin.LOCAL && isFunction(server.remove)) {\n                const noop = () => {};\n                item.origin = FileOrigin.LIMBO;\n                state.options.server.remove(item.source, noop, noop);\n            }\n\n            // All items processed? No errors?\n            const allItemsProcessed =\n                query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING_COMPLETE).length ===\n                state.items.length;\n            if (allItemsProcessed) {\n                dispatch('DID_COMPLETE_ITEM_PROCESSING_ALL');\n            }\n        });\n\n        // we error function\n        item.onOnce('process-error', error => {\n            failure({ error, file: createItemAPI(item) });\n            processNext();\n        });\n\n        // abort function\n        item.onOnce('process-abort', () => {\n            processNext();\n        });\n\n        // start file processing\n        const options = state.options;\n        item.process(\n            createFileProcessor(\n                createProcessorFunction(options.server.url, options.server.process, options.name, {\n                    chunkTransferId: item.transferId,\n                    chunkServer: options.server.patch,\n                    chunkUploads: options.chunkUploads,\n                    chunkForce: options.chunkForce,\n                    chunkSize: options.chunkSize,\n                    chunkRetryDelays: options.chunkRetryDelays,\n                }),\n                {\n                    allowMinimumUploadDuration: query('GET_ALLOW_MINIMUM_UPLOAD_DURATION'),\n                }\n            ),\n            // called when the file is about to be processed so it can be piped through the transform filters\n            (file, success, error) => {\n                // allow plugins to alter the file data\n                applyFilterChain('PREPARE_OUTPUT', file, { query, item })\n                    .then(file => {\n                        dispatch('DID_PREPARE_OUTPUT', { id: item.id, file });\n\n                        success(file);\n                    })\n                    .catch(error);\n            }\n        );\n    }),\n\n    RETRY_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        dispatch('REQUEST_ITEM_PROCESSING', { query: item });\n    }),\n\n    REQUEST_REMOVE_ITEM: getItemByQueryFromState(state, item => {\n        optionalPromise(query('GET_BEFORE_REMOVE_FILE'), createItemAPI(item)).then(shouldRemove => {\n            if (!shouldRemove) {\n                return;\n            }\n            dispatch('REMOVE_ITEM', { query: item });\n        });\n    }),\n\n    RELEASE_ITEM: getItemByQueryFromState(state, item => {\n        item.release();\n    }),\n\n    REMOVE_ITEM: getItemByQueryFromState(state, (item, success, failure, options) => {\n        const removeFromView = () => {\n            // get id reference\n            const id = item.id;\n\n            // archive the item, this does not remove it from the list\n            getItemById(state.items, id).archive();\n\n            // tell the view the item has been removed\n            dispatch('DID_REMOVE_ITEM', { error: null, id, item });\n\n            // now the list has been modified\n            listUpdated(dispatch, state);\n\n            // correctly removed\n            success(createItemAPI(item));\n        };\n\n        // if this is a local file and the `server.remove` function has been configured,\n        // send source there so dev can remove file from server\n        const server = state.options.server;\n        if (\n            item.origin === FileOrigin.LOCAL &&\n            server &&\n            isFunction(server.remove) &&\n            options.remove !== false\n        ) {\n            dispatch('DID_START_ITEM_REMOVE', { id: item.id });\n\n            server.remove(\n                item.source,\n                () => removeFromView(),\n                status => {\n                    dispatch('DID_THROW_ITEM_REMOVE_ERROR', {\n                        id: item.id,\n                        error: createResponse('error', 0, status, null),\n                        status: {\n                            main: dynamicLabel(state.options.labelFileRemoveError)(status),\n                            sub: state.options.labelTapToRetry,\n                        },\n                    });\n                }\n            );\n        } else {\n            // if is requesting revert and can revert need to call revert handler (not calling request_ because that would also trigger beforeRemoveHook)\n            if (\n                (options.revert && item.origin !== FileOrigin.LOCAL && item.serverId !== null) ||\n                // if chunked uploads are enabled and we're uploading in chunks for this specific file\n                // or if the file isn't big enough for chunked uploads but chunkForce is set then call\n                // revert before removing from the view...\n                (state.options.chunkUploads && item.file.size > state.options.chunkSize) ||\n                (state.options.chunkUploads && state.options.chunkForce)\n            ) {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                );\n            }\n\n            // can now safely remove from view\n            removeFromView();\n        }\n    }),\n\n    ABORT_ITEM_LOAD: getItemByQueryFromState(state, item => {\n        item.abortLoad();\n    }),\n\n    ABORT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        // test if is already processed\n        if (item.serverId) {\n            dispatch('REVERT_ITEM_PROCESSING', { id: item.id });\n            return;\n        }\n\n        // abort\n        item.abortProcessing().then(() => {\n            const shouldRemove = state.options.instantUpload;\n            if (shouldRemove) {\n                dispatch('REMOVE_ITEM', { query: item.id });\n            }\n        });\n    }),\n\n    REQUEST_REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        // not instant uploading, revert immediately\n        if (!state.options.instantUpload) {\n            dispatch('REVERT_ITEM_PROCESSING', { query: item });\n            return;\n        }\n\n        // if we're instant uploading the file will also be removed if we revert,\n        // so if a before remove file hook is defined we need to run it now\n        const handleRevert = shouldRevert => {\n            if (!shouldRevert) return;\n            dispatch('REVERT_ITEM_PROCESSING', { query: item });\n        };\n\n        const fn = query('GET_BEFORE_REMOVE_FILE');\n        if (!fn) {\n            return handleRevert(true);\n        }\n\n        const requestRemoveResult = fn(createItemAPI(item));\n        if (requestRemoveResult == null) {\n            // undefined or null\n            return handleRevert(true);\n        }\n\n        if (typeof requestRemoveResult === 'boolean') {\n            return handleRevert(requestRemoveResult);\n        }\n\n        if (typeof requestRemoveResult.then === 'function') {\n            requestRemoveResult.then(handleRevert);\n        }\n    }),\n\n    REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        item.revert(\n            createRevertFunction(state.options.server.url, state.options.server.revert),\n            query('GET_FORCE_REVERT')\n        )\n            .then(() => {\n                const shouldRemove = state.options.instantUpload || isMockItem(item);\n                if (shouldRemove) {\n                    dispatch('REMOVE_ITEM', { query: item.id });\n                }\n            })\n            .catch(() => {});\n    }),\n\n    SET_OPTIONS: ({ options }) => {\n        // get all keys passed\n        const optionKeys = Object.keys(options);\n\n        // get prioritized keyed to include (remove once not in options object)\n        const prioritizedOptionKeys = PrioritizedOptions.filter(key => optionKeys.includes(key));\n\n        // order the keys, prioritized first, then rest\n        const orderedOptionKeys = [\n            // add prioritized first if passed to options, else remove\n            ...prioritizedOptionKeys,\n\n            // prevent duplicate keys\n            ...Object.keys(options).filter(key => !prioritizedOptionKeys.includes(key)),\n        ];\n\n        // dispatch set event for each option\n        orderedOptionKeys.forEach(key => {\n            dispatch(`SET_${fromCamels(key, '_').toUpperCase()}`, {\n                value: options[key],\n            });\n        });\n    },\n});\n\nconst PrioritizedOptions = [\n    'server', // must be processed before \"files\"\n];\n\nconst formatFilename = name => name;\n\nconst createElement$1 = tagName => {\n    return document.createElement(tagName);\n};\n\nconst text = (node, value) => {\n    let textNode = node.childNodes[0];\n    if (!textNode) {\n        textNode = document.createTextNode(value);\n        node.appendChild(textNode);\n    } else if (value !== textNode.nodeValue) {\n        textNode.nodeValue = value;\n    }\n};\n\nconst polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {\n    const angleInRadians = (((angleInDegrees % 360) - 90) * Math.PI) / 180.0;\n    return {\n        x: centerX + radius * Math.cos(angleInRadians),\n        y: centerY + radius * Math.sin(angleInRadians),\n    };\n};\n\nconst describeArc = (x, y, radius, startAngle, endAngle, arcSweep) => {\n    const start = polarToCartesian(x, y, radius, endAngle);\n    const end = polarToCartesian(x, y, radius, startAngle);\n    return ['M', start.x, start.y, 'A', radius, radius, 0, arcSweep, 0, end.x, end.y].join(' ');\n};\n\nconst percentageArc = (x, y, radius, from, to) => {\n    let arcSweep = 1;\n    if (to > from && to - from <= 0.5) {\n        arcSweep = 0;\n    }\n    if (from > to && from - to >= 0.5) {\n        arcSweep = 0;\n    }\n    return describeArc(\n        x,\n        y,\n        radius,\n        Math.min(0.9999, from) * 360,\n        Math.min(0.9999, to) * 360,\n        arcSweep\n    );\n};\n\nconst create = ({ root, props }) => {\n    // start at 0\n    props.spin = false;\n    props.progress = 0;\n    props.opacity = 0;\n\n    // svg\n    const svg = createElement('svg');\n    root.ref.path = createElement('path', {\n        'stroke-width': 2,\n        'stroke-linecap': 'round',\n    });\n    svg.appendChild(root.ref.path);\n\n    root.ref.svg = svg;\n\n    root.appendChild(svg);\n};\n\nconst write = ({ root, props }) => {\n    if (props.opacity === 0) {\n        return;\n    }\n\n    if (props.align) {\n        root.element.dataset.align = props.align;\n    }\n\n    // get width of stroke\n    const ringStrokeWidth = parseInt(attr(root.ref.path, 'stroke-width'), 10);\n\n    // calculate size of ring\n    const size = root.rect.element.width * 0.5;\n\n    // ring state\n    let ringFrom = 0;\n    let ringTo = 0;\n\n    // now in busy mode\n    if (props.spin) {\n        ringFrom = 0;\n        ringTo = 0.5;\n    } else {\n        ringFrom = 0;\n        ringTo = props.progress;\n    }\n\n    // get arc path\n    const coordinates = percentageArc(size, size, size - ringStrokeWidth, ringFrom, ringTo);\n\n    // update progress bar\n    attr(root.ref.path, 'd', coordinates);\n\n    // hide while contains 0 value\n    attr(root.ref.path, 'stroke-opacity', props.spin || props.progress > 0 ? 1 : 0);\n};\n\nconst progressIndicator = createView({\n    tag: 'div',\n    name: 'progress-indicator',\n    ignoreRectUpdate: true,\n    ignoreRect: true,\n    create,\n    write,\n    mixins: {\n        apis: ['progress', 'spin', 'align'],\n        styles: ['opacity'],\n        animations: {\n            opacity: { type: 'tween', duration: 500 },\n            progress: {\n                type: 'spring',\n                stiffness: 0.95,\n                damping: 0.65,\n                mass: 10,\n            },\n        },\n    },\n});\n\nconst create$1 = ({ root, props }) => {\n    root.element.innerHTML = (props.icon || '') + `<span>${props.label}</span>`;\n\n    props.isDisabled = false;\n};\n\nconst write$1 = ({ root, props }) => {\n    const { isDisabled } = props;\n    const shouldDisable = root.query('GET_DISABLED') || props.opacity === 0;\n\n    if (shouldDisable && !isDisabled) {\n        props.isDisabled = true;\n        attr(root.element, 'disabled', 'disabled');\n    } else if (!shouldDisable && isDisabled) {\n        props.isDisabled = false;\n        root.element.removeAttribute('disabled');\n    }\n};\n\nconst fileActionButton = createView({\n    tag: 'button',\n    attributes: {\n        type: 'button',\n    },\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    name: 'file-action-button',\n    mixins: {\n        apis: ['label'],\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            translateX: 'spring',\n            translateY: 'spring',\n            opacity: { type: 'tween', duration: 250 },\n        },\n        listeners: true,\n    },\n    create: create$1,\n    write: write$1,\n});\n\nconst toNaturalFileSize = (bytes, decimalSeparator = '.', base = 1000, options = {}) => {\n    const {\n        labelBytes = 'bytes',\n        labelKilobytes = 'KB',\n        labelMegabytes = 'MB',\n        labelGigabytes = 'GB',\n    } = options;\n\n    // no negative byte sizes\n    bytes = Math.round(Math.abs(bytes));\n\n    const KB = base;\n    const MB = base * base;\n    const GB = base * base * base;\n\n    // just bytes\n    if (bytes < KB) {\n        return `${bytes} ${labelBytes}`;\n    }\n\n    // kilobytes\n    if (bytes < MB) {\n        return `${Math.floor(bytes / KB)} ${labelKilobytes}`;\n    }\n\n    // megabytes\n    if (bytes < GB) {\n        return `${removeDecimalsWhenZero(bytes / MB, 1, decimalSeparator)} ${labelMegabytes}`;\n    }\n\n    // gigabytes\n    return `${removeDecimalsWhenZero(bytes / GB, 2, decimalSeparator)} ${labelGigabytes}`;\n};\n\nconst removeDecimalsWhenZero = (value, decimalCount, separator) => {\n    return value\n        .toFixed(decimalCount)\n        .split('.')\n        .filter(part => part !== '0')\n        .join(separator);\n};\n\nconst create$2 = ({ root, props }) => {\n    // filename\n    const fileName = createElement$1('span');\n    fileName.className = 'filepond--file-info-main';\n    // hide for screenreaders\n    // the file is contained in a fieldset with legend that contains the filename\n    // no need to read it twice\n    attr(fileName, 'aria-hidden', 'true');\n    root.appendChild(fileName);\n    root.ref.fileName = fileName;\n\n    // filesize\n    const fileSize = createElement$1('span');\n    fileSize.className = 'filepond--file-info-sub';\n    root.appendChild(fileSize);\n    root.ref.fileSize = fileSize;\n\n    // set initial values\n    text(fileSize, root.query('GET_LABEL_FILE_WAITING_FOR_SIZE'));\n    text(fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n};\n\nconst updateFile = ({ root, props }) => {\n    text(\n        root.ref.fileSize,\n        toNaturalFileSize(\n            root.query('GET_ITEM_SIZE', props.id),\n            '.',\n            root.query('GET_FILE_SIZE_BASE'),\n            root.query('GET_FILE_SIZE_LABELS', root.query)\n        )\n    );\n    text(root.ref.fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n};\n\nconst updateFileSizeOnError = ({ root, props }) => {\n    // if size is available don't fallback to unknown size message\n    if (isInt(root.query('GET_ITEM_SIZE', props.id))) {\n        updateFile({ root, props });\n        return;\n    }\n\n    text(root.ref.fileSize, root.query('GET_LABEL_FILE_SIZE_NOT_AVAILABLE'));\n};\n\nconst fileInfo = createView({\n    name: 'file-info',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: updateFile,\n        DID_UPDATE_ITEM_META: updateFile,\n        DID_THROW_ITEM_LOAD_ERROR: updateFileSizeOnError,\n        DID_THROW_ITEM_INVALID: updateFileSizeOnError,\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    create: create$2,\n    mixins: {\n        styles: ['translateX', 'translateY'],\n        animations: {\n            translateX: 'spring',\n            translateY: 'spring',\n        },\n    },\n});\n\nconst toPercentage = value => Math.round(value * 100);\n\nconst create$3 = ({ root }) => {\n    // main status\n    const main = createElement$1('span');\n    main.className = 'filepond--file-status-main';\n    root.appendChild(main);\n    root.ref.main = main;\n\n    // sub status\n    const sub = createElement$1('span');\n    sub.className = 'filepond--file-status-sub';\n    root.appendChild(sub);\n    root.ref.sub = sub;\n\n    didSetItemLoadProgress({ root, action: { progress: null } });\n};\n\nconst didSetItemLoadProgress = ({ root, action }) => {\n    const title =\n        action.progress === null\n            ? root.query('GET_LABEL_FILE_LOADING')\n            : `${root.query('GET_LABEL_FILE_LOADING')} ${toPercentage(action.progress)}%`;\n    text(root.ref.main, title);\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didSetItemProcessProgress = ({ root, action }) => {\n    const title =\n        action.progress === null\n            ? root.query('GET_LABEL_FILE_PROCESSING')\n            : `${root.query('GET_LABEL_FILE_PROCESSING')} ${toPercentage(action.progress)}%`;\n    text(root.ref.main, title);\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didRequestItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didAbortItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_ABORTED'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_RETRY'));\n};\n\nconst didCompleteItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_COMPLETE'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_UNDO'));\n};\n\nconst clear = ({ root }) => {\n    text(root.ref.main, '');\n    text(root.ref.sub, '');\n};\n\nconst error = ({ root, action }) => {\n    text(root.ref.main, action.status.main);\n    text(root.ref.sub, action.status.sub);\n};\n\nconst fileStatus = createView({\n    name: 'file-status',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: clear,\n        DID_REVERT_ITEM_PROCESSING: clear,\n        DID_REQUEST_ITEM_PROCESSING: didRequestItemProcessing,\n        DID_ABORT_ITEM_PROCESSING: didAbortItemProcessing,\n        DID_COMPLETE_ITEM_PROCESSING: didCompleteItemProcessing,\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: didSetItemProcessProgress,\n        DID_UPDATE_ITEM_LOAD_PROGRESS: didSetItemLoadProgress,\n        DID_THROW_ITEM_LOAD_ERROR: error,\n        DID_THROW_ITEM_INVALID: error,\n        DID_THROW_ITEM_PROCESSING_ERROR: error,\n        DID_THROW_ITEM_PROCESSING_REVERT_ERROR: error,\n        DID_THROW_ITEM_REMOVE_ERROR: error,\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    create: create$3,\n    mixins: {\n        styles: ['translateX', 'translateY', 'opacity'],\n        animations: {\n            opacity: { type: 'tween', duration: 250 },\n            translateX: 'spring',\n            translateY: 'spring',\n        },\n    },\n});\n\n/**\n * Button definitions for the file view\n */\n\nconst Buttons = {\n    AbortItemLoad: {\n        label: 'GET_LABEL_BUTTON_ABORT_ITEM_LOAD',\n        action: 'ABORT_ITEM_LOAD',\n        className: 'filepond--action-abort-item-load',\n        align: 'LOAD_INDICATOR_POSITION', // right\n    },\n    RetryItemLoad: {\n        label: 'GET_LABEL_BUTTON_RETRY_ITEM_LOAD',\n        action: 'RETRY_ITEM_LOAD',\n        icon: 'GET_ICON_RETRY',\n        className: 'filepond--action-retry-item-load',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RemoveItem: {\n        label: 'GET_LABEL_BUTTON_REMOVE_ITEM',\n        action: 'REQUEST_REMOVE_ITEM',\n        icon: 'GET_ICON_REMOVE',\n        className: 'filepond--action-remove-item',\n        align: 'BUTTON_REMOVE_ITEM_POSITION', // left\n    },\n    ProcessItem: {\n        label: 'GET_LABEL_BUTTON_PROCESS_ITEM',\n        action: 'REQUEST_ITEM_PROCESSING',\n        icon: 'GET_ICON_PROCESS',\n        className: 'filepond--action-process-item',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    AbortItemProcessing: {\n        label: 'GET_LABEL_BUTTON_ABORT_ITEM_PROCESSING',\n        action: 'ABORT_ITEM_PROCESSING',\n        className: 'filepond--action-abort-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RetryItemProcessing: {\n        label: 'GET_LABEL_BUTTON_RETRY_ITEM_PROCESSING',\n        action: 'RETRY_ITEM_PROCESSING',\n        icon: 'GET_ICON_RETRY',\n        className: 'filepond--action-retry-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RevertItemProcessing: {\n        label: 'GET_LABEL_BUTTON_UNDO_ITEM_PROCESSING',\n        action: 'REQUEST_REVERT_ITEM_PROCESSING',\n        icon: 'GET_ICON_UNDO',\n        className: 'filepond--action-revert-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n};\n\n// make a list of buttons, we can then remove buttons from this list if they're disabled\nconst ButtonKeys = [];\nforin(Buttons, key => {\n    ButtonKeys.push(key);\n});\n\nconst calculateFileInfoOffset = root => {\n    if (getRemoveIndicatorAligment(root) === 'right') return 0;\n    const buttonRect = root.ref.buttonRemoveItem.rect.element;\n    return buttonRect.hidden ? null : buttonRect.width + buttonRect.left;\n};\n\nconst calculateButtonWidth = root => {\n    const buttonRect = root.ref.buttonAbortItemLoad.rect.element;\n    return buttonRect.width;\n};\n\n// Force on full pixels so text stays crips\nconst calculateFileVerticalCenterOffset = root =>\n    Math.floor(root.ref.buttonRemoveItem.rect.element.height / 4);\nconst calculateFileHorizontalCenterOffset = root =>\n    Math.floor(root.ref.buttonRemoveItem.rect.element.left / 2);\n\nconst getLoadIndicatorAlignment = root => root.query('GET_STYLE_LOAD_INDICATOR_POSITION');\nconst getProcessIndicatorAlignment = root => root.query('GET_STYLE_PROGRESS_INDICATOR_POSITION');\nconst getRemoveIndicatorAligment = root => root.query('GET_STYLE_BUTTON_REMOVE_ITEM_POSITION');\n\nconst DefaultStyle = {\n    buttonAbortItemLoad: { opacity: 0 },\n    buttonRetryItemLoad: { opacity: 0 },\n    buttonRemoveItem: { opacity: 0 },\n    buttonProcessItem: { opacity: 0 },\n    buttonAbortItemProcessing: { opacity: 0 },\n    buttonRetryItemProcessing: { opacity: 0 },\n    buttonRevertItemProcessing: { opacity: 0 },\n    loadProgressIndicator: { opacity: 0, align: getLoadIndicatorAlignment },\n    processProgressIndicator: { opacity: 0, align: getProcessIndicatorAlignment },\n    processingCompleteIndicator: { opacity: 0, scaleX: 0.75, scaleY: 0.75 },\n    info: { translateX: 0, translateY: 0, opacity: 0 },\n    status: { translateX: 0, translateY: 0, opacity: 0 },\n};\n\nconst IdleStyle = {\n    buttonRemoveItem: { opacity: 1 },\n    buttonProcessItem: { opacity: 1 },\n    info: { translateX: calculateFileInfoOffset },\n    status: { translateX: calculateFileInfoOffset },\n};\n\nconst ProcessingStyle = {\n    buttonAbortItemProcessing: { opacity: 1 },\n    processProgressIndicator: { opacity: 1 },\n    status: { opacity: 1 },\n};\n\nconst StyleMap = {\n    DID_THROW_ITEM_INVALID: {\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { translateX: calculateFileInfoOffset, opacity: 1 },\n    },\n    DID_START_ITEM_LOAD: {\n        buttonAbortItemLoad: { opacity: 1 },\n        loadProgressIndicator: { opacity: 1 },\n        status: { opacity: 1 },\n    },\n    DID_THROW_ITEM_LOAD_ERROR: {\n        buttonRetryItemLoad: { opacity: 1 },\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1 },\n    },\n    DID_START_ITEM_REMOVE: {\n        processProgressIndicator: { opacity: 1, align: getRemoveIndicatorAligment },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 0 },\n    },\n    DID_THROW_ITEM_REMOVE_ERROR: {\n        processProgressIndicator: { opacity: 0, align: getRemoveIndicatorAligment },\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1, translateX: calculateFileInfoOffset },\n    },\n    DID_LOAD_ITEM: IdleStyle,\n    DID_LOAD_LOCAL_ITEM: {\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { translateX: calculateFileInfoOffset },\n    },\n    DID_START_ITEM_PROCESSING: ProcessingStyle,\n    DID_REQUEST_ITEM_PROCESSING: ProcessingStyle,\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: ProcessingStyle,\n    DID_COMPLETE_ITEM_PROCESSING: {\n        buttonRevertItemProcessing: { opacity: 1 },\n        info: { opacity: 1 },\n        status: { opacity: 1 },\n    },\n    DID_THROW_ITEM_PROCESSING_ERROR: {\n        buttonRemoveItem: { opacity: 1 },\n        buttonRetryItemProcessing: { opacity: 1 },\n        status: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n    },\n    DID_THROW_ITEM_PROCESSING_REVERT_ERROR: {\n        buttonRevertItemProcessing: { opacity: 1 },\n        status: { opacity: 1 },\n        info: { opacity: 1 },\n    },\n    DID_ABORT_ITEM_PROCESSING: {\n        buttonRemoveItem: { opacity: 1 },\n        buttonProcessItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1 },\n    },\n    DID_REVERT_ITEM_PROCESSING: IdleStyle,\n};\n\n// complete indicator view\nconst processingCompleteIndicatorView = createView({\n    create: ({ root }) => {\n        root.element.innerHTML = root.query('GET_ICON_DONE');\n    },\n    name: 'processing-complete-indicator',\n    ignoreRect: true,\n    mixins: {\n        styles: ['scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            opacity: { type: 'tween', duration: 250 },\n        },\n    },\n});\n\n/**\n * Creates the file view\n */\nconst create$4 = ({ root, props }) => {\n    // copy Buttons object\n    const LocalButtons = Object.keys(Buttons).reduce((prev, curr) => {\n        prev[curr] = { ...Buttons[curr] };\n        return prev;\n    }, {});\n\n    const { id } = props;\n\n    // allow reverting upload\n    const allowRevert = root.query('GET_ALLOW_REVERT');\n\n    // allow remove file\n    const allowRemove = root.query('GET_ALLOW_REMOVE');\n\n    // allow processing upload\n    const allowProcess = root.query('GET_ALLOW_PROCESS');\n\n    // is instant uploading, need this to determine the icon of the undo button\n    const instantUpload = root.query('GET_INSTANT_UPLOAD');\n\n    // is async set up\n    const isAsync = root.query('IS_ASYNC');\n\n    // should align remove item buttons\n    const alignRemoveItemButton = root.query('GET_STYLE_BUTTON_REMOVE_ITEM_ALIGN');\n\n    // enabled buttons array\n    let buttonFilter;\n    if (isAsync) {\n        if (allowProcess && !allowRevert) {\n            // only remove revert button\n            buttonFilter = key => !/RevertItemProcessing/.test(key);\n        } else if (!allowProcess && allowRevert) {\n            // only remove process button\n            buttonFilter = key => !/ProcessItem|RetryItemProcessing|AbortItemProcessing/.test(key);\n        } else if (!allowProcess && !allowRevert) {\n            // remove all process buttons\n            buttonFilter = key => !/Process/.test(key);\n        }\n    } else {\n        // no process controls available\n        buttonFilter = key => !/Process/.test(key);\n    }\n\n    const enabledButtons = buttonFilter ? ButtonKeys.filter(buttonFilter) : ButtonKeys.concat();\n\n    // update icon and label for revert button when instant uploading\n    if (instantUpload && allowRevert) {\n        LocalButtons['RevertItemProcessing'].label = 'GET_LABEL_BUTTON_REMOVE_ITEM';\n        LocalButtons['RevertItemProcessing'].icon = 'GET_ICON_REMOVE';\n    }\n\n    // remove last button (revert) if not allowed\n    if (isAsync && !allowRevert) {\n        const map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n        map.info.translateX = calculateFileHorizontalCenterOffset;\n        map.info.translateY = calculateFileVerticalCenterOffset;\n        map.status.translateY = calculateFileVerticalCenterOffset;\n        map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n    }\n\n    // should align center\n    if (isAsync && !allowProcess) {\n        [\n            'DID_START_ITEM_PROCESSING',\n            'DID_REQUEST_ITEM_PROCESSING',\n            'DID_UPDATE_ITEM_PROCESS_PROGRESS',\n            'DID_THROW_ITEM_PROCESSING_ERROR',\n        ].forEach(key => {\n            StyleMap[key].status.translateY = calculateFileVerticalCenterOffset;\n        });\n        StyleMap['DID_THROW_ITEM_PROCESSING_ERROR'].status.translateX = calculateButtonWidth;\n    }\n\n    // move remove button to right\n    if (alignRemoveItemButton && allowRevert) {\n        LocalButtons['RevertItemProcessing'].align = 'BUTTON_REMOVE_ITEM_POSITION';\n        const map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n        map.info.translateX = calculateFileInfoOffset;\n        map.status.translateY = calculateFileVerticalCenterOffset;\n        map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n    }\n\n    // show/hide RemoveItem button\n    if (!allowRemove) {\n        LocalButtons['RemoveItem'].disabled = true;\n    }\n\n    // create the button views\n    forin(LocalButtons, (key, definition) => {\n        // create button\n        const buttonView = root.createChildView(fileActionButton, {\n            label: root.query(definition.label),\n            icon: root.query(definition.icon),\n            opacity: 0,\n        });\n\n        // should be appended?\n        if (enabledButtons.includes(key)) {\n            root.appendChildView(buttonView);\n        }\n\n        // toggle\n        if (definition.disabled) {\n            buttonView.element.setAttribute('disabled', 'disabled');\n            buttonView.element.setAttribute('hidden', 'hidden');\n        }\n\n        // add position attribute\n        buttonView.element.dataset.align = root.query(`GET_STYLE_${definition.align}`);\n\n        // add class\n        buttonView.element.classList.add(definition.className);\n\n        // handle interactions\n        buttonView.on('click', e => {\n            e.stopPropagation();\n            if (definition.disabled) return;\n            root.dispatch(definition.action, { query: id });\n        });\n\n        // set reference\n        root.ref[`button${key}`] = buttonView;\n    });\n\n    // checkmark\n    root.ref.processingCompleteIndicator = root.appendChildView(\n        root.createChildView(processingCompleteIndicatorView)\n    );\n    root.ref.processingCompleteIndicator.element.dataset.align = root.query(\n        `GET_STYLE_BUTTON_PROCESS_ITEM_POSITION`\n    );\n\n    // create file info view\n    root.ref.info = root.appendChildView(root.createChildView(fileInfo, { id }));\n\n    // create file status view\n    root.ref.status = root.appendChildView(root.createChildView(fileStatus, { id }));\n\n    // add progress indicators\n    const loadIndicatorView = root.appendChildView(\n        root.createChildView(progressIndicator, {\n            opacity: 0,\n            align: root.query(`GET_STYLE_LOAD_INDICATOR_POSITION`),\n        })\n    );\n    loadIndicatorView.element.classList.add('filepond--load-indicator');\n    root.ref.loadProgressIndicator = loadIndicatorView;\n\n    const progressIndicatorView = root.appendChildView(\n        root.createChildView(progressIndicator, {\n            opacity: 0,\n            align: root.query(`GET_STYLE_PROGRESS_INDICATOR_POSITION`),\n        })\n    );\n    progressIndicatorView.element.classList.add('filepond--process-indicator');\n    root.ref.processProgressIndicator = progressIndicatorView;\n\n    // current active styles\n    root.ref.activeStyles = [];\n};\n\nconst write$2 = ({ root, actions, props }) => {\n    // route actions\n    route({ root, actions, props });\n\n    // select last state change action\n    let action = actions\n        .concat()\n        .filter(action => /^DID_/.test(action.type))\n        .reverse()\n        .find(action => StyleMap[action.type]);\n\n    // a new action happened, let's get the matching styles\n    if (action) {\n        // define new active styles\n        root.ref.activeStyles = [];\n\n        const stylesToApply = StyleMap[action.type];\n        forin(DefaultStyle, (name, defaultStyles) => {\n            // get reference to control\n            const control = root.ref[name];\n\n            // loop over all styles for this control\n            forin(defaultStyles, (key, defaultValue) => {\n                const value =\n                    stylesToApply[name] && typeof stylesToApply[name][key] !== 'undefined'\n                        ? stylesToApply[name][key]\n                        : defaultValue;\n                root.ref.activeStyles.push({ control, key, value });\n            });\n        });\n    }\n\n    // apply active styles to element\n    root.ref.activeStyles.forEach(({ control, key, value }) => {\n        control[key] = typeof value === 'function' ? value(root) : value;\n    });\n};\n\nconst route = createRoute({\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_PROCESSING: ({ root, action }) => {\n        root.ref.buttonAbortItemProcessing.label = action.value;\n    },\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_LOAD: ({ root, action }) => {\n        root.ref.buttonAbortItemLoad.label = action.value;\n    },\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_REMOVAL: ({ root, action }) => {\n        root.ref.buttonAbortItemRemoval.label = action.value;\n    },\n    DID_REQUEST_ITEM_PROCESSING: ({ root }) => {\n        root.ref.processProgressIndicator.spin = true;\n        root.ref.processProgressIndicator.progress = 0;\n    },\n    DID_START_ITEM_LOAD: ({ root }) => {\n        root.ref.loadProgressIndicator.spin = true;\n        root.ref.loadProgressIndicator.progress = 0;\n    },\n    DID_START_ITEM_REMOVE: ({ root }) => {\n        root.ref.processProgressIndicator.spin = true;\n        root.ref.processProgressIndicator.progress = 0;\n    },\n    DID_UPDATE_ITEM_LOAD_PROGRESS: ({ root, action }) => {\n        root.ref.loadProgressIndicator.spin = false;\n        root.ref.loadProgressIndicator.progress = action.progress;\n    },\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: ({ root, action }) => {\n        root.ref.processProgressIndicator.spin = false;\n        root.ref.processProgressIndicator.progress = action.progress;\n    },\n});\n\nconst file = createView({\n    create: create$4,\n    write: write$2,\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    name: 'file',\n});\n\n/**\n * Creates the file view\n */\nconst create$5 = ({ root, props }) => {\n    // filename\n    root.ref.fileName = createElement$1('legend');\n    root.appendChild(root.ref.fileName);\n\n    // file appended\n    root.ref.file = root.appendChildView(root.createChildView(file, { id: props.id }));\n\n    // data has moved to data.js\n    root.ref.data = false;\n};\n\n/**\n * Data storage\n */\nconst didLoadItem = ({ root, props }) => {\n    // updates the legend of the fieldset so screenreaders can better group buttons\n    text(root.ref.fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n};\n\nconst fileWrapper = createView({\n    create: create$5,\n    ignoreRect: true,\n    write: createRoute({\n        DID_LOAD_ITEM: didLoadItem,\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    tag: 'fieldset',\n    name: 'file-wrapper',\n});\n\nconst PANEL_SPRING_PROPS = { type: 'spring', damping: 0.6, mass: 7 };\n\nconst create$6 = ({ root, props }) => {\n    [\n        {\n            name: 'top',\n        },\n        {\n            name: 'center',\n            props: {\n                translateY: null,\n                scaleY: null,\n            },\n            mixins: {\n                animations: {\n                    scaleY: PANEL_SPRING_PROPS,\n                },\n                styles: ['translateY', 'scaleY'],\n            },\n        },\n        {\n            name: 'bottom',\n            props: {\n                translateY: null,\n            },\n            mixins: {\n                animations: {\n                    translateY: PANEL_SPRING_PROPS,\n                },\n                styles: ['translateY'],\n            },\n        },\n    ].forEach(section => {\n        createSection(root, section, props.name);\n    });\n\n    root.element.classList.add(`filepond--${props.name}`);\n\n    root.ref.scalable = null;\n};\n\nconst createSection = (root, section, className) => {\n    const viewConstructor = createView({\n        name: `panel-${section.name} filepond--${className}`,\n        mixins: section.mixins,\n        ignoreRectUpdate: true,\n    });\n\n    const view = root.createChildView(viewConstructor, section.props);\n\n    root.ref[section.name] = root.appendChildView(view);\n};\n\nconst write$3 = ({ root, props }) => {\n    // update scalable state\n    if (root.ref.scalable === null || props.scalable !== root.ref.scalable) {\n        root.ref.scalable = isBoolean(props.scalable) ? props.scalable : true;\n        root.element.dataset.scalable = root.ref.scalable;\n    }\n\n    // no height, can't set\n    if (!props.height) return;\n\n    // get child rects\n    const topRect = root.ref.top.rect.element;\n    const bottomRect = root.ref.bottom.rect.element;\n\n    // make sure height never is smaller than bottom and top seciton heights combined (will probably never happen, but who knows)\n    const height = Math.max(topRect.height + bottomRect.height, props.height);\n\n    // offset center part\n    root.ref.center.translateY = topRect.height;\n\n    // scale center part\n    // use math ceil to prevent transparent lines because of rounding errors\n    root.ref.center.scaleY = (height - topRect.height - bottomRect.height) / 100;\n\n    // offset bottom part\n    root.ref.bottom.translateY = height - bottomRect.height;\n};\n\nconst panel = createView({\n    name: 'panel',\n    read: ({ root, props }) => (props.heightCurrent = root.ref.bottom.translateY),\n    write: write$3,\n    create: create$6,\n    ignoreRect: true,\n    mixins: {\n        apis: ['height', 'heightCurrent', 'scalable'],\n    },\n});\n\nconst createDragHelper = items => {\n    const itemIds = items.map(item => item.id);\n    let prevIndex = undefined;\n    return {\n        setIndex: index => {\n            prevIndex = index;\n        },\n        getIndex: () => prevIndex,\n        getItemIndex: item => itemIds.indexOf(item.id),\n    };\n};\n\nconst ITEM_TRANSLATE_SPRING = {\n    type: 'spring',\n    stiffness: 0.75,\n    damping: 0.45,\n    mass: 10,\n};\n\nconst ITEM_SCALE_SPRING = 'spring';\n\nconst StateMap = {\n    DID_START_ITEM_LOAD: 'busy',\n    DID_UPDATE_ITEM_LOAD_PROGRESS: 'loading',\n    DID_THROW_ITEM_INVALID: 'load-invalid',\n    DID_THROW_ITEM_LOAD_ERROR: 'load-error',\n    DID_LOAD_ITEM: 'idle',\n    DID_THROW_ITEM_REMOVE_ERROR: 'remove-error',\n    DID_START_ITEM_REMOVE: 'busy',\n    DID_START_ITEM_PROCESSING: 'busy processing',\n    DID_REQUEST_ITEM_PROCESSING: 'busy processing',\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: 'processing',\n    DID_COMPLETE_ITEM_PROCESSING: 'processing-complete',\n    DID_THROW_ITEM_PROCESSING_ERROR: 'processing-error',\n    DID_THROW_ITEM_PROCESSING_REVERT_ERROR: 'processing-revert-error',\n    DID_ABORT_ITEM_PROCESSING: 'cancelled',\n    DID_REVERT_ITEM_PROCESSING: 'idle',\n};\n\n/**\n * Creates the file view\n */\nconst create$7 = ({ root, props }) => {\n    // select\n    root.ref.handleClick = e => root.dispatch('DID_ACTIVATE_ITEM', { id: props.id });\n\n    // set id\n    root.element.id = `filepond--item-${props.id}`;\n    root.element.addEventListener('click', root.ref.handleClick);\n\n    // file view\n    root.ref.container = root.appendChildView(root.createChildView(fileWrapper, { id: props.id }));\n\n    // file panel\n    root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'item-panel' }));\n\n    // default start height\n    root.ref.panel.height = null;\n\n    // by default not marked for removal\n    props.markedForRemoval = false;\n\n    // if not allowed to reorder file items, exit here\n    if (!root.query('GET_ALLOW_REORDER')) return;\n\n    // set to idle so shows grab cursor\n    root.element.dataset.dragState = 'idle';\n\n    const grab = e => {\n        if (!e.isPrimary) return;\n\n        let removedActivateListener = false;\n\n        const origin = {\n            x: e.pageX,\n            y: e.pageY,\n        };\n\n        props.dragOrigin = {\n            x: root.translateX,\n            y: root.translateY,\n        };\n\n        props.dragCenter = {\n            x: e.offsetX,\n            y: e.offsetY,\n        };\n\n        const dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));\n\n        root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });\n\n        const drag = e => {\n            if (!e.isPrimary) return;\n\n            e.stopPropagation();\n            e.preventDefault();\n\n            props.dragOffset = {\n                x: e.pageX - origin.x,\n                y: e.pageY - origin.y,\n            };\n\n            // if dragged stop listening to clicks, will re-add when done dragging\n            const dist =\n                props.dragOffset.x * props.dragOffset.x + props.dragOffset.y * props.dragOffset.y;\n            if (dist > 16 && !removedActivateListener) {\n                removedActivateListener = true;\n                root.element.removeEventListener('click', root.ref.handleClick);\n            }\n\n            root.dispatch('DID_DRAG_ITEM', { id: props.id, dragState });\n        };\n\n        const drop = e => {\n            if (!e.isPrimary) return;\n\n            props.dragOffset = {\n                x: e.pageX - origin.x,\n                y: e.pageY - origin.y,\n            };\n\n            reset();\n        };\n\n        const cancel = () => {\n            reset();\n        };\n\n        const reset = () => {\n            document.removeEventListener('pointercancel', cancel);\n            document.removeEventListener('pointermove', drag);\n            document.removeEventListener('pointerup', drop);\n\n            root.dispatch('DID_DROP_ITEM', { id: props.id, dragState });\n\n            // start listening to clicks again\n            if (removedActivateListener) {\n                setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);\n            }\n        };\n\n        document.addEventListener('pointercancel', cancel);\n        document.addEventListener('pointermove', drag);\n        document.addEventListener('pointerup', drop);\n    };\n\n    root.element.addEventListener('pointerdown', grab);\n};\n\nconst route$1 = createRoute({\n    DID_UPDATE_PANEL_HEIGHT: ({ root, action }) => {\n        root.height = action.height;\n    },\n});\n\nconst write$4 = createRoute(\n    {\n        DID_GRAB_ITEM: ({ root, props }) => {\n            props.dragOrigin = {\n                x: root.translateX,\n                y: root.translateY,\n            };\n        },\n        DID_DRAG_ITEM: ({ root }) => {\n            root.element.dataset.dragState = 'drag';\n        },\n        DID_DROP_ITEM: ({ root, props }) => {\n            props.dragOffset = null;\n            props.dragOrigin = null;\n            root.element.dataset.dragState = 'drop';\n        },\n    },\n    ({ root, actions, props, shouldOptimize }) => {\n        if (root.element.dataset.dragState === 'drop') {\n            if (root.scaleX <= 1) {\n                root.element.dataset.dragState = 'idle';\n            }\n        }\n\n        // select last state change action\n        let action = actions\n            .concat()\n            .filter(action => /^DID_/.test(action.type))\n            .reverse()\n            .find(action => StateMap[action.type]);\n\n        // no need to set same state twice\n        if (action && action.type !== props.currentState) {\n            // set current state\n            props.currentState = action.type;\n\n            // set state\n            root.element.dataset.filepondItemState = StateMap[props.currentState] || '';\n        }\n\n        // route actions\n        const aspectRatio =\n            root.query('GET_ITEM_PANEL_ASPECT_RATIO') || root.query('GET_PANEL_ASPECT_RATIO');\n        if (!aspectRatio) {\n            route$1({ root, actions, props });\n            if (!root.height && root.ref.container.rect.element.height > 0) {\n                root.height = root.ref.container.rect.element.height;\n            }\n        } else if (!shouldOptimize) {\n            root.height = root.rect.element.width * aspectRatio;\n        }\n\n        // sync panel height with item height\n        if (shouldOptimize) {\n            root.ref.panel.height = null;\n        }\n\n        root.ref.panel.height = root.height;\n    }\n);\n\nconst item = createView({\n    create: create$7,\n    write: write$4,\n    destroy: ({ root, props }) => {\n        root.element.removeEventListener('click', root.ref.handleClick);\n        root.dispatch('RELEASE_ITEM', { query: props.id });\n    },\n    tag: 'li',\n    name: 'item',\n    mixins: {\n        apis: [\n            'id',\n            'interactionMethod',\n            'markedForRemoval',\n            'spawnDate',\n            'dragCenter',\n            'dragOrigin',\n            'dragOffset',\n        ],\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity', 'height'],\n        animations: {\n            scaleX: ITEM_SCALE_SPRING,\n            scaleY: ITEM_SCALE_SPRING,\n            translateX: ITEM_TRANSLATE_SPRING,\n            translateY: ITEM_TRANSLATE_SPRING,\n            opacity: { type: 'tween', duration: 150 },\n        },\n    },\n});\n\nvar getItemsPerRow = (horizontalSpace, itemWidth) => {\n    // add one pixel leeway, when using percentages for item width total items can be 1.99 per row\n\n    return Math.max(1, Math.floor((horizontalSpace + 1) / itemWidth));\n};\n\nconst getItemIndexByPosition = (view, children, positionInView) => {\n    if (!positionInView) return;\n\n    const horizontalSpace = view.rect.element.width;\n    // const children = view.childViews;\n    const l = children.length;\n    let last = null;\n\n    // -1, don't move items to accomodate (either add to top or bottom)\n    if (l === 0 || positionInView.top < children[0].rect.element.top) return -1;\n\n    // let's get the item width\n    const item = children[0];\n    const itemRect = item.rect.element;\n    const itemHorizontalMargin = itemRect.marginLeft + itemRect.marginRight;\n    const itemWidth = itemRect.width + itemHorizontalMargin;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        for (let index = 0; index < l; index++) {\n            const child = children[index];\n            const childMid = child.rect.outer.top + child.rect.element.height * 0.5;\n            if (positionInView.top < childMid) {\n                return index;\n            }\n        }\n        return l;\n    }\n\n    // grid\n    const itemVerticalMargin = itemRect.marginTop + itemRect.marginBottom;\n    const itemHeight = itemRect.height + itemVerticalMargin;\n    for (let index = 0; index < l; index++) {\n        const indexX = index % itemsPerRow;\n        const indexY = Math.floor(index / itemsPerRow);\n\n        const offsetX = indexX * itemWidth;\n        const offsetY = indexY * itemHeight;\n\n        const itemTop = offsetY - itemRect.marginTop;\n        const itemRight = offsetX + itemWidth;\n        const itemBottom = offsetY + itemHeight + itemRect.marginBottom;\n\n        if (positionInView.top < itemBottom && positionInView.top > itemTop) {\n            if (positionInView.left < itemRight) {\n                return index;\n            } else if (index !== l - 1) {\n                last = index;\n            } else {\n                last = null;\n            }\n        }\n    }\n\n    if (last !== null) {\n        return last;\n    }\n\n    return l;\n};\n\nconst dropAreaDimensions = {\n    height: 0,\n    width: 0,\n    get getHeight() {\n        return this.height;\n    },\n    set setHeight(val) {\n        if (this.height === 0 || val === 0) this.height = val;\n    },\n    get getWidth() {\n        return this.width;\n    },\n    set setWidth(val) {\n        if (this.width === 0 || val === 0) this.width = val;\n    },\n    setDimensions: function(height, width) {\n        if (this.height === 0 || height === 0) this.height = height;\n        if (this.width === 0 || width === 0) this.width = width;\n    },\n};\n\nconst create$8 = ({ root }) => {\n    // need to set role to list as otherwise it won't be read as a list by VoiceOver\n    attr(root.element, 'role', 'list');\n\n    root.ref.lastItemSpanwDate = Date.now();\n};\n\n/**\n * Inserts a new item\n * @param root\n * @param action\n */\nconst addItemView = ({ root, action }) => {\n    const { id, index, interactionMethod } = action;\n\n    root.ref.addIndex = index;\n\n    const now = Date.now();\n    let spawnDate = now;\n    let opacity = 1;\n\n    if (interactionMethod !== InteractionMethod.NONE) {\n        opacity = 0;\n        const cooldown = root.query('GET_ITEM_INSERT_INTERVAL');\n        const dist = now - root.ref.lastItemSpanwDate;\n        spawnDate = dist < cooldown ? now + (cooldown - dist) : now;\n    }\n\n    root.ref.lastItemSpanwDate = spawnDate;\n\n    root.appendChildView(\n        root.createChildView(\n            // view type\n            item,\n\n            // props\n            {\n                spawnDate,\n                id,\n                opacity,\n                interactionMethod,\n            }\n        ),\n        index\n    );\n};\n\nconst moveItem = (item, x, y, vx = 0, vy = 1) => {\n    // set to null to remove animation while dragging\n    if (item.dragOffset) {\n        item.translateX = null;\n        item.translateY = null;\n        item.translateX = item.dragOrigin.x + item.dragOffset.x;\n        item.translateY = item.dragOrigin.y + item.dragOffset.y;\n        item.scaleX = 1.025;\n        item.scaleY = 1.025;\n    } else {\n        item.translateX = x;\n        item.translateY = y;\n\n        if (Date.now() > item.spawnDate) {\n            // reveal element\n            if (item.opacity === 0) {\n                introItemView(item, x, y, vx, vy);\n            }\n\n            // make sure is default scale every frame\n            item.scaleX = 1;\n            item.scaleY = 1;\n            item.opacity = 1;\n        }\n    }\n};\n\nconst introItemView = (item, x, y, vx, vy) => {\n    if (item.interactionMethod === InteractionMethod.NONE) {\n        item.translateX = null;\n        item.translateX = x;\n        item.translateY = null;\n        item.translateY = y;\n    } else if (item.interactionMethod === InteractionMethod.DROP) {\n        item.translateX = null;\n        item.translateX = x - vx * 20;\n\n        item.translateY = null;\n        item.translateY = y - vy * 10;\n\n        item.scaleX = 0.8;\n        item.scaleY = 0.8;\n    } else if (item.interactionMethod === InteractionMethod.BROWSE) {\n        item.translateY = null;\n        item.translateY = y - 30;\n    } else if (item.interactionMethod === InteractionMethod.API) {\n        item.translateX = null;\n        item.translateX = x - 30;\n        item.translateY = null;\n    }\n};\n\n/**\n * Removes an existing item\n * @param root\n * @param action\n */\nconst removeItemView = ({ root, action }) => {\n    const { id } = action;\n\n    // get the view matching the given id\n    const view = root.childViews.find(child => child.id === id);\n\n    // if no view found, exit\n    if (!view) {\n        return;\n    }\n\n    // animate view out of view\n    view.scaleX = 0.9;\n    view.scaleY = 0.9;\n    view.opacity = 0;\n\n    // mark for removal\n    view.markedForRemoval = true;\n};\n\nconst getItemHeight = child =>\n    child.rect.element.height + child.rect.element.marginBottom + child.rect.element.marginTop;\nconst getItemWidth = child =>\n    child.rect.element.width +\n    child.rect.element.marginLeft * 0.5 +\n    child.rect.element.marginRight * 0.5;\n\nconst dragItem = ({ root, action }) => {\n    const { id, dragState } = action;\n\n    // reference to item\n    const item = root.query('GET_ITEM', { id });\n\n    // get the view matching the given id\n    const view = root.childViews.find(child => child.id === id);\n\n    const numItems = root.childViews.length;\n    const oldIndex = dragState.getItemIndex(item);\n\n    // if no view found, exit\n    if (!view) return;\n\n    const dragPosition = {\n        x: view.dragOrigin.x + view.dragOffset.x + view.dragCenter.x,\n        y: view.dragOrigin.y + view.dragOffset.y + view.dragCenter.y,\n    };\n\n    // get drag area dimensions\n    const dragHeight = getItemHeight(view);\n    const dragWidth = getItemWidth(view);\n\n    // get rows and columns (There will always be at least one row and one column if a file is present)\n    let cols = Math.floor(root.rect.outer.width / dragWidth);\n    if (cols > numItems) cols = numItems;\n\n    // rows are used to find when we have left the preview area bounding box\n    const rows = Math.floor(numItems / cols + 1);\n\n    dropAreaDimensions.setHeight = dragHeight * rows;\n    dropAreaDimensions.setWidth = dragWidth * cols;\n\n    // get new index of dragged item\n    var location = {\n        y: Math.floor(dragPosition.y / dragHeight),\n        x: Math.floor(dragPosition.x / dragWidth),\n        getGridIndex: function getGridIndex() {\n            if (\n                dragPosition.y > dropAreaDimensions.getHeight ||\n                dragPosition.y < 0 ||\n                dragPosition.x > dropAreaDimensions.getWidth ||\n                dragPosition.x < 0\n            )\n                return oldIndex;\n            return this.y * cols + this.x;\n        },\n        getColIndex: function getColIndex() {\n            const items = root.query('GET_ACTIVE_ITEMS');\n            const visibleChildren = root.childViews.filter(child => child.rect.element.height);\n            const children = items.map(item =>\n                visibleChildren.find(childView => childView.id === item.id)\n            );\n            const currentIndex = children.findIndex(child => child === view);\n            const dragHeight = getItemHeight(view);\n            const l = children.length;\n            let idx = l;\n            let childHeight = 0;\n            let childBottom = 0;\n            let childTop = 0;\n            for (let i = 0; i < l; i++) {\n                childHeight = getItemHeight(children[i]);\n                childTop = childBottom;\n                childBottom = childTop + childHeight;\n                if (dragPosition.y < childBottom) {\n                    if (currentIndex > i) {\n                        if (dragPosition.y < childTop + dragHeight) {\n                            idx = i;\n                            break;\n                        }\n                        continue;\n                    }\n                    idx = i;\n                    break;\n                }\n            }\n            return idx;\n        },\n    };\n\n    // get new index\n    const index = cols > 1 ? location.getGridIndex() : location.getColIndex();\n    root.dispatch('MOVE_ITEM', { query: view, index });\n\n    // if the index of the item changed, dispatch reorder action\n    const currentIndex = dragState.getIndex();\n\n    if (currentIndex === undefined || currentIndex !== index) {\n        dragState.setIndex(index);\n\n        if (currentIndex === undefined) return;\n\n        root.dispatch('DID_REORDER_ITEMS', {\n            items: root.query('GET_ACTIVE_ITEMS'),\n            origin: oldIndex,\n            target: index,\n        });\n    }\n};\n\n/**\n * Setup action routes\n */\nconst route$2 = createRoute({\n    DID_ADD_ITEM: addItemView,\n    DID_REMOVE_ITEM: removeItemView,\n    DID_DRAG_ITEM: dragItem,\n});\n\n/**\n * Write to view\n * @param root\n * @param actions\n * @param props\n */\nconst write$5 = ({ root, props, actions, shouldOptimize }) => {\n    // route actions\n    route$2({ root, props, actions });\n\n    const { dragCoordinates } = props;\n\n    // available space on horizontal axis\n    const horizontalSpace = root.rect.element.width;\n\n    // only draw children that have dimensions\n    const visibleChildren = root.childViews.filter(child => child.rect.element.height);\n\n    // sort based on current active items\n    const children = root\n        .query('GET_ACTIVE_ITEMS')\n        .map(item => visibleChildren.find(child => child.id === item.id))\n        .filter(item => item);\n\n    // get index\n    const dragIndex = dragCoordinates\n        ? getItemIndexByPosition(root, children, dragCoordinates)\n        : null;\n\n    // add index is used to reserve the dropped/added item index till the actual item is rendered\n    const addIndex = root.ref.addIndex || null;\n\n    // add index no longer needed till possibly next draw\n    root.ref.addIndex = null;\n\n    let dragIndexOffset = 0;\n    let removeIndexOffset = 0;\n    let addIndexOffset = 0;\n\n    if (children.length === 0) return;\n\n    const childRect = children[0].rect.element;\n    const itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n    const itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n    const itemWidth = childRect.width + itemHorizontalMargin;\n    const itemHeight = childRect.height + itemVerticalMargin;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        let offsetY = 0;\n        let dragOffset = 0;\n\n        children.forEach((child, index) => {\n            if (dragIndex) {\n                let dist = index - dragIndex;\n                if (dist === -2) {\n                    dragOffset = -itemVerticalMargin * 0.25;\n                } else if (dist === -1) {\n                    dragOffset = -itemVerticalMargin * 0.75;\n                } else if (dist === 0) {\n                    dragOffset = itemVerticalMargin * 0.75;\n                } else if (dist === 1) {\n                    dragOffset = itemVerticalMargin * 0.25;\n                } else {\n                    dragOffset = 0;\n                }\n            }\n\n            if (shouldOptimize) {\n                child.translateX = null;\n                child.translateY = null;\n            }\n\n            if (!child.markedForRemoval) {\n                moveItem(child, 0, offsetY + dragOffset);\n            }\n\n            let itemHeight = child.rect.element.height + itemVerticalMargin;\n\n            let visualHeight = itemHeight * (child.markedForRemoval ? child.opacity : 1);\n\n            offsetY += visualHeight;\n        });\n    }\n    // grid\n    else {\n        let prevX = 0;\n        let prevY = 0;\n\n        children.forEach((child, index) => {\n            if (index === dragIndex) {\n                dragIndexOffset = 1;\n            }\n\n            if (index === addIndex) {\n                addIndexOffset += 1;\n            }\n\n            if (child.markedForRemoval && child.opacity < 0.5) {\n                removeIndexOffset -= 1;\n            }\n\n            const visualIndex = index + addIndexOffset + dragIndexOffset + removeIndexOffset;\n\n            const indexX = visualIndex % itemsPerRow;\n            const indexY = Math.floor(visualIndex / itemsPerRow);\n\n            const offsetX = indexX * itemWidth;\n            const offsetY = indexY * itemHeight;\n\n            const vectorX = Math.sign(offsetX - prevX);\n            const vectorY = Math.sign(offsetY - prevY);\n\n            prevX = offsetX;\n            prevY = offsetY;\n\n            if (child.markedForRemoval) return;\n\n            if (shouldOptimize) {\n                child.translateX = null;\n                child.translateY = null;\n            }\n\n            moveItem(child, offsetX, offsetY, vectorX, vectorY);\n        });\n    }\n};\n\n/**\n * Filters actions that are meant specifically for a certain child of the list\n * @param child\n * @param actions\n */\nconst filterSetItemActions = (child, actions) =>\n    actions.filter(action => {\n        // if action has an id, filter out actions that don't have this child id\n        if (action.data && action.data.id) {\n            return child.id === action.data.id;\n        }\n\n        // allow all other actions\n        return true;\n    });\n\nconst list = createView({\n    create: create$8,\n    write: write$5,\n    tag: 'ul',\n    name: 'list',\n    didWriteView: ({ root }) => {\n        root.childViews\n            .filter(view => view.markedForRemoval && view.opacity === 0 && view.resting)\n            .forEach(view => {\n                view._destroy();\n                root.removeChildView(view);\n            });\n    },\n    filterFrameActionsForChild: filterSetItemActions,\n    mixins: {\n        apis: ['dragCoordinates'],\n    },\n});\n\nconst create$9 = ({ root, props }) => {\n    root.ref.list = root.appendChildView(root.createChildView(list));\n    props.dragCoordinates = null;\n    props.overflowing = false;\n};\n\nconst storeDragCoordinates = ({ root, props, action }) => {\n    if (!root.query('GET_ITEM_INSERT_LOCATION_FREEDOM')) return;\n    props.dragCoordinates = {\n        left: action.position.scopeLeft - root.ref.list.rect.element.left,\n        top:\n            action.position.scopeTop -\n            (root.rect.outer.top + root.rect.element.marginTop + root.rect.element.scrollTop),\n    };\n};\n\nconst clearDragCoordinates = ({ props }) => {\n    props.dragCoordinates = null;\n};\n\nconst route$3 = createRoute({\n    DID_DRAG: storeDragCoordinates,\n    DID_END_DRAG: clearDragCoordinates,\n});\n\nconst write$6 = ({ root, props, actions }) => {\n    // route actions\n    route$3({ root, props, actions });\n\n    // current drag position\n    root.ref.list.dragCoordinates = props.dragCoordinates;\n\n    // if currently overflowing but no longer received overflow\n    if (props.overflowing && !props.overflow) {\n        props.overflowing = false;\n\n        // reset overflow state\n        root.element.dataset.state = '';\n        root.height = null;\n    }\n\n    // if is not overflowing currently but does receive overflow value\n    if (props.overflow) {\n        const newHeight = Math.round(props.overflow);\n        if (newHeight !== root.height) {\n            props.overflowing = true;\n            root.element.dataset.state = 'overflow';\n            root.height = newHeight;\n        }\n    }\n};\n\nconst listScroller = createView({\n    create: create$9,\n    write: write$6,\n    name: 'list-scroller',\n    mixins: {\n        apis: ['overflow', 'dragCoordinates'],\n        styles: ['height', 'translateY'],\n        animations: {\n            translateY: 'spring',\n        },\n    },\n});\n\nconst attrToggle = (element, name, state, enabledValue = '') => {\n    if (state) {\n        attr(element, name, enabledValue);\n    } else {\n        element.removeAttribute(name);\n    }\n};\n\nconst resetFileInput = input => {\n    // no value, no need to reset\n    if (!input || input.value === '') {\n        return;\n    }\n\n    try {\n        // for modern browsers\n        input.value = '';\n    } catch (err) {}\n\n    // for IE10\n    if (input.value) {\n        // quickly append input to temp form and reset form\n        const form = createElement$1('form');\n        const parentNode = input.parentNode;\n        const ref = input.nextSibling;\n        form.appendChild(input);\n        form.reset();\n\n        // re-inject input where it originally was\n        if (ref) {\n            parentNode.insertBefore(input, ref);\n        } else {\n            parentNode.appendChild(input);\n        }\n    }\n};\n\nconst create$a = ({ root, props }) => {\n    // set id so can be referenced from outside labels\n    root.element.id = `filepond--browser-${props.id}`;\n\n    // set name of element (is removed when a value is set)\n    attr(root.element, 'name', root.query('GET_NAME'));\n\n    // we have to link this element to the status element\n    attr(root.element, 'aria-controls', `filepond--assistant-${props.id}`);\n\n    // set label, we use labelled by as otherwise the screenreader does not read the \"browse\" text in the label (as it has tabindex: 0)\n    attr(root.element, 'aria-labelledby', `filepond--drop-label-${props.id}`);\n\n    // set configurable props\n    setAcceptedFileTypes({ root, action: { value: root.query('GET_ACCEPTED_FILE_TYPES') } });\n    toggleAllowMultiple({ root, action: { value: root.query('GET_ALLOW_MULTIPLE') } });\n    toggleDirectoryFilter({ root, action: { value: root.query('GET_ALLOW_DIRECTORIES_ONLY') } });\n    toggleDisabled({ root });\n    toggleRequired({ root, action: { value: root.query('GET_REQUIRED') } });\n    setCaptureMethod({ root, action: { value: root.query('GET_CAPTURE_METHOD') } });\n\n    // handle changes to the input field\n    root.ref.handleChange = e => {\n        if (!root.element.value) {\n            return;\n        }\n\n        // extract files and move value of webkitRelativePath path to _relativePath\n        const files = Array.from(root.element.files).map(file => {\n            file._relativePath = file.webkitRelativePath;\n            return file;\n        });\n\n        // we add a little delay so the OS file select window can move out of the way before we add our file\n        setTimeout(() => {\n            // load files\n            props.onload(files);\n\n            // reset input, it's just for exposing a method to drop files, should not retain any state\n            resetFileInput(root.element);\n        }, 250);\n    };\n\n    root.element.addEventListener('change', root.ref.handleChange);\n};\n\nconst setAcceptedFileTypes = ({ root, action }) => {\n    if (!root.query('GET_ALLOW_SYNC_ACCEPT_ATTRIBUTE')) return;\n    attrToggle(root.element, 'accept', !!action.value, action.value ? action.value.join(',') : '');\n};\n\nconst toggleAllowMultiple = ({ root, action }) => {\n    attrToggle(root.element, 'multiple', action.value);\n};\n\nconst toggleDirectoryFilter = ({ root, action }) => {\n    attrToggle(root.element, 'webkitdirectory', action.value);\n};\n\nconst toggleDisabled = ({ root }) => {\n    const isDisabled = root.query('GET_DISABLED');\n    const doesAllowBrowse = root.query('GET_ALLOW_BROWSE');\n    const disableField = isDisabled || !doesAllowBrowse;\n    attrToggle(root.element, 'disabled', disableField);\n};\n\nconst toggleRequired = ({ root, action }) => {\n    // want to remove required, always possible\n    if (!action.value) {\n        attrToggle(root.element, 'required', false);\n    }\n    // if want to make required, only possible when zero items\n    else if (root.query('GET_TOTAL_ITEMS') === 0) {\n        attrToggle(root.element, 'required', true);\n    }\n};\n\nconst setCaptureMethod = ({ root, action }) => {\n    attrToggle(root.element, 'capture', !!action.value, action.value === true ? '' : action.value);\n};\n\nconst updateRequiredStatus = ({ root }) => {\n    const { element } = root;\n    // always remove the required attribute when more than zero items\n    if (root.query('GET_TOTAL_ITEMS') > 0) {\n        attrToggle(element, 'required', false);\n        attrToggle(element, 'name', false);\n\n        // still has items\n        const activeItems = root.query('GET_ACTIVE_ITEMS');\n        let hasInvalidField = false;\n        for (let i = 0; i < activeItems.length; i++) {\n            if (activeItems[i].status === ItemStatus.LOAD_ERROR) {\n                hasInvalidField = true;\n            }\n        }\n        // set validity status\n        root.element.setCustomValidity(\n            hasInvalidField ? root.query('GET_LABEL_INVALID_FIELD') : ''\n        );\n    } else {\n        // add name attribute\n        attrToggle(element, 'name', true, root.query('GET_NAME'));\n\n        // remove any validation messages\n        const shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n        if (shouldCheckValidity) {\n            element.setCustomValidity('');\n        }\n\n        // we only add required if the field has been deemed required\n        if (root.query('GET_REQUIRED')) {\n            attrToggle(element, 'required', true);\n        }\n    }\n};\n\nconst updateFieldValidityStatus = ({ root }) => {\n    const shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n    if (!shouldCheckValidity) return;\n    root.element.setCustomValidity(root.query('GET_LABEL_INVALID_FIELD'));\n};\n\nconst browser = createView({\n    tag: 'input',\n    name: 'browser',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    attributes: {\n        type: 'file',\n    },\n    create: create$a,\n    destroy: ({ root }) => {\n        root.element.removeEventListener('change', root.ref.handleChange);\n    },\n    write: createRoute({\n        DID_LOAD_ITEM: updateRequiredStatus,\n        DID_REMOVE_ITEM: updateRequiredStatus,\n        DID_THROW_ITEM_INVALID: updateFieldValidityStatus,\n\n        DID_SET_DISABLED: toggleDisabled,\n        DID_SET_ALLOW_BROWSE: toggleDisabled,\n        DID_SET_ALLOW_DIRECTORIES_ONLY: toggleDirectoryFilter,\n        DID_SET_ALLOW_MULTIPLE: toggleAllowMultiple,\n        DID_SET_ACCEPTED_FILE_TYPES: setAcceptedFileTypes,\n        DID_SET_CAPTURE_METHOD: setCaptureMethod,\n        DID_SET_REQUIRED: toggleRequired,\n    }),\n});\n\nconst Key = {\n    ENTER: 13,\n    SPACE: 32,\n};\n\nconst create$b = ({ root, props }) => {\n    // create the label and link it to the file browser\n    const label = createElement$1('label');\n    attr(label, 'for', `filepond--browser-${props.id}`);\n\n    // use for labeling file input (aria-labelledby on file input)\n    attr(label, 'id', `filepond--drop-label-${props.id}`);\n\n    // handle keys\n    root.ref.handleKeyDown = e => {\n        const isActivationKey = e.keyCode === Key.ENTER || e.keyCode === Key.SPACE;\n        if (!isActivationKey) return;\n        // stops from triggering the element a second time\n        e.preventDefault();\n\n        // click link (will then in turn activate file input)\n        root.ref.label.click();\n    };\n\n    root.ref.handleClick = e => {\n        const isLabelClick = e.target === label || label.contains(e.target);\n\n        // don't want to click twice\n        if (isLabelClick) return;\n\n        // click link (will then in turn activate file input)\n        root.ref.label.click();\n    };\n\n    // attach events\n    label.addEventListener('keydown', root.ref.handleKeyDown);\n    root.element.addEventListener('click', root.ref.handleClick);\n\n    // update\n    updateLabelValue(label, props.caption);\n\n    // add!\n    root.appendChild(label);\n    root.ref.label = label;\n};\n\nconst updateLabelValue = (label, value) => {\n    label.innerHTML = value;\n    const clickable = label.querySelector('.filepond--label-action');\n    if (clickable) {\n        attr(clickable, 'tabindex', '0');\n    }\n    return value;\n};\n\nconst dropLabel = createView({\n    name: 'drop-label',\n    ignoreRect: true,\n    create: create$b,\n    destroy: ({ root }) => {\n        root.ref.label.addEventListener('keydown', root.ref.handleKeyDown);\n        root.element.removeEventListener('click', root.ref.handleClick);\n    },\n    write: createRoute({\n        DID_SET_LABEL_IDLE: ({ root, action }) => {\n            updateLabelValue(root.ref.label, action.value);\n        },\n    }),\n    mixins: {\n        styles: ['opacity', 'translateX', 'translateY'],\n        animations: {\n            opacity: { type: 'tween', duration: 150 },\n            translateX: 'spring',\n            translateY: 'spring',\n        },\n    },\n});\n\nconst blob = createView({\n    name: 'drip-blob',\n    ignoreRect: true,\n    mixins: {\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            translateX: 'spring',\n            translateY: 'spring',\n            opacity: { type: 'tween', duration: 250 },\n        },\n    },\n});\n\nconst addBlob = ({ root }) => {\n    const centerX = root.rect.element.width * 0.5;\n    const centerY = root.rect.element.height * 0.5;\n\n    root.ref.blob = root.appendChildView(\n        root.createChildView(blob, {\n            opacity: 0,\n            scaleX: 2.5,\n            scaleY: 2.5,\n            translateX: centerX,\n            translateY: centerY,\n        })\n    );\n};\n\nconst moveBlob = ({ root, action }) => {\n    if (!root.ref.blob) {\n        addBlob({ root });\n        return;\n    }\n\n    root.ref.blob.translateX = action.position.scopeLeft;\n    root.ref.blob.translateY = action.position.scopeTop;\n    root.ref.blob.scaleX = 1;\n    root.ref.blob.scaleY = 1;\n    root.ref.blob.opacity = 1;\n};\n\nconst hideBlob = ({ root }) => {\n    if (!root.ref.blob) {\n        return;\n    }\n    root.ref.blob.opacity = 0;\n};\n\nconst explodeBlob = ({ root }) => {\n    if (!root.ref.blob) {\n        return;\n    }\n    root.ref.blob.scaleX = 2.5;\n    root.ref.blob.scaleY = 2.5;\n    root.ref.blob.opacity = 0;\n};\n\nconst write$7 = ({ root, props, actions }) => {\n    route$4({ root, props, actions });\n\n    const { blob } = root.ref;\n\n    if (actions.length === 0 && blob && blob.opacity === 0) {\n        root.removeChildView(blob);\n        root.ref.blob = null;\n    }\n};\n\nconst route$4 = createRoute({\n    DID_DRAG: moveBlob,\n    DID_DROP: explodeBlob,\n    DID_END_DRAG: hideBlob,\n});\n\nconst drip = createView({\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    name: 'drip',\n    write: write$7,\n});\n\nconst setInputFiles = (element, files) => {\n    try {\n        // Create a DataTransfer instance and add a newly created file\n        const dataTransfer = new DataTransfer();\n        files.forEach(file => {\n            if (file instanceof File) {\n                dataTransfer.items.add(file);\n            } else {\n                dataTransfer.items.add(\n                    new File([file], file.name, {\n                        type: file.type,\n                    })\n                );\n            }\n        });\n\n        // Assign the DataTransfer files list to the file input\n        element.files = dataTransfer.files;\n    } catch (err) {\n        return false;\n    }\n    return true;\n};\n\nconst create$c = ({ root }) => {\n    root.ref.fields = {};\n    const legend = document.createElement('legend');\n    legend.textContent = 'Files';\n    root.element.appendChild(legend);\n};\n\nconst getField = (root, id) => root.ref.fields[id];\n\nconst syncFieldPositionsWithItems = root => {\n    root.query('GET_ACTIVE_ITEMS').forEach(item => {\n        if (!root.ref.fields[item.id]) return;\n        root.element.appendChild(root.ref.fields[item.id]);\n    });\n};\n\nconst didReorderItems = ({ root }) => syncFieldPositionsWithItems(root);\n\nconst didAddItem = ({ root, action }) => {\n    const fileItem = root.query('GET_ITEM', action.id);\n    const isLocalFile = fileItem.origin === FileOrigin.LOCAL;\n    const shouldUseFileInput = !isLocalFile && root.query('SHOULD_UPDATE_FILE_INPUT');\n    const dataContainer = createElement$1('input');\n    dataContainer.type = shouldUseFileInput ? 'file' : 'hidden';\n    dataContainer.name = root.query('GET_NAME');\n    root.ref.fields[action.id] = dataContainer;\n    syncFieldPositionsWithItems(root);\n};\n\nconst didLoadItem$1 = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n\n    // store server ref in hidden input\n    if (action.serverFileReference !== null) field.value = action.serverFileReference;\n\n    // store file item in file input\n    if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n\n    const fileItem = root.query('GET_ITEM', action.id);\n    setInputFiles(field, [fileItem.file]);\n};\n\nconst didPrepareOutput = ({ root, action }) => {\n    // this timeout pushes the handler after 'load'\n    if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n    setTimeout(() => {\n        const field = getField(root, action.id);\n        if (!field) return;\n        setInputFiles(field, [action.file]);\n    }, 0);\n};\n\nconst didSetDisabled = ({ root }) => {\n    root.element.disabled = root.query('GET_DISABLED');\n};\n\nconst didRemoveItem = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n    if (field.parentNode) field.parentNode.removeChild(field);\n    delete root.ref.fields[action.id];\n};\n\n// only runs for server files. will refuse to update the value if the field\n// is a file field\nconst didDefineValue = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n    if (action.value === null) {\n        // clear field value\n        field.removeAttribute('value');\n    } else {\n        // set field value\n        if (field.type != 'file') {\n            field.value = action.value;\n        }\n    }\n    syncFieldPositionsWithItems(root);\n};\n\nconst write$8 = createRoute({\n    DID_SET_DISABLED: didSetDisabled,\n    DID_ADD_ITEM: didAddItem,\n    DID_LOAD_ITEM: didLoadItem$1,\n    DID_REMOVE_ITEM: didRemoveItem,\n    DID_DEFINE_VALUE: didDefineValue,\n    DID_PREPARE_OUTPUT: didPrepareOutput,\n    DID_REORDER_ITEMS: didReorderItems,\n    DID_SORT_ITEMS: didReorderItems,\n});\n\nconst data = createView({\n    tag: 'fieldset',\n    name: 'data',\n    create: create$c,\n    write: write$8,\n    ignoreRect: true,\n});\n\nconst getRootNode = element => ('getRootNode' in element ? element.getRootNode() : document);\n\nconst images = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff'];\nconst text$1 = ['css', 'csv', 'html', 'txt'];\nconst map = {\n    zip: 'zip|compressed',\n    epub: 'application/epub+zip',\n};\n\nconst guesstimateMimeType = (extension = '') => {\n    extension = extension.toLowerCase();\n    if (images.includes(extension)) {\n        return (\n            'image/' + (extension === 'jpg' ? 'jpeg' : extension === 'svg' ? 'svg+xml' : extension)\n        );\n    }\n    if (text$1.includes(extension)) {\n        return 'text/' + extension;\n    }\n\n    return map[extension] || '';\n};\n\nconst requestDataTransferItems = dataTransfer =>\n    new Promise((resolve, reject) => {\n        // try to get links from transfer, if found we'll exit immediately (unless a file is in the dataTransfer as well, this is because Firefox could represent the file as a URL and a file object at the same time)\n        const links = getLinks(dataTransfer);\n        if (links.length && !hasFiles(dataTransfer)) {\n            return resolve(links);\n        }\n        // try to get files from the transfer\n        getFiles(dataTransfer).then(resolve);\n    });\n\n/**\n * Test if datatransfer has files\n */\nconst hasFiles = dataTransfer => {\n    if (dataTransfer.files) return dataTransfer.files.length > 0;\n    return false;\n};\n\n/**\n * Extracts files from a DataTransfer object\n */\nconst getFiles = dataTransfer =>\n    new Promise((resolve, reject) => {\n        // get the transfer items as promises\n        const promisedFiles = (dataTransfer.items ? Array.from(dataTransfer.items) : [])\n\n            // only keep file system items (files and directories)\n            .filter(item => isFileSystemItem(item))\n\n            // map each item to promise\n            .map(item => getFilesFromItem(item));\n\n        // if is empty, see if we can extract some info from the files property as a fallback\n        if (!promisedFiles.length) {\n            // TODO: test for directories (should not be allowed)\n            // Use FileReader, problem is that the files property gets lost in the process\n            resolve(dataTransfer.files ? Array.from(dataTransfer.files) : []);\n            return;\n        }\n\n        // done!\n        Promise.all(promisedFiles)\n            .then(returnedFileGroups => {\n                // flatten groups\n                const files = [];\n                returnedFileGroups.forEach(group => {\n                    files.push.apply(files, group);\n                });\n\n                // done (filter out empty files)!\n                resolve(\n                    files\n                        .filter(file => file)\n                        .map(file => {\n                            if (!file._relativePath) file._relativePath = file.webkitRelativePath;\n                            return file;\n                        })\n                );\n            })\n            .catch(console.error);\n    });\n\nconst isFileSystemItem = item => {\n    if (isEntry(item)) {\n        const entry = getAsEntry(item);\n        if (entry) {\n            return entry.isFile || entry.isDirectory;\n        }\n    }\n    return item.kind === 'file';\n};\n\nconst getFilesFromItem = item =>\n    new Promise((resolve, reject) => {\n        if (isDirectoryEntry(item)) {\n            getFilesInDirectory(getAsEntry(item))\n                .then(resolve)\n                .catch(reject);\n            return;\n        }\n\n        resolve([item.getAsFile()]);\n    });\n\nconst getFilesInDirectory = entry =>\n    new Promise((resolve, reject) => {\n        const files = [];\n\n        // the total entries to read\n        let dirCounter = 0;\n        let fileCounter = 0;\n\n        const resolveIfDone = () => {\n            if (fileCounter === 0 && dirCounter === 0) {\n                resolve(files);\n            }\n        };\n\n        // the recursive function\n        const readEntries = dirEntry => {\n            dirCounter++;\n\n            const directoryReader = dirEntry.createReader();\n\n            // directories are returned in batches, we need to process all batches before we're done\n            const readBatch = () => {\n                directoryReader.readEntries(entries => {\n                    if (entries.length === 0) {\n                        dirCounter--;\n                        resolveIfDone();\n                        return;\n                    }\n\n                    entries.forEach(entry => {\n                        // recursively read more directories\n                        if (entry.isDirectory) {\n                            readEntries(entry);\n                        } else {\n                            // read as file\n                            fileCounter++;\n\n                            entry.file(file => {\n                                const correctedFile = correctMissingFileType(file);\n                                if (entry.fullPath) correctedFile._relativePath = entry.fullPath;\n                                files.push(correctedFile);\n                                fileCounter--;\n                                resolveIfDone();\n                            });\n                        }\n                    });\n\n                    // try to get next batch of files\n                    readBatch();\n                }, reject);\n            };\n\n            // read first batch of files\n            readBatch();\n        };\n\n        // go!\n        readEntries(entry);\n    });\n\nconst correctMissingFileType = file => {\n    if (file.type.length) return file;\n    const date = file.lastModifiedDate;\n    const name = file.name;\n    const type = guesstimateMimeType(getExtensionFromFilename(file.name));\n    if (!type.length) return file;\n    file = file.slice(0, file.size, type);\n    file.name = name;\n    file.lastModifiedDate = date;\n    return file;\n};\n\nconst isDirectoryEntry = item => isEntry(item) && (getAsEntry(item) || {}).isDirectory;\n\nconst isEntry = item => 'webkitGetAsEntry' in item;\n\nconst getAsEntry = item => item.webkitGetAsEntry();\n\n/**\n * Extracts links from a DataTransfer object\n */\nconst getLinks = dataTransfer => {\n    let links = [];\n    try {\n        // look in meta data property\n        links = getLinksFromTransferMetaData(dataTransfer);\n        if (links.length) {\n            return links;\n        }\n        links = getLinksFromTransferURLData(dataTransfer);\n    } catch (e) {\n        // nope nope nope (probably IE trouble)\n    }\n    return links;\n};\n\nconst getLinksFromTransferURLData = dataTransfer => {\n    let data = dataTransfer.getData('url');\n    if (typeof data === 'string' && data.length) {\n        return [data];\n    }\n    return [];\n};\n\nconst getLinksFromTransferMetaData = dataTransfer => {\n    let data = dataTransfer.getData('text/html');\n    if (typeof data === 'string' && data.length) {\n        const matches = data.match(/src\\s*=\\s*\"(.+?)\"/);\n        if (matches) {\n            return [matches[1]];\n        }\n    }\n    return [];\n};\n\nconst dragNDropObservers = [];\n\nconst eventPosition = e => ({\n    pageLeft: e.pageX,\n    pageTop: e.pageY,\n    scopeLeft: e.offsetX || e.layerX,\n    scopeTop: e.offsetY || e.layerY,\n});\n\nconst createDragNDropClient = (element, scopeToObserve, filterElement) => {\n    const observer = getDragNDropObserver(scopeToObserve);\n\n    const client = {\n        element,\n        filterElement,\n        state: null,\n        ondrop: () => {},\n        onenter: () => {},\n        ondrag: () => {},\n        onexit: () => {},\n        onload: () => {},\n        allowdrop: () => {},\n    };\n\n    client.destroy = observer.addListener(client);\n\n    return client;\n};\n\nconst getDragNDropObserver = element => {\n    // see if already exists, if so, return\n    const observer = dragNDropObservers.find(item => item.element === element);\n    if (observer) {\n        return observer;\n    }\n\n    // create new observer, does not yet exist for this element\n    const newObserver = createDragNDropObserver(element);\n    dragNDropObservers.push(newObserver);\n    return newObserver;\n};\n\nconst createDragNDropObserver = element => {\n    const clients = [];\n\n    const routes = {\n        dragenter,\n        dragover,\n        dragleave,\n        drop,\n    };\n\n    const handlers = {};\n\n    forin(routes, (event, createHandler) => {\n        handlers[event] = createHandler(element, clients);\n        element.addEventListener(event, handlers[event], false);\n    });\n\n    const observer = {\n        element,\n        addListener: client => {\n            // add as client\n            clients.push(client);\n\n            // return removeListener function\n            return () => {\n                // remove client\n                clients.splice(clients.indexOf(client), 1);\n\n                // if no more clients, clean up observer\n                if (clients.length === 0) {\n                    dragNDropObservers.splice(dragNDropObservers.indexOf(observer), 1);\n\n                    forin(routes, event => {\n                        element.removeEventListener(event, handlers[event], false);\n                    });\n                }\n            };\n        },\n    };\n\n    return observer;\n};\n\nconst elementFromPoint = (root, point) => {\n    if (!('elementFromPoint' in root)) {\n        root = document;\n    }\n    return root.elementFromPoint(point.x, point.y);\n};\n\nconst isEventTarget = (e, target) => {\n    // get root\n    const root = getRootNode(target);\n\n    // get element at position\n    // if root is not actual shadow DOM and does not have elementFromPoint method, use the one on document\n    const elementAtPosition = elementFromPoint(root, {\n        x: e.pageX - window.pageXOffset,\n        y: e.pageY - window.pageYOffset,\n    });\n\n    // test if target is the element or if one of its children is\n    return elementAtPosition === target || target.contains(elementAtPosition);\n};\n\nlet initialTarget = null;\n\nconst setDropEffect = (dataTransfer, effect) => {\n    // is in try catch as IE11 will throw error if not\n    try {\n        dataTransfer.dropEffect = effect;\n    } catch (e) {}\n};\n\nconst dragenter = (root, clients) => e => {\n    e.preventDefault();\n\n    initialTarget = e.target;\n\n    clients.forEach(client => {\n        const { element, onenter } = client;\n\n        if (isEventTarget(e, element)) {\n            client.state = 'enter';\n\n            // fire enter event\n            onenter(eventPosition(e));\n        }\n    });\n};\n\nconst dragover = (root, clients) => e => {\n    e.preventDefault();\n\n    const dataTransfer = e.dataTransfer;\n\n    requestDataTransferItems(dataTransfer).then(items => {\n        let overDropTarget = false;\n\n        clients.some(client => {\n            const { filterElement, element, onenter, onexit, ondrag, allowdrop } = client;\n\n            // by default we can drop\n            setDropEffect(dataTransfer, 'copy');\n\n            // allow transfer of these items\n            const allowsTransfer = allowdrop(items);\n\n            // only used when can be dropped on page\n            if (!allowsTransfer) {\n                setDropEffect(dataTransfer, 'none');\n                return;\n            }\n\n            // targetting this client\n            if (isEventTarget(e, element)) {\n                overDropTarget = true;\n\n                // had no previous state, means we are entering this client\n                if (client.state === null) {\n                    client.state = 'enter';\n                    onenter(eventPosition(e));\n                    return;\n                }\n\n                // now over element (no matter if it allows the drop or not)\n                client.state = 'over';\n\n                // needs to allow transfer\n                if (filterElement && !allowsTransfer) {\n                    setDropEffect(dataTransfer, 'none');\n                    return;\n                }\n\n                // dragging\n                ondrag(eventPosition(e));\n            } else {\n                // should be over an element to drop\n                if (filterElement && !overDropTarget) {\n                    setDropEffect(dataTransfer, 'none');\n                }\n\n                // might have just left this client?\n                if (client.state) {\n                    client.state = null;\n                    onexit(eventPosition(e));\n                }\n            }\n        });\n    });\n};\n\nconst drop = (root, clients) => e => {\n    e.preventDefault();\n\n    const dataTransfer = e.dataTransfer;\n\n    requestDataTransferItems(dataTransfer).then(items => {\n        clients.forEach(client => {\n            const { filterElement, element, ondrop, onexit, allowdrop } = client;\n\n            client.state = null;\n\n            // if we're filtering on element we need to be over the element to drop\n            if (filterElement && !isEventTarget(e, element)) return;\n\n            // no transfer for this client\n            if (!allowdrop(items)) return onexit(eventPosition(e));\n\n            // we can drop these items on this client\n            ondrop(eventPosition(e), items);\n        });\n    });\n};\n\nconst dragleave = (root, clients) => e => {\n    if (initialTarget !== e.target) {\n        return;\n    }\n\n    clients.forEach(client => {\n        const { onexit } = client;\n\n        client.state = null;\n\n        onexit(eventPosition(e));\n    });\n};\n\nconst createHopper = (scope, validateItems, options) => {\n    // is now hopper scope\n    scope.classList.add('filepond--hopper');\n\n    // shortcuts\n    const { catchesDropsOnPage, requiresDropOnElement, filterItems = items => items } = options;\n\n    // create a dnd client\n    const client = createDragNDropClient(\n        scope,\n        catchesDropsOnPage ? document.documentElement : scope,\n        requiresDropOnElement\n    );\n\n    // current client state\n    let lastState = '';\n    let currentState = '';\n\n    // determines if a file may be dropped\n    client.allowdrop = items => {\n        // TODO: if we can, throw error to indicate the items cannot by dropped\n\n        return validateItems(filterItems(items));\n    };\n\n    client.ondrop = (position, items) => {\n        const filteredItems = filterItems(items);\n\n        if (!validateItems(filteredItems)) {\n            api.ondragend(position);\n            return;\n        }\n\n        currentState = 'drag-drop';\n\n        api.onload(filteredItems, position);\n    };\n\n    client.ondrag = position => {\n        api.ondrag(position);\n    };\n\n    client.onenter = position => {\n        currentState = 'drag-over';\n\n        api.ondragstart(position);\n    };\n\n    client.onexit = position => {\n        currentState = 'drag-exit';\n\n        api.ondragend(position);\n    };\n\n    const api = {\n        updateHopperState: () => {\n            if (lastState !== currentState) {\n                scope.dataset.hopperState = currentState;\n                lastState = currentState;\n            }\n        },\n        onload: () => {},\n        ondragstart: () => {},\n        ondrag: () => {},\n        ondragend: () => {},\n        destroy: () => {\n            // destroy client\n            client.destroy();\n        },\n    };\n\n    return api;\n};\n\nlet listening = false;\nconst listeners$1 = [];\n\nconst handlePaste = e => {\n    // if is pasting in input or textarea and the target is outside of a filepond scope, ignore\n    const activeEl = document.activeElement;\n    const isActiveElementEditable =\n        activeEl &&\n        (/textarea|input/i.test(activeEl.nodeName) ||\n            activeEl.getAttribute('contenteditable') === 'true' ||\n            activeEl.getAttribute('contenteditable') === '');\n\n    if (isActiveElementEditable) {\n        // test textarea or input is contained in filepond root\n        let inScope = false;\n        let element = activeEl;\n        while (element !== document.body) {\n            if (element.classList.contains('filepond--root')) {\n                inScope = true;\n                break;\n            }\n            element = element.parentNode;\n        }\n\n        if (!inScope) return;\n    }\n\n    requestDataTransferItems(e.clipboardData).then(files => {\n        // no files received\n        if (!files.length) {\n            return;\n        }\n\n        // notify listeners of received files\n        listeners$1.forEach(listener => listener(files));\n    });\n};\n\nconst listen = cb => {\n    // can't add twice\n    if (listeners$1.includes(cb)) {\n        return;\n    }\n\n    // add initial listener\n    listeners$1.push(cb);\n\n    // setup paste listener for entire page\n    if (listening) {\n        return;\n    }\n\n    listening = true;\n    document.addEventListener('paste', handlePaste);\n};\n\nconst unlisten = listener => {\n    arrayRemove(listeners$1, listeners$1.indexOf(listener));\n\n    // clean up\n    if (listeners$1.length === 0) {\n        document.removeEventListener('paste', handlePaste);\n        listening = false;\n    }\n};\n\nconst createPaster = () => {\n    const cb = files => {\n        api.onload(files);\n    };\n\n    const api = {\n        destroy: () => {\n            unlisten(cb);\n        },\n        onload: () => {},\n    };\n\n    listen(cb);\n\n    return api;\n};\n\n/**\n * Creates the file view\n */\nconst create$d = ({ root, props }) => {\n    root.element.id = `filepond--assistant-${props.id}`;\n    attr(root.element, 'role', 'alert');\n    attr(root.element, 'aria-live', 'polite');\n    attr(root.element, 'aria-relevant', 'additions');\n};\n\nlet addFilesNotificationTimeout = null;\nlet notificationClearTimeout = null;\n\nconst filenames = [];\n\nconst assist = (root, message) => {\n    root.element.textContent = message;\n};\n\nconst clear$1 = root => {\n    root.element.textContent = '';\n};\n\nconst listModified = (root, filename, label) => {\n    const total = root.query('GET_TOTAL_ITEMS');\n    assist(\n        root,\n        `${label} ${filename}, ${total} ${\n            total === 1\n                ? root.query('GET_LABEL_FILE_COUNT_SINGULAR')\n                : root.query('GET_LABEL_FILE_COUNT_PLURAL')\n        }`\n    );\n\n    // clear group after set amount of time so the status is not read twice\n    clearTimeout(notificationClearTimeout);\n    notificationClearTimeout = setTimeout(() => {\n        clear$1(root);\n    }, 1500);\n};\n\nconst isUsingFilePond = root => root.element.parentNode.contains(document.activeElement);\n\nconst itemAdded = ({ root, action }) => {\n    if (!isUsingFilePond(root)) {\n        return;\n    }\n\n    root.element.textContent = '';\n    const item = root.query('GET_ITEM', action.id);\n    filenames.push(item.filename);\n\n    clearTimeout(addFilesNotificationTimeout);\n    addFilesNotificationTimeout = setTimeout(() => {\n        listModified(root, filenames.join(', '), root.query('GET_LABEL_FILE_ADDED'));\n        filenames.length = 0;\n    }, 750);\n};\n\nconst itemRemoved = ({ root, action }) => {\n    if (!isUsingFilePond(root)) {\n        return;\n    }\n\n    const item = action.item;\n    listModified(root, item.filename, root.query('GET_LABEL_FILE_REMOVED'));\n};\n\nconst itemProcessed = ({ root, action }) => {\n    // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n    const label = root.query('GET_LABEL_FILE_PROCESSING_COMPLETE');\n\n    assist(root, `${filename} ${label}`);\n};\n\nconst itemProcessedUndo = ({ root, action }) => {\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n    const label = root.query('GET_LABEL_FILE_PROCESSING_ABORTED');\n\n    assist(root, `${filename} ${label}`);\n};\n\nconst itemError = ({ root, action }) => {\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n\n    // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n    assist(root, `${action.status.main} ${filename} ${action.status.sub}`);\n};\n\nconst assistant = createView({\n    create: create$d,\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: itemAdded,\n        DID_REMOVE_ITEM: itemRemoved,\n        DID_COMPLETE_ITEM_PROCESSING: itemProcessed,\n\n        DID_ABORT_ITEM_PROCESSING: itemProcessedUndo,\n        DID_REVERT_ITEM_PROCESSING: itemProcessedUndo,\n\n        DID_THROW_ITEM_REMOVE_ERROR: itemError,\n        DID_THROW_ITEM_LOAD_ERROR: itemError,\n        DID_THROW_ITEM_INVALID: itemError,\n        DID_THROW_ITEM_PROCESSING_ERROR: itemError,\n    }),\n    tag: 'span',\n    name: 'assistant',\n});\n\nconst toCamels = (string, separator = '-') =>\n    string.replace(new RegExp(`${separator}.`, 'g'), sub => sub.charAt(1).toUpperCase());\n\nconst debounce = (func, interval = 16, immidiateOnly = true) => {\n    let last = Date.now();\n    let timeout = null;\n\n    return (...args) => {\n        clearTimeout(timeout);\n\n        const dist = Date.now() - last;\n\n        const fn = () => {\n            last = Date.now();\n            func(...args);\n        };\n\n        if (dist < interval) {\n            // we need to delay by the difference between interval and dist\n            // for example: if distance is 10 ms and interval is 16 ms,\n            // we need to wait an additional 6ms before calling the function)\n            if (!immidiateOnly) {\n                timeout = setTimeout(fn, interval - dist);\n            }\n        } else {\n            // go!\n            fn();\n        }\n    };\n};\n\nconst MAX_FILES_LIMIT = 1000000;\n\nconst prevent = e => e.preventDefault();\n\nconst create$e = ({ root, props }) => {\n    // Add id\n    const id = root.query('GET_ID');\n    if (id) {\n        root.element.id = id;\n    }\n\n    // Add className\n    const className = root.query('GET_CLASS_NAME');\n    if (className) {\n        className\n            .split(' ')\n            .filter(name => name.length)\n            .forEach(name => {\n                root.element.classList.add(name);\n            });\n    }\n\n    // Field label\n    root.ref.label = root.appendChildView(\n        root.createChildView(dropLabel, {\n            ...props,\n            translateY: null,\n            caption: root.query('GET_LABEL_IDLE'),\n        })\n    );\n\n    // List of items\n    root.ref.list = root.appendChildView(root.createChildView(listScroller, { translateY: null }));\n\n    // Background panel\n    root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'panel-root' }));\n\n    // Assistant notifies assistive tech when content changes\n    root.ref.assistant = root.appendChildView(root.createChildView(assistant, { ...props }));\n\n    // Data\n    root.ref.data = root.appendChildView(root.createChildView(data, { ...props }));\n\n    // Measure (tests if fixed height was set)\n    // DOCTYPE needs to be set for this to work\n    root.ref.measure = createElement$1('div');\n    root.ref.measure.style.height = '100%';\n    root.element.appendChild(root.ref.measure);\n\n    // information on the root height or fixed height status\n    root.ref.bounds = null;\n\n    // apply initial style properties\n    root.query('GET_STYLES')\n        .filter(style => !isEmpty(style.value))\n        .map(({ name, value }) => {\n            root.element.dataset[name] = value;\n        });\n\n    // determine if width changed\n    root.ref.widthPrevious = null;\n    root.ref.widthUpdated = debounce(() => {\n        root.ref.updateHistory = [];\n        root.dispatch('DID_RESIZE_ROOT');\n    }, 250);\n\n    // history of updates\n    root.ref.previousAspectRatio = null;\n    root.ref.updateHistory = [];\n\n    // prevent scrolling and zooming on iOS (only if supports pointer events, for then we can enable reorder)\n    const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;\n    const hasPointerEvents = 'PointerEvent' in window;\n    if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {\n        root.element.addEventListener('touchmove', prevent, { passive: false });\n        root.element.addEventListener('gesturestart', prevent);\n    }\n\n    // add credits\n    const credits = root.query('GET_CREDITS');\n    const hasCredits = credits.length === 2;\n    if (hasCredits) {\n        const frag = document.createElement('a');\n        frag.className = 'filepond--credits';\n        frag.href = credits[0];\n        frag.tabIndex = -1;\n        frag.target = '_blank';\n        frag.rel = 'noopener noreferrer nofollow';\n        frag.textContent = credits[1];\n        root.element.appendChild(frag);\n        root.ref.credits = frag;\n    }\n};\n\nconst write$9 = ({ root, props, actions }) => {\n    // route actions\n    route$5({ root, props, actions });\n\n    // apply style properties\n    actions\n        .filter(action => /^DID_SET_STYLE_/.test(action.type))\n        .filter(action => !isEmpty(action.data.value))\n        .map(({ type, data }) => {\n            const name = toCamels(type.substring(8).toLowerCase(), '_');\n            root.element.dataset[name] = data.value;\n            root.invalidateLayout();\n        });\n\n    if (root.rect.element.hidden) return;\n\n    if (root.rect.element.width !== root.ref.widthPrevious) {\n        root.ref.widthPrevious = root.rect.element.width;\n        root.ref.widthUpdated();\n    }\n\n    // get box bounds, we do this only once\n    let bounds = root.ref.bounds;\n    if (!bounds) {\n        bounds = root.ref.bounds = calculateRootBoundingBoxHeight(root);\n\n        // destroy measure element\n        root.element.removeChild(root.ref.measure);\n        root.ref.measure = null;\n    }\n\n    // get quick references to various high level parts of the upload tool\n    const { hopper, label, list, panel } = root.ref;\n\n    // sets correct state to hopper scope\n    if (hopper) {\n        hopper.updateHopperState();\n    }\n\n    // bool to indicate if we're full or not\n    const aspectRatio = root.query('GET_PANEL_ASPECT_RATIO');\n    const isMultiItem = root.query('GET_ALLOW_MULTIPLE');\n    const totalItems = root.query('GET_TOTAL_ITEMS');\n    const maxItems = isMultiItem ? root.query('GET_MAX_FILES') || MAX_FILES_LIMIT : 1;\n    const atMaxCapacity = totalItems === maxItems;\n\n    // action used to add item\n    const addAction = actions.find(action => action.type === 'DID_ADD_ITEM');\n\n    // if reached max capacity and we've just reached it\n    if (atMaxCapacity && addAction) {\n        // get interaction type\n        const interactionMethod = addAction.data.interactionMethod;\n\n        // hide label\n        label.opacity = 0;\n\n        if (isMultiItem) {\n            label.translateY = -40;\n        } else {\n            if (interactionMethod === InteractionMethod.API) {\n                label.translateX = 40;\n            } else if (interactionMethod === InteractionMethod.BROWSE) {\n                label.translateY = 40;\n            } else {\n                label.translateY = 30;\n            }\n        }\n    } else if (!atMaxCapacity) {\n        label.opacity = 1;\n        label.translateX = 0;\n        label.translateY = 0;\n    }\n\n    const listItemMargin = calculateListItemMargin(root);\n\n    const listHeight = calculateListHeight(root);\n\n    const labelHeight = label.rect.element.height;\n    const currentLabelHeight = !isMultiItem || atMaxCapacity ? 0 : labelHeight;\n\n    const listMarginTop = atMaxCapacity ? list.rect.element.marginTop : 0;\n    const listMarginBottom = totalItems === 0 ? 0 : list.rect.element.marginBottom;\n\n    const visualHeight = currentLabelHeight + listMarginTop + listHeight.visual + listMarginBottom;\n    const boundsHeight = currentLabelHeight + listMarginTop + listHeight.bounds + listMarginBottom;\n\n    // link list to label bottom position\n    list.translateY =\n        Math.max(0, currentLabelHeight - list.rect.element.marginTop) - listItemMargin.top;\n\n    if (aspectRatio) {\n        // fixed aspect ratio\n\n        // calculate height based on width\n        const width = root.rect.element.width;\n        const height = width * aspectRatio;\n\n        // clear history if aspect ratio has changed\n        if (aspectRatio !== root.ref.previousAspectRatio) {\n            root.ref.previousAspectRatio = aspectRatio;\n            root.ref.updateHistory = [];\n        }\n\n        // remember this width\n        const history = root.ref.updateHistory;\n        history.push(width);\n\n        const MAX_BOUNCES = 2;\n        if (history.length > MAX_BOUNCES * 2) {\n            const l = history.length;\n            const bottom = l - 10;\n            let bounces = 0;\n            for (let i = l; i >= bottom; i--) {\n                if (history[i] === history[i - 2]) {\n                    bounces++;\n                }\n\n                if (bounces >= MAX_BOUNCES) {\n                    // dont adjust height\n                    return;\n                }\n            }\n        }\n\n        // fix height of panel so it adheres to aspect ratio\n        panel.scalable = false;\n        panel.height = height;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            height -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        if (listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = height;\n    } else if (bounds.fixedHeight) {\n        // fixed height\n\n        // fix height of panel\n        panel.scalable = false;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            bounds.fixedHeight -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        // set list height\n        if (listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // no need to set container bounds as these are handles by CSS fixed height\n    } else if (bounds.cappedHeight) {\n        // max-height\n\n        // not a fixed height panel\n        const isCappedHeight = visualHeight >= bounds.cappedHeight;\n        const panelHeight = Math.min(bounds.cappedHeight, visualHeight);\n        panel.scalable = true;\n        panel.height = isCappedHeight\n            ? panelHeight\n            : panelHeight - listItemMargin.top - listItemMargin.bottom;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            panelHeight -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        // set list height (if is overflowing)\n        if (visualHeight > bounds.cappedHeight && listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = Math.min(\n            bounds.cappedHeight,\n            boundsHeight - listItemMargin.top - listItemMargin.bottom\n        );\n    } else {\n        // flexible height\n\n        // not a fixed height panel\n        const itemMargin = totalItems > 0 ? listItemMargin.top + listItemMargin.bottom : 0;\n        panel.scalable = true;\n        panel.height = Math.max(labelHeight, visualHeight - itemMargin);\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = Math.max(labelHeight, boundsHeight - itemMargin);\n    }\n\n    // move credits to bottom\n    if (root.ref.credits && panel.heightCurrent)\n        root.ref.credits.style.transform = `translateY(${panel.heightCurrent}px)`;\n};\n\nconst calculateListItemMargin = root => {\n    const item = root.ref.list.childViews[0].childViews[0];\n    return item\n        ? {\n              top: item.rect.element.marginTop,\n              bottom: item.rect.element.marginBottom,\n          }\n        : {\n              top: 0,\n              bottom: 0,\n          };\n};\n\nconst calculateListHeight = root => {\n    let visual = 0;\n    let bounds = 0;\n\n    // get file list reference\n    const scrollList = root.ref.list;\n    const itemList = scrollList.childViews[0];\n    const visibleChildren = itemList.childViews.filter(child => child.rect.element.height);\n    const children = root\n        .query('GET_ACTIVE_ITEMS')\n        .map(item => visibleChildren.find(child => child.id === item.id))\n        .filter(item => item);\n\n    // no children, done!\n    if (children.length === 0) return { visual, bounds };\n\n    const horizontalSpace = itemList.rect.element.width;\n    const dragIndex = getItemIndexByPosition(itemList, children, scrollList.dragCoordinates);\n\n    const childRect = children[0].rect.element;\n\n    const itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n    const itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n\n    const itemWidth = childRect.width + itemHorizontalMargin;\n    const itemHeight = childRect.height + itemVerticalMargin;\n\n    const newItem = typeof dragIndex !== 'undefined' && dragIndex >= 0 ? 1 : 0;\n    const removedItem = children.find(child => child.markedForRemoval && child.opacity < 0.45)\n        ? -1\n        : 0;\n    const verticalItemCount = children.length + newItem + removedItem;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        children.forEach(item => {\n            const height = item.rect.element.height + itemVerticalMargin;\n            bounds += height;\n            visual += height * item.opacity;\n        });\n    }\n    // grid\n    else {\n        bounds = Math.ceil(verticalItemCount / itemsPerRow) * itemHeight;\n        visual = bounds;\n    }\n\n    return { visual, bounds };\n};\n\nconst calculateRootBoundingBoxHeight = root => {\n    const height = root.ref.measureHeight || null;\n    const cappedHeight = parseInt(root.style.maxHeight, 10) || null;\n    const fixedHeight = height === 0 ? null : height;\n\n    return {\n        cappedHeight,\n        fixedHeight,\n    };\n};\n\nconst exceedsMaxFiles = (root, items) => {\n    const allowReplace = root.query('GET_ALLOW_REPLACE');\n    const allowMultiple = root.query('GET_ALLOW_MULTIPLE');\n    const totalItems = root.query('GET_TOTAL_ITEMS');\n    let maxItems = root.query('GET_MAX_FILES');\n\n    // total amount of items being dragged\n    const totalBrowseItems = items.length;\n\n    // if does not allow multiple items and dragging more than one item\n    if (!allowMultiple && totalBrowseItems > 1) {\n        root.dispatch('DID_THROW_MAX_FILES', {\n            source: items,\n            error: createResponse('warning', 0, 'Max files'),\n        });\n        return true;\n    }\n\n    // limit max items to one if not allowed to drop multiple items\n    maxItems = allowMultiple ? maxItems : 1;\n\n    if (!allowMultiple && allowReplace) {\n        // There is only one item, so there is room to replace or add an item\n        return false;\n    }\n\n    // no more room?\n    const hasMaxItems = isInt(maxItems);\n    if (hasMaxItems && totalItems + totalBrowseItems > maxItems) {\n        root.dispatch('DID_THROW_MAX_FILES', {\n            source: items,\n            error: createResponse('warning', 0, 'Max files'),\n        });\n        return true;\n    }\n\n    return false;\n};\n\nconst getDragIndex = (list, children, position) => {\n    const itemList = list.childViews[0];\n    return getItemIndexByPosition(itemList, children, {\n        left: position.scopeLeft - itemList.rect.element.left,\n        top:\n            position.scopeTop -\n            (list.rect.outer.top + list.rect.element.marginTop + list.rect.element.scrollTop),\n    });\n};\n\n/**\n * Enable or disable file drop functionality\n */\nconst toggleDrop = root => {\n    const isAllowed = root.query('GET_ALLOW_DROP');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.hopper) {\n        const hopper = createHopper(\n            root.element,\n            items => {\n                // allow quick validation of dropped items\n                const beforeDropFile = root.query('GET_BEFORE_DROP_FILE') || (() => true);\n\n                // all items should be validated by all filters as valid\n                const dropValidation = root.query('GET_DROP_VALIDATION');\n                return dropValidation\n                    ? items.every(\n                          item =>\n                              applyFilters('ALLOW_HOPPER_ITEM', item, {\n                                  query: root.query,\n                              }).every(result => result === true) && beforeDropFile(item)\n                      )\n                    : true;\n            },\n            {\n                filterItems: items => {\n                    const ignoredFiles = root.query('GET_IGNORED_FILES');\n                    return items.filter(item => {\n                        if (isFile(item)) {\n                            return !ignoredFiles.includes(item.name.toLowerCase());\n                        }\n                        return true;\n                    });\n                },\n                catchesDropsOnPage: root.query('GET_DROP_ON_PAGE'),\n                requiresDropOnElement: root.query('GET_DROP_ON_ELEMENT'),\n            }\n        );\n\n        hopper.onload = (items, position) => {\n            // get item children elements and sort based on list sort\n            const list = root.ref.list.childViews[0];\n            const visibleChildren = list.childViews.filter(child => child.rect.element.height);\n            const children = root\n                .query('GET_ACTIVE_ITEMS')\n                .map(item => visibleChildren.find(child => child.id === item.id))\n                .filter(item => item);\n\n            applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(queue => {\n                // these files don't fit so stop here\n                if (exceedsMaxFiles(root, queue)) return false;\n\n                // go\n                root.dispatch('ADD_ITEMS', {\n                    items: queue,\n                    index: getDragIndex(root.ref.list, children, position),\n                    interactionMethod: InteractionMethod.DROP,\n                });\n            });\n\n            root.dispatch('DID_DROP', { position });\n\n            root.dispatch('DID_END_DRAG', { position });\n        };\n\n        hopper.ondragstart = position => {\n            root.dispatch('DID_START_DRAG', { position });\n        };\n\n        hopper.ondrag = debounce(position => {\n            root.dispatch('DID_DRAG', { position });\n        });\n\n        hopper.ondragend = position => {\n            root.dispatch('DID_END_DRAG', { position });\n        };\n\n        root.ref.hopper = hopper;\n\n        root.ref.drip = root.appendChildView(root.createChildView(drip));\n    } else if (!enabled && root.ref.hopper) {\n        root.ref.hopper.destroy();\n        root.ref.hopper = null;\n        root.removeChildView(root.ref.drip);\n    }\n};\n\n/**\n * Enable or disable browse functionality\n */\nconst toggleBrowse = (root, props) => {\n    const isAllowed = root.query('GET_ALLOW_BROWSE');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.browser) {\n        root.ref.browser = root.appendChildView(\n            root.createChildView(browser, {\n                ...props,\n                onload: items => {\n                    applyFilterChain('ADD_ITEMS', items, {\n                        dispatch: root.dispatch,\n                    }).then(queue => {\n                        // these files don't fit so stop here\n                        if (exceedsMaxFiles(root, queue)) return false;\n\n                        // add items!\n                        root.dispatch('ADD_ITEMS', {\n                            items: queue,\n                            index: -1,\n                            interactionMethod: InteractionMethod.BROWSE,\n                        });\n                    });\n                },\n            }),\n            0\n        );\n    } else if (!enabled && root.ref.browser) {\n        root.removeChildView(root.ref.browser);\n        root.ref.browser = null;\n    }\n};\n\n/**\n * Enable or disable paste functionality\n */\nconst togglePaste = root => {\n    const isAllowed = root.query('GET_ALLOW_PASTE');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.paster) {\n        root.ref.paster = createPaster();\n        root.ref.paster.onload = items => {\n            applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(queue => {\n                // these files don't fit so stop here\n                if (exceedsMaxFiles(root, queue)) return false;\n\n                // add items!\n                root.dispatch('ADD_ITEMS', {\n                    items: queue,\n                    index: -1,\n                    interactionMethod: InteractionMethod.PASTE,\n                });\n            });\n        };\n    } else if (!enabled && root.ref.paster) {\n        root.ref.paster.destroy();\n        root.ref.paster = null;\n    }\n};\n\n/**\n * Route actions\n */\nconst route$5 = createRoute({\n    DID_SET_ALLOW_BROWSE: ({ root, props }) => {\n        toggleBrowse(root, props);\n    },\n    DID_SET_ALLOW_DROP: ({ root }) => {\n        toggleDrop(root);\n    },\n    DID_SET_ALLOW_PASTE: ({ root }) => {\n        togglePaste(root);\n    },\n    DID_SET_DISABLED: ({ root, props }) => {\n        toggleDrop(root);\n        togglePaste(root);\n        toggleBrowse(root, props);\n        const isDisabled = root.query('GET_DISABLED');\n        if (isDisabled) {\n            root.element.dataset.disabled = 'disabled';\n        } else {\n            // delete root.element.dataset.disabled; <= this does not work on iOS 10\n            root.element.removeAttribute('data-disabled');\n        }\n    },\n});\n\nconst root = createView({\n    name: 'root',\n    read: ({ root }) => {\n        if (root.ref.measure) {\n            root.ref.measureHeight = root.ref.measure.offsetHeight;\n        }\n    },\n    create: create$e,\n    write: write$9,\n    destroy: ({ root }) => {\n        if (root.ref.paster) {\n            root.ref.paster.destroy();\n        }\n        if (root.ref.hopper) {\n            root.ref.hopper.destroy();\n        }\n        root.element.removeEventListener('touchmove', prevent);\n        root.element.removeEventListener('gesturestart', prevent);\n    },\n    mixins: {\n        styles: ['height'],\n    },\n});\n\n// creates the app\nconst createApp = (initialOptions = {}) => {\n    // let element\n    let originalElement = null;\n\n    // get default options\n    const defaultOptions = getOptions();\n\n    // create the data store, this will contain all our app info\n    const store = createStore(\n        // initial state (should be serializable)\n        createInitialState(defaultOptions),\n\n        // queries\n        [queries, createOptionQueries(defaultOptions)],\n\n        // action handlers\n        [actions, createOptionActions(defaultOptions)]\n    );\n\n    // set initial options\n    store.dispatch('SET_OPTIONS', { options: initialOptions });\n\n    // kick thread if visibility changes\n    const visibilityHandler = () => {\n        if (document.hidden) return;\n        store.dispatch('KICK');\n    };\n    document.addEventListener('visibilitychange', visibilityHandler);\n\n    // re-render on window resize start and finish\n    let resizeDoneTimer = null;\n    let isResizing = false;\n    let isResizingHorizontally = false;\n    let initialWindowWidth = null;\n    let currentWindowWidth = null;\n    const resizeHandler = () => {\n        if (!isResizing) {\n            isResizing = true;\n        }\n        clearTimeout(resizeDoneTimer);\n        resizeDoneTimer = setTimeout(() => {\n            isResizing = false;\n            initialWindowWidth = null;\n            currentWindowWidth = null;\n            if (isResizingHorizontally) {\n                isResizingHorizontally = false;\n                store.dispatch('DID_STOP_RESIZE');\n            }\n        }, 500);\n    };\n    window.addEventListener('resize', resizeHandler);\n\n    // render initial view\n    const view = root(store, { id: getUniqueId() });\n\n    //\n    // PRIVATE API -------------------------------------------------------------------------------------\n    //\n    let isResting = false;\n    let isHidden = false;\n\n    const readWriteApi = {\n        // necessary for update loop\n\n        /**\n         * Reads from dom (never call manually)\n         * @private\n         */\n        _read: () => {\n            // test if we're resizing horizontally\n            // TODO: see if we can optimize this by measuring root rect\n            if (isResizing) {\n                currentWindowWidth = window.innerWidth;\n                if (!initialWindowWidth) {\n                    initialWindowWidth = currentWindowWidth;\n                }\n\n                if (!isResizingHorizontally && currentWindowWidth !== initialWindowWidth) {\n                    store.dispatch('DID_START_RESIZE');\n                    isResizingHorizontally = true;\n                }\n            }\n\n            if (isHidden && isResting) {\n                // test if is no longer hidden\n                isResting = view.element.offsetParent === null;\n            }\n\n            // if resting, no need to read as numbers will still all be correct\n            if (isResting) return;\n\n            // read view data\n            view._read();\n\n            // if is hidden we need to know so we exit rest mode when revealed\n            isHidden = view.rect.element.hidden;\n        },\n\n        /**\n         * Writes to dom (never call manually)\n         * @private\n         */\n        _write: ts => {\n            // get all actions from store\n            const actions = store\n                .processActionQueue()\n\n                // filter out set actions (these will automatically trigger DID_SET)\n                .filter(action => !/^SET_/.test(action.type));\n\n            // if was idling and no actions stop here\n            if (isResting && !actions.length) return;\n\n            // some actions might trigger events\n            routeActionsToEvents(actions);\n\n            // update the view\n            isResting = view._write(ts, actions, isResizingHorizontally);\n\n            // will clean up all archived items\n            removeReleasedItems(store.query('GET_ITEMS'));\n\n            // now idling\n            if (isResting) {\n                store.processDispatchQueue();\n            }\n        },\n    };\n\n    //\n    // EXPOSE EVENTS -------------------------------------------------------------------------------------\n    //\n    const createEvent = name => data => {\n        // create default event\n        const event = {\n            type: name,\n        };\n\n        // no data to add\n        if (!data) {\n            return event;\n        }\n\n        // copy relevant props\n        if (data.hasOwnProperty('error')) {\n            event.error = data.error ? { ...data.error } : null;\n        }\n\n        if (data.status) {\n            event.status = { ...data.status };\n        }\n\n        if (data.file) {\n            event.output = data.file;\n        }\n\n        // only source is available, else add item if possible\n        if (data.source) {\n            event.file = data.source;\n        } else if (data.item || data.id) {\n            const item = data.item ? data.item : store.query('GET_ITEM', data.id);\n            event.file = item ? createItemAPI(item) : null;\n        }\n\n        // map all items in a possible items array\n        if (data.items) {\n            event.items = data.items.map(createItemAPI);\n        }\n\n        // if this is a progress event add the progress amount\n        if (/progress/.test(name)) {\n            event.progress = data.progress;\n        }\n\n        // copy relevant props\n        if (data.hasOwnProperty('origin') && data.hasOwnProperty('target')) {\n            event.origin = data.origin;\n            event.target = data.target;\n        }\n\n        return event;\n    };\n\n    const eventRoutes = {\n        DID_DESTROY: createEvent('destroy'),\n\n        DID_INIT: createEvent('init'),\n\n        DID_THROW_MAX_FILES: createEvent('warning'),\n\n        DID_INIT_ITEM: createEvent('initfile'),\n        DID_START_ITEM_LOAD: createEvent('addfilestart'),\n        DID_UPDATE_ITEM_LOAD_PROGRESS: createEvent('addfileprogress'),\n        DID_LOAD_ITEM: createEvent('addfile'),\n\n        DID_THROW_ITEM_INVALID: [createEvent('error'), createEvent('addfile')],\n\n        DID_THROW_ITEM_LOAD_ERROR: [createEvent('error'), createEvent('addfile')],\n\n        DID_THROW_ITEM_REMOVE_ERROR: [createEvent('error'), createEvent('removefile')],\n\n        DID_PREPARE_OUTPUT: createEvent('preparefile'),\n\n        DID_START_ITEM_PROCESSING: createEvent('processfilestart'),\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: createEvent('processfileprogress'),\n        DID_ABORT_ITEM_PROCESSING: createEvent('processfileabort'),\n        DID_COMPLETE_ITEM_PROCESSING: createEvent('processfile'),\n        DID_COMPLETE_ITEM_PROCESSING_ALL: createEvent('processfiles'),\n        DID_REVERT_ITEM_PROCESSING: createEvent('processfilerevert'),\n\n        DID_THROW_ITEM_PROCESSING_ERROR: [createEvent('error'), createEvent('processfile')],\n\n        DID_REMOVE_ITEM: createEvent('removefile'),\n\n        DID_UPDATE_ITEMS: createEvent('updatefiles'),\n\n        DID_ACTIVATE_ITEM: createEvent('activatefile'),\n\n        DID_REORDER_ITEMS: createEvent('reorderfiles'),\n    };\n\n    const exposeEvent = event => {\n        // create event object to be dispatched\n        const detail = { pond: exports, ...event };\n        delete detail.type;\n        view.element.dispatchEvent(\n            new CustomEvent(`FilePond:${event.type}`, {\n                // event info\n                detail,\n\n                // event behaviour\n                bubbles: true,\n                cancelable: true,\n                composed: true, // triggers listeners outside of shadow root\n            })\n        );\n\n        // event object to params used for `on()` event handlers and callbacks `oninit()`\n        const params = [];\n\n        // if is possible error event, make it the first param\n        if (event.hasOwnProperty('error')) {\n            params.push(event.error);\n        }\n\n        // file is always section\n        if (event.hasOwnProperty('file')) {\n            params.push(event.file);\n        }\n\n        // append other props\n        const filtered = ['type', 'error', 'file'];\n        Object.keys(event)\n            .filter(key => !filtered.includes(key))\n            .forEach(key => params.push(event[key]));\n\n        // on(type, () => { })\n        exports.fire(event.type, ...params);\n\n        // oninit = () => {}\n        const handler = store.query(`GET_ON${event.type.toUpperCase()}`);\n        if (handler) {\n            handler(...params);\n        }\n    };\n\n    const routeActionsToEvents = actions => {\n        if (!actions.length) return;\n        actions\n            .filter(action => eventRoutes[action.type])\n            .forEach(action => {\n                const routes = eventRoutes[action.type];\n                (Array.isArray(routes) ? routes : [routes]).forEach(route => {\n                    // this isn't fantastic, but because of the stacking of settimeouts plugins can handle the did_load before the did_init\n                    if (action.type === 'DID_INIT_ITEM') {\n                        exposeEvent(route(action.data));\n                    } else {\n                        setTimeout(() => {\n                            exposeEvent(route(action.data));\n                        }, 0);\n                    }\n                });\n            });\n    };\n\n    //\n    // PUBLIC API -------------------------------------------------------------------------------------\n    //\n    const setOptions = options => store.dispatch('SET_OPTIONS', { options });\n\n    const getFile = query => store.query('GET_ACTIVE_ITEM', query);\n\n    const prepareFile = query =>\n        new Promise((resolve, reject) => {\n            store.dispatch('REQUEST_ITEM_PREPARE', {\n                query,\n                success: item => {\n                    resolve(item);\n                },\n                failure: error => {\n                    reject(error);\n                },\n            });\n        });\n\n    const addFile = (source, options = {}) =>\n        new Promise((resolve, reject) => {\n            addFiles([{ source, options }], { index: options.index })\n                .then(items => resolve(items && items[0]))\n                .catch(reject);\n        });\n\n    const isFilePondFile = obj => obj.file && obj.id;\n\n    const removeFile = (query, options) => {\n        // if only passed options\n        if (typeof query === 'object' && !isFilePondFile(query) && !options) {\n            options = query;\n            query = undefined;\n        }\n\n        // request item removal\n        store.dispatch('REMOVE_ITEM', { ...options, query });\n\n        // see if item has been removed\n        return store.query('GET_ACTIVE_ITEM', query) === null;\n    };\n\n    const addFiles = (...args) =>\n        new Promise((resolve, reject) => {\n            const sources = [];\n            const options = {};\n\n            // user passed a sources array\n            if (isArray(args[0])) {\n                sources.push.apply(sources, args[0]);\n                Object.assign(options, args[1] || {});\n            } else {\n                // user passed sources as arguments, last one might be options object\n                const lastArgument = args[args.length - 1];\n                if (typeof lastArgument === 'object' && !(lastArgument instanceof Blob)) {\n                    Object.assign(options, args.pop());\n                }\n\n                // add rest to sources\n                sources.push(...args);\n            }\n\n            store.dispatch('ADD_ITEMS', {\n                items: sources,\n                index: options.index,\n                interactionMethod: InteractionMethod.API,\n                success: resolve,\n                failure: reject,\n            });\n        });\n\n    const getFiles = () => store.query('GET_ACTIVE_ITEMS');\n\n    const processFile = query =>\n        new Promise((resolve, reject) => {\n            store.dispatch('REQUEST_ITEM_PROCESSING', {\n                query,\n                success: item => {\n                    resolve(item);\n                },\n                failure: error => {\n                    reject(error);\n                },\n            });\n        });\n\n    const prepareFiles = (...args) => {\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n        const items = queries.length ? queries : getFiles();\n        return Promise.all(items.map(prepareFile));\n    };\n\n    const processFiles = (...args) => {\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n        if (!queries.length) {\n            const files = getFiles().filter(\n                item =>\n                    !(item.status === ItemStatus.IDLE && item.origin === FileOrigin.LOCAL) &&\n                    item.status !== ItemStatus.PROCESSING &&\n                    item.status !== ItemStatus.PROCESSING_COMPLETE &&\n                    item.status !== ItemStatus.PROCESSING_REVERT_ERROR\n            );\n            return Promise.all(files.map(processFile));\n        }\n        return Promise.all(queries.map(processFile));\n    };\n\n    const removeFiles = (...args) => {\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n\n        let options;\n        if (typeof queries[queries.length - 1] === 'object') {\n            options = queries.pop();\n        } else if (Array.isArray(args[0])) {\n            options = args[1];\n        }\n\n        const files = getFiles();\n\n        if (!queries.length) return Promise.all(files.map(file => removeFile(file, options)));\n\n        // when removing by index the indexes shift after each file removal so we need to convert indexes to ids\n        const mappedQueries = queries\n            .map(query => (isNumber(query) ? (files[query] ? files[query].id : null) : query))\n            .filter(query => query);\n\n        return mappedQueries.map(q => removeFile(q, options));\n    };\n\n    const exports = {\n        // supports events\n        ...on(),\n\n        // inject private api methods\n        ...readWriteApi,\n\n        // inject all getters and setters\n        ...createOptionAPI(store, defaultOptions),\n\n        /**\n         * Override options defined in options object\n         * @param options\n         */\n        setOptions,\n\n        /**\n         * Load the given file\n         * @param source - the source of the file (either a File, base64 data uri or url)\n         * @param options - object, { index: 0 }\n         */\n        addFile,\n\n        /**\n         * Load the given files\n         * @param sources - the sources of the files to load\n         * @param options - object, { index: 0 }\n         */\n        addFiles,\n\n        /**\n         * Returns the file objects matching the given query\n         * @param query { string, number, null }\n         */\n        getFile,\n\n        /**\n         * Upload file with given name\n         * @param query { string, number, null  }\n         */\n        processFile,\n\n        /**\n         * Request prepare output for file with given name\n         * @param query { string, number, null  }\n         */\n        prepareFile,\n\n        /**\n         * Removes a file by its name\n         * @param query { string, number, null  }\n         */\n        removeFile,\n\n        /**\n         * Moves a file to a new location in the files list\n         */\n        moveFile: (query, index) => store.dispatch('MOVE_ITEM', { query, index }),\n\n        /**\n         * Returns all files (wrapped in public api)\n         */\n        getFiles,\n\n        /**\n         * Starts uploading all files\n         */\n        processFiles,\n\n        /**\n         * Clears all files from the files list\n         */\n        removeFiles,\n\n        /**\n         * Starts preparing output of all files\n         */\n        prepareFiles,\n\n        /**\n         * Sort list of files\n         */\n        sort: compare => store.dispatch('SORT', { compare }),\n\n        /**\n         * Browse the file system for a file\n         */\n        browse: () => {\n            // needs to be trigger directly as user action needs to be traceable (is not traceable in requestAnimationFrame)\n            var input = view.element.querySelector('input[type=file]');\n            if (input) {\n                input.click();\n            }\n        },\n\n        /**\n         * Destroys the app\n         */\n        destroy: () => {\n            // request destruction\n            exports.fire('destroy', view.element);\n\n            // stop active processes (file uploads, fetches, stuff like that)\n            // loop over items and depending on states call abort for ongoing processes\n            store.dispatch('ABORT_ALL');\n\n            // destroy view\n            view._destroy();\n\n            // stop listening to resize\n            window.removeEventListener('resize', resizeHandler);\n\n            // stop listening to the visiblitychange event\n            document.removeEventListener('visibilitychange', visibilityHandler);\n\n            // dispatch destroy\n            store.dispatch('DID_DESTROY');\n        },\n\n        /**\n         * Inserts the plugin before the target element\n         */\n        insertBefore: element => insertBefore(view.element, element),\n\n        /**\n         * Inserts the plugin after the target element\n         */\n        insertAfter: element => insertAfter(view.element, element),\n\n        /**\n         * Appends the plugin to the target element\n         */\n        appendTo: element => element.appendChild(view.element),\n\n        /**\n         * Replaces an element with the app\n         */\n        replaceElement: element => {\n            // insert the app before the element\n            insertBefore(view.element, element);\n\n            // remove the original element\n            element.parentNode.removeChild(element);\n\n            // remember original element\n            originalElement = element;\n        },\n\n        /**\n         * Restores the original element\n         */\n        restoreElement: () => {\n            if (!originalElement) {\n                return; // no element to restore\n            }\n\n            // restore original element\n            insertAfter(originalElement, view.element);\n\n            // remove our element\n            view.element.parentNode.removeChild(view.element);\n\n            // remove reference\n            originalElement = null;\n        },\n\n        /**\n         * Returns true if the app root is attached to given element\n         * @param element\n         */\n        isAttachedTo: element => view.element === element || originalElement === element,\n\n        /**\n         * Returns the root element\n         */\n        element: {\n            get: () => view.element,\n        },\n\n        /**\n         * Returns the current pond status\n         */\n        status: {\n            get: () => store.query('GET_STATUS'),\n        },\n    };\n\n    // Done!\n    store.dispatch('DID_INIT');\n\n    // create actual api object\n    return createObject(exports);\n};\n\nconst createAppObject = (customOptions = {}) => {\n    // default options\n    const defaultOptions = {};\n    forin(getOptions(), (key, value) => {\n        defaultOptions[key] = value[0];\n    });\n\n    // set app options\n    const app = createApp({\n        // default options\n        ...defaultOptions,\n\n        // custom options\n        ...customOptions,\n    });\n\n    // return the plugin instance\n    return app;\n};\n\nconst lowerCaseFirstLetter = string => string.charAt(0).toLowerCase() + string.slice(1);\n\nconst attributeNameToPropertyName = attributeName => toCamels(attributeName.replace(/^data-/, ''));\n\nconst mapObject = (object, propertyMap) => {\n    // remove unwanted\n    forin(propertyMap, (selector, mapping) => {\n        forin(object, (property, value) => {\n            // create regexp shortcut\n            const selectorRegExp = new RegExp(selector);\n\n            // tests if\n            const matches = selectorRegExp.test(property);\n\n            // no match, skip\n            if (!matches) {\n                return;\n            }\n\n            // if there's a mapping, the original property is always removed\n            delete object[property];\n\n            // should only remove, we done!\n            if (mapping === false) {\n                return;\n            }\n\n            // move value to new property\n            if (isString(mapping)) {\n                object[mapping] = value;\n                return;\n            }\n\n            // move to group\n            const group = mapping.group;\n            if (isObject(mapping) && !object[group]) {\n                object[group] = {};\n            }\n\n            object[group][lowerCaseFirstLetter(property.replace(selectorRegExp, ''))] = value;\n        });\n\n        // do submapping\n        if (mapping.mapping) {\n            mapObject(object[mapping.group], mapping.mapping);\n        }\n    });\n};\n\nconst getAttributesAsObject = (node, attributeMapping = {}) => {\n    // turn attributes into object\n    const attributes = [];\n    forin(node.attributes, index => {\n        attributes.push(node.attributes[index]);\n    });\n\n    const output = attributes\n        .filter(attribute => attribute.name)\n        .reduce((obj, attribute) => {\n            const value = attr(node, attribute.name);\n\n            obj[attributeNameToPropertyName(attribute.name)] =\n                value === attribute.name ? true : value;\n            return obj;\n        }, {});\n\n    // do mapping of object properties\n    mapObject(output, attributeMapping);\n\n    return output;\n};\n\nconst createAppAtElement = (element, options = {}) => {\n    // how attributes of the input element are mapped to the options for the plugin\n    const attributeMapping = {\n        // translate to other name\n        '^class$': 'className',\n        '^multiple$': 'allowMultiple',\n        '^capture$': 'captureMethod',\n        '^webkitdirectory$': 'allowDirectoriesOnly',\n\n        // group under single property\n        '^server': {\n            group: 'server',\n            mapping: {\n                '^process': {\n                    group: 'process',\n                },\n                '^revert': {\n                    group: 'revert',\n                },\n                '^fetch': {\n                    group: 'fetch',\n                },\n                '^restore': {\n                    group: 'restore',\n                },\n                '^load': {\n                    group: 'load',\n                },\n            },\n        },\n\n        // don't include in object\n        '^type$': false,\n        '^files$': false,\n    };\n\n    // add additional option translators\n    applyFilters('SET_ATTRIBUTE_TO_OPTION_MAP', attributeMapping);\n\n    // create final options object by setting options object and then overriding options supplied on element\n    const mergedOptions = {\n        ...options,\n    };\n\n    const attributeOptions = getAttributesAsObject(\n        element.nodeName === 'FIELDSET' ? element.querySelector('input[type=file]') : element,\n        attributeMapping\n    );\n\n    // merge with options object\n    Object.keys(attributeOptions).forEach(key => {\n        if (isObject(attributeOptions[key])) {\n            if (!isObject(mergedOptions[key])) {\n                mergedOptions[key] = {};\n            }\n            Object.assign(mergedOptions[key], attributeOptions[key]);\n        } else {\n            mergedOptions[key] = attributeOptions[key];\n        }\n    });\n\n    // if parent is a fieldset, get files from parent by selecting all input fields that are not file upload fields\n    // these will then be automatically set to the initial files\n    mergedOptions.files = (options.files || []).concat(\n        Array.from(element.querySelectorAll('input:not([type=file])')).map(input => ({\n            source: input.value,\n            options: {\n                type: input.dataset.type,\n            },\n        }))\n    );\n\n    // build plugin\n    const app = createAppObject(mergedOptions);\n\n    // add already selected files\n    if (element.files) {\n        Array.from(element.files).forEach(file => {\n            app.addFile(file);\n        });\n    }\n\n    // replace the target element\n    app.replaceElement(element);\n\n    // expose\n    return app;\n};\n\n// if an element is passed, we create the instance at that element, if not, we just create an up object\nconst createApp$1 = (...args) =>\n    isNode(args[0]) ? createAppAtElement(...args) : createAppObject(...args);\n\nconst PRIVATE_METHODS = ['fire', '_read', '_write'];\n\nconst createAppAPI = app => {\n    const api = {};\n\n    copyObjectPropertiesToObject(app, api, PRIVATE_METHODS);\n\n    return api;\n};\n\n/**\n * Replaces placeholders in given string with replacements\n * @param string - \"Foo {bar}\"\"\n * @param replacements - { \"bar\": 10 }\n */\nconst replaceInString = (string, replacements) =>\n    string.replace(/(?:{([a-zA-Z]+)})/g, (match, group) => replacements[group]);\n\nconst createWorker = fn => {\n    const workerBlob = new Blob(['(', fn.toString(), ')()'], {\n        type: 'application/javascript',\n    });\n    const workerURL = URL.createObjectURL(workerBlob);\n    const worker = new Worker(workerURL);\n\n    return {\n        transfer: (message, cb) => {},\n        post: (message, cb, transferList) => {\n            const id = getUniqueId();\n\n            worker.onmessage = e => {\n                if (e.data.id === id) {\n                    cb(e.data.message);\n                }\n            };\n\n            worker.postMessage(\n                {\n                    id,\n                    message,\n                },\n                transferList\n            );\n        },\n        terminate: () => {\n            worker.terminate();\n            URL.revokeObjectURL(workerURL);\n        },\n    };\n};\n\nconst loadImage = url =>\n    new Promise((resolve, reject) => {\n        const img = new Image();\n        img.onload = () => {\n            resolve(img);\n        };\n        img.onerror = e => {\n            reject(e);\n        };\n        img.src = url;\n    });\n\nconst renameFile = (file, name) => {\n    const renamedFile = file.slice(0, file.size, file.type);\n    renamedFile.lastModifiedDate = file.lastModifiedDate;\n    renamedFile.name = name;\n    return renamedFile;\n};\n\nconst copyFile = file => renameFile(file, file.name);\n\n// already registered plugins (can't register twice)\nconst registeredPlugins = [];\n\n// pass utils to plugin\nconst createAppPlugin = plugin => {\n    // already registered\n    if (registeredPlugins.includes(plugin)) {\n        return;\n    }\n\n    // remember this plugin\n    registeredPlugins.push(plugin);\n\n    // setup!\n    const pluginOutline = plugin({\n        addFilter,\n        utils: {\n            Type,\n            forin,\n            isString,\n            isFile,\n            toNaturalFileSize,\n            replaceInString,\n            getExtensionFromFilename,\n            getFilenameWithoutExtension,\n            guesstimateMimeType,\n            getFileFromBlob,\n            getFilenameFromURL,\n            createRoute,\n            createWorker,\n            createView,\n            createItemAPI,\n            loadImage,\n            copyFile,\n            renameFile,\n            createBlob,\n            applyFilterChain,\n            text,\n            getNumericAspectRatioFromString,\n        },\n        views: {\n            fileActionButton,\n        },\n    });\n\n    // add plugin options to default options\n    extendDefaultOptions(pluginOutline.options);\n};\n\n// feature detection used by supported() method\nconst isOperaMini = () => Object.prototype.toString.call(window.operamini) === '[object OperaMini]';\nconst hasPromises = () => 'Promise' in window;\nconst hasBlobSlice = () => 'slice' in Blob.prototype;\nconst hasCreateObjectURL = () => 'URL' in window && 'createObjectURL' in window.URL;\nconst hasVisibility = () => 'visibilityState' in document;\nconst hasTiming = () => 'performance' in window; // iOS 8.x\nconst hasCSSSupports = () => 'supports' in (window.CSS || {}); // use to detect Safari 9+\nconst isIE11 = () => /MSIE|Trident/.test(window.navigator.userAgent);\n\nconst supported = (() => {\n    // Runs immediately and then remembers result for subsequent calls\n    const isSupported =\n        // Has to be a browser\n        isBrowser() &&\n        // Can't run on Opera Mini due to lack of everything\n        !isOperaMini() &&\n        // Require these APIs to feature detect a modern browser\n        hasVisibility() &&\n        hasPromises() &&\n        hasBlobSlice() &&\n        hasCreateObjectURL() &&\n        hasTiming() &&\n        // doesn't need CSSSupports but is a good way to detect Safari 9+ (we do want to support IE11 though)\n        (hasCSSSupports() || isIE11());\n\n    return () => isSupported;\n})();\n\n/**\n * Plugin internal state (over all instances)\n */\nconst state = {\n    // active app instances, used to redraw the apps and to find the later\n    apps: [],\n};\n\n// plugin name\nconst name = 'filepond';\n\n/**\n * Public Plugin methods\n */\nconst fn = () => {};\nlet Status$1 = {};\nlet FileStatus = {};\nlet FileOrigin$1 = {};\nlet OptionTypes = {};\nlet create$f = fn;\nlet destroy = fn;\nlet parse = fn;\nlet find = fn;\nlet registerPlugin = fn;\nlet getOptions$1 = fn;\nlet setOptions$1 = fn;\n\n// if not supported, no API\nif (supported()) {\n    // start painter and fire load event\n    createPainter(\n        () => {\n            state.apps.forEach(app => app._read());\n        },\n        ts => {\n            state.apps.forEach(app => app._write(ts));\n        }\n    );\n\n    // fire loaded event so we know when FilePond is available\n    const dispatch = () => {\n        // let others know we have area ready\n        document.dispatchEvent(\n            new CustomEvent('FilePond:loaded', {\n                detail: {\n                    supported,\n                    create: create$f,\n                    destroy,\n                    parse,\n                    find,\n                    registerPlugin,\n                    setOptions: setOptions$1,\n                },\n            })\n        );\n\n        // clean up event\n        document.removeEventListener('DOMContentLoaded', dispatch);\n    };\n\n    if (document.readyState !== 'loading') {\n        // move to back of execution queue, FilePond should have been exported by then\n        setTimeout(() => dispatch(), 0);\n    } else {\n        document.addEventListener('DOMContentLoaded', dispatch);\n    }\n\n    // updates the OptionTypes object based on the current options\n    const updateOptionTypes = () =>\n        forin(getOptions(), (key, value) => {\n            OptionTypes[key] = value[1];\n        });\n\n    Status$1 = { ...Status };\n    FileOrigin$1 = { ...FileOrigin };\n    FileStatus = { ...ItemStatus };\n\n    OptionTypes = {};\n    updateOptionTypes();\n\n    // create method, creates apps and adds them to the app array\n    create$f = (...args) => {\n        const app = createApp$1(...args);\n        app.on('destroy', destroy);\n        state.apps.push(app);\n        return createAppAPI(app);\n    };\n\n    // destroys apps and removes them from the app array\n    destroy = hook => {\n        // returns true if the app was destroyed successfully\n        const indexToRemove = state.apps.findIndex(app => app.isAttachedTo(hook));\n        if (indexToRemove >= 0) {\n            // remove from apps\n            const app = state.apps.splice(indexToRemove, 1)[0];\n\n            // restore original dom element\n            app.restoreElement();\n\n            return true;\n        }\n\n        return false;\n    };\n\n    // parses the given context for plugins (does not include the context element itself)\n    parse = context => {\n        // get all possible hooks\n        const matchedHooks = Array.from(context.querySelectorAll(`.${name}`));\n\n        // filter out already active hooks\n        const newHooks = matchedHooks.filter(\n            newHook => !state.apps.find(app => app.isAttachedTo(newHook))\n        );\n\n        // create new instance for each hook\n        return newHooks.map(hook => create$f(hook));\n    };\n\n    // returns an app based on the given element hook\n    find = hook => {\n        const app = state.apps.find(app => app.isAttachedTo(hook));\n        if (!app) {\n            return null;\n        }\n        return createAppAPI(app);\n    };\n\n    // adds a plugin extension\n    registerPlugin = (...plugins) => {\n        // register plugins\n        plugins.forEach(createAppPlugin);\n\n        // update OptionTypes, each plugin might have extended the default options\n        updateOptionTypes();\n    };\n\n    getOptions$1 = () => {\n        const opts = {};\n        forin(getOptions(), (key, value) => {\n            opts[key] = value[0];\n        });\n        return opts;\n    };\n\n    setOptions$1 = opts => {\n        if (isObject(opts)) {\n            // update existing plugins\n            state.apps.forEach(app => {\n                app.setOptions(opts);\n            });\n\n            // override defaults\n            setOptions(opts);\n        }\n\n        // return new options\n        return getOptions$1();\n    };\n}\n\nexport {\n    FileOrigin$1 as FileOrigin,\n    FileStatus,\n    OptionTypes,\n    Status$1 as Status,\n    create$f as create,\n    destroy,\n    find,\n    getOptions$1 as getOptions,\n    parse,\n    registerPlugin,\n    setOptions$1 as setOptions,\n    supported,\n};\n"
  },
  {
    "path": "dist/filepond.js",
    "content": "/*!\n * FilePond 4.32.12\n * Licensed under MIT, https://opensource.org/licenses/MIT/\n * Please visit https://pqina.nl/filepond/ for details.\n */\n\n/* eslint-disable */\n\n(function(global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined'\n        ? factory(exports)\n        : typeof define === 'function' && define.amd\n        ? define(['exports'], factory)\n        : ((global = global || self), factory((global.FilePond = {})));\n})(this, function(exports) {\n    'use strict';\n\n    var isNode = function isNode(value) {\n        return value instanceof HTMLElement;\n    };\n\n    var createStore = function createStore(initialState) {\n        var queries = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n        var actions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];\n        // internal state\n        var state = Object.assign({}, initialState);\n\n        // contains all actions for next frame, is clear when actions are requested\n        var actionQueue = [];\n        var dispatchQueue = [];\n\n        // returns a duplicate of the current state\n        var getState = function getState() {\n            return Object.assign({}, state);\n        };\n\n        // returns a duplicate of the actions array and clears the actions array\n        var processActionQueue = function processActionQueue() {\n            // create copy of actions queue\n            var queue = [].concat(actionQueue);\n\n            // clear actions queue (we don't want no double actions)\n            actionQueue.length = 0;\n\n            return queue;\n        };\n\n        // processes actions that might block the main UI thread\n        var processDispatchQueue = function processDispatchQueue() {\n            // create copy of actions queue\n            var queue = [].concat(dispatchQueue);\n\n            // clear actions queue (we don't want no double actions)\n            dispatchQueue.length = 0;\n\n            // now dispatch these actions\n            queue.forEach(function(_ref) {\n                var type = _ref.type,\n                    data = _ref.data;\n                dispatch(type, data);\n            });\n        };\n\n        // adds a new action, calls its handler and\n        var dispatch = function dispatch(type, data, isBlocking) {\n            // is blocking action (should never block if document is hidden)\n            if (isBlocking && !document.hidden) {\n                dispatchQueue.push({ type: type, data: data });\n                return;\n            }\n\n            // if this action has a handler, handle the action\n            if (actionHandlers[type]) {\n                actionHandlers[type](data);\n            }\n\n            // now add action\n            actionQueue.push({\n                type: type,\n                data: data,\n            });\n        };\n\n        var query = function query(str) {\n            var _queryHandles;\n            for (\n                var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1;\n                _key < _len;\n                _key++\n            ) {\n                args[_key - 1] = arguments[_key];\n            }\n            return queryHandles[str]\n                ? (_queryHandles = queryHandles)[str].apply(_queryHandles, args)\n                : null;\n        };\n\n        var api = {\n            getState: getState,\n            processActionQueue: processActionQueue,\n            processDispatchQueue: processDispatchQueue,\n            dispatch: dispatch,\n            query: query,\n        };\n\n        var queryHandles = {};\n        queries.forEach(function(query) {\n            queryHandles = Object.assign({}, query(state), {}, queryHandles);\n        });\n\n        var actionHandlers = {};\n        actions.forEach(function(action) {\n            actionHandlers = Object.assign({}, action(dispatch, query, state), {}, actionHandlers);\n        });\n\n        return api;\n    };\n\n    var defineProperty = function defineProperty(obj, property, definition) {\n        if (typeof definition === 'function') {\n            obj[property] = definition;\n            return;\n        }\n        Object.defineProperty(obj, property, Object.assign({}, definition));\n    };\n\n    var forin = function forin(obj, cb) {\n        for (var key in obj) {\n            if (!obj.hasOwnProperty(key)) {\n                continue;\n            }\n\n            cb(key, obj[key]);\n        }\n    };\n\n    var createObject = function createObject(definition) {\n        var obj = {};\n        forin(definition, function(property) {\n            defineProperty(obj, property, definition[property]);\n        });\n        return obj;\n    };\n\n    var attr = function attr(node, name) {\n        var value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n        if (value === null) {\n            return node.getAttribute(name) || node.hasAttribute(name);\n        }\n        node.setAttribute(name, value);\n    };\n\n    var ns = 'http://www.w3.org/2000/svg';\n    var svgElements = ['svg', 'path']; // only svg elements used\n\n    var isSVGElement = function isSVGElement(tag) {\n        return svgElements.includes(tag);\n    };\n\n    var createElement = function createElement(tag, className) {\n        var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n        if (typeof className === 'object') {\n            attributes = className;\n            className = null;\n        }\n        var element = isSVGElement(tag)\n            ? document.createElementNS(ns, tag)\n            : document.createElement(tag);\n        if (className) {\n            if (isSVGElement(tag)) {\n                attr(element, 'class', className);\n            } else {\n                element.className = className;\n            }\n        }\n        forin(attributes, function(name, value) {\n            attr(element, name, value);\n        });\n        return element;\n    };\n\n    var appendChild = function appendChild(parent) {\n        return function(child, index) {\n            if (typeof index !== 'undefined' && parent.children[index]) {\n                parent.insertBefore(child, parent.children[index]);\n            } else {\n                parent.appendChild(child);\n            }\n        };\n    };\n\n    var appendChildView = function appendChildView(parent, childViews) {\n        return function(view, index) {\n            if (typeof index !== 'undefined') {\n                childViews.splice(index, 0, view);\n            } else {\n                childViews.push(view);\n            }\n\n            return view;\n        };\n    };\n\n    var removeChildView = function removeChildView(parent, childViews) {\n        return function(view) {\n            // remove from child views\n            childViews.splice(childViews.indexOf(view), 1);\n\n            // remove the element\n            if (view.element.parentNode) {\n                parent.removeChild(view.element);\n            }\n\n            return view;\n        };\n    };\n\n    var IS_BROWSER = (function() {\n        return typeof window !== 'undefined' && typeof window.document !== 'undefined';\n    })();\n    var isBrowser = function isBrowser() {\n        return IS_BROWSER;\n    };\n\n    var testElement = isBrowser() ? createElement('svg') : {};\n    var getChildCount =\n        'children' in testElement\n            ? function(el) {\n                  return el.children.length;\n              }\n            : function(el) {\n                  return el.childNodes.length;\n              };\n\n    var getViewRect = function getViewRect(elementRect, childViews, offset, scale) {\n        var left = offset[0] || elementRect.left;\n        var top = offset[1] || elementRect.top;\n        var right = left + elementRect.width;\n        var bottom = top + elementRect.height * (scale[1] || 1);\n\n        var rect = {\n            // the rectangle of the element itself\n            element: Object.assign({}, elementRect),\n\n            // the rectangle of the element expanded to contain its children, does not include any margins\n            inner: {\n                left: elementRect.left,\n                top: elementRect.top,\n                right: elementRect.right,\n                bottom: elementRect.bottom,\n            },\n\n            // the rectangle of the element expanded to contain its children including own margin and child margins\n            // margins will be added after we've recalculated the size\n            outer: {\n                left: left,\n                top: top,\n                right: right,\n                bottom: bottom,\n            },\n        };\n\n        // expand rect to fit all child rectangles\n        childViews\n            .filter(function(childView) {\n                return !childView.isRectIgnored();\n            })\n            .map(function(childView) {\n                return childView.rect;\n            })\n            .forEach(function(childViewRect) {\n                expandRect(rect.inner, Object.assign({}, childViewRect.inner));\n                expandRect(rect.outer, Object.assign({}, childViewRect.outer));\n            });\n\n        // calculate inner width and height\n        calculateRectSize(rect.inner);\n\n        // append additional margin (top and left margins are included in top and left automatically)\n        rect.outer.bottom += rect.element.marginBottom;\n        rect.outer.right += rect.element.marginRight;\n\n        // calculate outer width and height\n        calculateRectSize(rect.outer);\n\n        return rect;\n    };\n\n    var expandRect = function expandRect(parent, child) {\n        // adjust for parent offset\n        child.top += parent.top;\n        child.right += parent.left;\n        child.bottom += parent.top;\n        child.left += parent.left;\n\n        if (child.bottom > parent.bottom) {\n            parent.bottom = child.bottom;\n        }\n\n        if (child.right > parent.right) {\n            parent.right = child.right;\n        }\n    };\n\n    var calculateRectSize = function calculateRectSize(rect) {\n        rect.width = rect.right - rect.left;\n        rect.height = rect.bottom - rect.top;\n    };\n\n    var isNumber = function isNumber(value) {\n        return typeof value === 'number';\n    };\n\n    /**\n     * Determines if position is at destination\n     * @param position\n     * @param destination\n     * @param velocity\n     * @param errorMargin\n     * @returns {boolean}\n     */\n    var thereYet = function thereYet(position, destination, velocity) {\n        var errorMargin = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0.001;\n        return Math.abs(position - destination) < errorMargin && Math.abs(velocity) < errorMargin;\n    };\n\n    /**\n     * Spring animation\n     */\n    var spring =\n        // default options\n        function spring() // method definition\n        {\n            var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n                _ref$stiffness = _ref.stiffness,\n                stiffness = _ref$stiffness === void 0 ? 0.5 : _ref$stiffness,\n                _ref$damping = _ref.damping,\n                damping = _ref$damping === void 0 ? 0.75 : _ref$damping,\n                _ref$mass = _ref.mass,\n                mass = _ref$mass === void 0 ? 10 : _ref$mass;\n            var target = null;\n            var position = null;\n            var velocity = 0;\n            var resting = false;\n\n            // updates spring state\n            var interpolate = function interpolate(ts, skipToEndState) {\n                // in rest, don't animate\n                if (resting) return;\n\n                // need at least a target or position to do springy things\n                if (!(isNumber(target) && isNumber(position))) {\n                    resting = true;\n                    velocity = 0;\n                    return;\n                }\n\n                // calculate spring force\n                var f = -(position - target) * stiffness;\n\n                // update velocity by adding force based on mass\n                velocity += f / mass;\n\n                // update position by adding velocity\n                position += velocity;\n\n                // slow down based on amount of damping\n                velocity *= damping;\n\n                // we've arrived if we're near target and our velocity is near zero\n                if (thereYet(position, target, velocity) || skipToEndState) {\n                    position = target;\n                    velocity = 0;\n                    resting = true;\n\n                    // we done\n                    api.onupdate(position);\n                    api.oncomplete(position);\n                } else {\n                    // progress update\n                    api.onupdate(position);\n                }\n            };\n\n            /**\n             * Set new target value\n             * @param value\n             */\n            var setTarget = function setTarget(value) {\n                // if currently has no position, set target and position to this value\n                if (isNumber(value) && !isNumber(position)) {\n                    position = value;\n                }\n\n                // next target value will not be animated to\n                if (target === null) {\n                    target = value;\n                    position = value;\n                }\n\n                // let start moving to target\n                target = value;\n\n                // already at target\n                if (position === target || typeof target === 'undefined') {\n                    // now resting as target is current position, stop moving\n                    resting = true;\n                    velocity = 0;\n\n                    // done!\n                    api.onupdate(position);\n                    api.oncomplete(position);\n\n                    return;\n                }\n\n                resting = false;\n            };\n\n            // need 'api' to call onupdate callback\n            var api = createObject({\n                interpolate: interpolate,\n                target: {\n                    set: setTarget,\n                    get: function get() {\n                        return target;\n                    },\n                },\n\n                resting: {\n                    get: function get() {\n                        return resting;\n                    },\n                },\n\n                onupdate: function onupdate(value) {},\n                oncomplete: function oncomplete(value) {},\n            });\n\n            return api;\n        };\n\n    var easeLinear = function easeLinear(t) {\n        return t;\n    };\n    var easeInOutQuad = function easeInOutQuad(t) {\n        return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\n    };\n\n    var tween =\n        // default values\n        function tween() // method definition\n        {\n            var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n                _ref$duration = _ref.duration,\n                duration = _ref$duration === void 0 ? 500 : _ref$duration,\n                _ref$easing = _ref.easing,\n                easing = _ref$easing === void 0 ? easeInOutQuad : _ref$easing,\n                _ref$delay = _ref.delay,\n                delay = _ref$delay === void 0 ? 0 : _ref$delay;\n            var start = null;\n            var t;\n            var p;\n            var resting = true;\n            var reverse = false;\n            var target = null;\n\n            var interpolate = function interpolate(ts, skipToEndState) {\n                if (resting || target === null) return;\n\n                if (start === null) {\n                    start = ts;\n                }\n\n                if (ts - start < delay) return;\n\n                t = ts - start - delay;\n\n                if (t >= duration || skipToEndState) {\n                    t = 1;\n                    p = reverse ? 0 : 1;\n                    api.onupdate(p * target);\n                    api.oncomplete(p * target);\n                    resting = true;\n                } else {\n                    p = t / duration;\n                    api.onupdate((t >= 0 ? easing(reverse ? 1 - p : p) : 0) * target);\n                }\n            };\n\n            // need 'api' to call onupdate callback\n            var api = createObject({\n                interpolate: interpolate,\n                target: {\n                    get: function get() {\n                        return reverse ? 0 : target;\n                    },\n                    set: function set(value) {\n                        // is initial value\n                        if (target === null) {\n                            target = value;\n                            api.onupdate(value);\n                            api.oncomplete(value);\n                            return;\n                        }\n\n                        // want to tween to a smaller value and have a current value\n                        if (value < target) {\n                            target = 1;\n                            reverse = true;\n                        } else {\n                            // not tweening to a smaller value\n                            reverse = false;\n                            target = value;\n                        }\n\n                        // let's go!\n                        resting = false;\n                        start = null;\n                    },\n                },\n\n                resting: {\n                    get: function get() {\n                        return resting;\n                    },\n                },\n\n                onupdate: function onupdate(value) {},\n                oncomplete: function oncomplete(value) {},\n            });\n\n            return api;\n        };\n\n    var animator = {\n        spring: spring,\n        tween: tween,\n    };\n\n    /*\n                       { type: 'spring', stiffness: .5, damping: .75, mass: 10 };\n                       { translation: { type: 'spring', ... }, ... }\n                       { translation: { x: { type: 'spring', ... } } }\n                      */\n    var createAnimator = function createAnimator(definition, category, property) {\n        // default is single definition\n        // we check if transform is set, if so, we check if property is set\n        var def =\n            definition[category] && typeof definition[category][property] === 'object'\n                ? definition[category][property]\n                : definition[category] || definition;\n\n        var type = typeof def === 'string' ? def : def.type;\n        var props = typeof def === 'object' ? Object.assign({}, def) : {};\n\n        return animator[type] ? animator[type](props) : null;\n    };\n\n    var addGetSet = function addGetSet(keys, obj, props) {\n        var overwrite = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n        obj = Array.isArray(obj) ? obj : [obj];\n        obj.forEach(function(o) {\n            keys.forEach(function(key) {\n                var name = key;\n                var getter = function getter() {\n                    return props[key];\n                };\n                var setter = function setter(value) {\n                    return (props[key] = value);\n                };\n\n                if (typeof key === 'object') {\n                    name = key.key;\n                    getter = key.getter || getter;\n                    setter = key.setter || setter;\n                }\n\n                if (o[name] && !overwrite) {\n                    return;\n                }\n\n                o[name] = {\n                    get: getter,\n                    set: setter,\n                };\n            });\n        });\n    };\n\n    // add to state,\n    // add getters and setters to internal and external api (if not set)\n    // setup animators\n\n    var animations = function animations(_ref) {\n        var mixinConfig = _ref.mixinConfig,\n            viewProps = _ref.viewProps,\n            viewInternalAPI = _ref.viewInternalAPI,\n            viewExternalAPI = _ref.viewExternalAPI;\n        // initial properties\n        var initialProps = Object.assign({}, viewProps);\n\n        // list of all active animations\n        var animations = [];\n\n        // setup animators\n        forin(mixinConfig, function(property, animation) {\n            var animator = createAnimator(animation);\n            if (!animator) {\n                return;\n            }\n\n            // when the animator updates, update the view state value\n            animator.onupdate = function(value) {\n                viewProps[property] = value;\n            };\n\n            // set animator target\n            animator.target = initialProps[property];\n\n            // when value is set, set the animator target value\n            var prop = {\n                key: property,\n                setter: function setter(value) {\n                    // if already at target, we done!\n                    if (animator.target === value) {\n                        return;\n                    }\n\n                    animator.target = value;\n                },\n                getter: function getter() {\n                    return viewProps[property];\n                },\n            };\n\n            // add getters and setters\n            addGetSet([prop], [viewInternalAPI, viewExternalAPI], viewProps, true);\n\n            // add it to the list for easy updating from the _write method\n            animations.push(animator);\n        });\n\n        // expose internal write api\n        return {\n            write: function write(ts) {\n                var skipToEndState = document.hidden;\n                var resting = true;\n                animations.forEach(function(animation) {\n                    if (!animation.resting) resting = false;\n                    animation.interpolate(ts, skipToEndState);\n                });\n                return resting;\n            },\n            destroy: function destroy() {},\n        };\n    };\n\n    var addEvent = function addEvent(element) {\n        return function(type, fn) {\n            element.addEventListener(type, fn);\n        };\n    };\n\n    var removeEvent = function removeEvent(element) {\n        return function(type, fn) {\n            element.removeEventListener(type, fn);\n        };\n    };\n\n    // mixin\n    var listeners = function listeners(_ref) {\n        var mixinConfig = _ref.mixinConfig,\n            viewProps = _ref.viewProps,\n            viewInternalAPI = _ref.viewInternalAPI,\n            viewExternalAPI = _ref.viewExternalAPI,\n            viewState = _ref.viewState,\n            view = _ref.view;\n        var events = [];\n\n        var add = addEvent(view.element);\n        var remove = removeEvent(view.element);\n\n        viewExternalAPI.on = function(type, fn) {\n            events.push({\n                type: type,\n                fn: fn,\n            });\n\n            add(type, fn);\n        };\n\n        viewExternalAPI.off = function(type, fn) {\n            events.splice(\n                events.findIndex(function(event) {\n                    return event.type === type && event.fn === fn;\n                }),\n                1\n            );\n\n            remove(type, fn);\n        };\n\n        return {\n            write: function write() {\n                // not busy\n                return true;\n            },\n            destroy: function destroy() {\n                events.forEach(function(event) {\n                    remove(event.type, event.fn);\n                });\n            },\n        };\n    };\n\n    // add to external api and link to props\n\n    var apis = function apis(_ref) {\n        var mixinConfig = _ref.mixinConfig,\n            viewProps = _ref.viewProps,\n            viewExternalAPI = _ref.viewExternalAPI;\n        addGetSet(mixinConfig, viewExternalAPI, viewProps);\n    };\n\n    var isDefined = function isDefined(value) {\n        return value != null;\n    };\n\n    // add to state,\n    // add getters and setters to internal and external api (if not set)\n    // set initial state based on props in viewProps\n    // apply as transforms each frame\n\n    var defaults = {\n        opacity: 1,\n        scaleX: 1,\n        scaleY: 1,\n        translateX: 0,\n        translateY: 0,\n        rotateX: 0,\n        rotateY: 0,\n        rotateZ: 0,\n        originX: 0,\n        originY: 0,\n    };\n\n    var styles = function styles(_ref) {\n        var mixinConfig = _ref.mixinConfig,\n            viewProps = _ref.viewProps,\n            viewInternalAPI = _ref.viewInternalAPI,\n            viewExternalAPI = _ref.viewExternalAPI,\n            view = _ref.view;\n        // initial props\n        var initialProps = Object.assign({}, viewProps);\n\n        // current props\n        var currentProps = {};\n\n        // we will add those properties to the external API and link them to the viewState\n        addGetSet(mixinConfig, [viewInternalAPI, viewExternalAPI], viewProps);\n\n        // override rect on internal and external rect getter so it takes in account transforms\n        var getOffset = function getOffset() {\n            return [viewProps['translateX'] || 0, viewProps['translateY'] || 0];\n        };\n\n        var getScale = function getScale() {\n            return [viewProps['scaleX'] || 0, viewProps['scaleY'] || 0];\n        };\n        var getRect = function getRect() {\n            return view.rect\n                ? getViewRect(view.rect, view.childViews, getOffset(), getScale())\n                : null;\n        };\n        viewInternalAPI.rect = { get: getRect };\n        viewExternalAPI.rect = { get: getRect };\n\n        // apply view props\n        mixinConfig.forEach(function(key) {\n            viewProps[key] =\n                typeof initialProps[key] === 'undefined' ? defaults[key] : initialProps[key];\n        });\n\n        // expose api\n        return {\n            write: function write() {\n                // see if props have changed\n                if (!propsHaveChanged(currentProps, viewProps)) {\n                    return;\n                }\n\n                // moves element to correct position on screen\n                applyStyles(view.element, viewProps);\n\n                // store new transforms\n                Object.assign(currentProps, Object.assign({}, viewProps));\n\n                // no longer busy\n                return true;\n            },\n            destroy: function destroy() {},\n        };\n    };\n\n    var propsHaveChanged = function propsHaveChanged(currentProps, newProps) {\n        // different amount of keys\n        if (Object.keys(currentProps).length !== Object.keys(newProps).length) {\n            return true;\n        }\n\n        // lets analyze the individual props\n        for (var prop in newProps) {\n            if (newProps[prop] !== currentProps[prop]) {\n                return true;\n            }\n        }\n\n        return false;\n    };\n\n    var applyStyles = function applyStyles(element, _ref2) {\n        var opacity = _ref2.opacity,\n            perspective = _ref2.perspective,\n            translateX = _ref2.translateX,\n            translateY = _ref2.translateY,\n            scaleX = _ref2.scaleX,\n            scaleY = _ref2.scaleY,\n            rotateX = _ref2.rotateX,\n            rotateY = _ref2.rotateY,\n            rotateZ = _ref2.rotateZ,\n            originX = _ref2.originX,\n            originY = _ref2.originY,\n            width = _ref2.width,\n            height = _ref2.height;\n\n        var transforms = '';\n        var styles = '';\n\n        // handle transform origin\n        if (isDefined(originX) || isDefined(originY)) {\n            styles += 'transform-origin: ' + (originX || 0) + 'px ' + (originY || 0) + 'px;';\n        }\n\n        // transform order is relevant\n        // 0. perspective\n        if (isDefined(perspective)) {\n            transforms += 'perspective(' + perspective + 'px) ';\n        }\n\n        // 1. translate\n        if (isDefined(translateX) || isDefined(translateY)) {\n            transforms +=\n                'translate3d(' + (translateX || 0) + 'px, ' + (translateY || 0) + 'px, 0) ';\n        }\n\n        // 2. scale\n        if (isDefined(scaleX) || isDefined(scaleY)) {\n            transforms +=\n                'scale3d(' +\n                (isDefined(scaleX) ? scaleX : 1) +\n                ', ' +\n                (isDefined(scaleY) ? scaleY : 1) +\n                ', 1) ';\n        }\n\n        // 3. rotate\n        if (isDefined(rotateZ)) {\n            transforms += 'rotateZ(' + rotateZ + 'rad) ';\n        }\n\n        if (isDefined(rotateX)) {\n            transforms += 'rotateX(' + rotateX + 'rad) ';\n        }\n\n        if (isDefined(rotateY)) {\n            transforms += 'rotateY(' + rotateY + 'rad) ';\n        }\n\n        // add transforms\n        if (transforms.length) {\n            styles += 'transform:' + transforms + ';';\n        }\n\n        // add opacity\n        if (isDefined(opacity)) {\n            styles += 'opacity:' + opacity + ';';\n\n            // if we reach zero, we make the element inaccessible\n            if (opacity === 0) {\n                styles += 'visibility:hidden;';\n            }\n\n            // if we're below 100% opacity this element can't be clicked\n            if (opacity < 1) {\n                styles += 'pointer-events:none;';\n            }\n        }\n\n        // add height\n        if (isDefined(height)) {\n            styles += 'height:' + height + 'px;';\n        }\n\n        // add width\n        if (isDefined(width)) {\n            styles += 'width:' + width + 'px;';\n        }\n\n        // apply styles\n        var elementCurrentStyle = element.elementCurrentStyle || '';\n\n        // if new styles does not match current styles, lets update!\n        if (styles.length !== elementCurrentStyle.length || styles !== elementCurrentStyle) {\n            element.style.cssText = styles;\n            // store current styles so we can compare them to new styles later on\n            // _not_ getting the style value is faster\n            element.elementCurrentStyle = styles;\n        }\n    };\n\n    var Mixins = {\n        styles: styles,\n        listeners: listeners,\n        animations: animations,\n        apis: apis,\n    };\n\n    var updateRect = function updateRect() {\n        var rect = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n        var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n        var style = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n        if (!element.layoutCalculated) {\n            rect.paddingTop = parseInt(style.paddingTop, 10) || 0;\n            rect.marginTop = parseInt(style.marginTop, 10) || 0;\n            rect.marginRight = parseInt(style.marginRight, 10) || 0;\n            rect.marginBottom = parseInt(style.marginBottom, 10) || 0;\n            rect.marginLeft = parseInt(style.marginLeft, 10) || 0;\n            element.layoutCalculated = true;\n        }\n\n        rect.left = element.offsetLeft || 0;\n        rect.top = element.offsetTop || 0;\n        rect.width = element.offsetWidth || 0;\n        rect.height = element.offsetHeight || 0;\n\n        rect.right = rect.left + rect.width;\n        rect.bottom = rect.top + rect.height;\n\n        rect.scrollTop = element.scrollTop;\n\n        rect.hidden = element.offsetParent === null;\n\n        return rect;\n    };\n\n    var createView =\n        // default view definition\n        function createView() {\n            var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n                _ref$tag = _ref.tag,\n                tag = _ref$tag === void 0 ? 'div' : _ref$tag,\n                _ref$name = _ref.name,\n                name = _ref$name === void 0 ? null : _ref$name,\n                _ref$attributes = _ref.attributes,\n                attributes = _ref$attributes === void 0 ? {} : _ref$attributes,\n                _ref$read = _ref.read,\n                read = _ref$read === void 0 ? function() {} : _ref$read,\n                _ref$write = _ref.write,\n                write = _ref$write === void 0 ? function() {} : _ref$write,\n                _ref$create = _ref.create,\n                create = _ref$create === void 0 ? function() {} : _ref$create,\n                _ref$destroy = _ref.destroy,\n                destroy = _ref$destroy === void 0 ? function() {} : _ref$destroy,\n                _ref$filterFrameActio = _ref.filterFrameActionsForChild,\n                filterFrameActionsForChild =\n                    _ref$filterFrameActio === void 0\n                        ? function(child, actions) {\n                              return actions;\n                          }\n                        : _ref$filterFrameActio,\n                _ref$didCreateView = _ref.didCreateView,\n                didCreateView = _ref$didCreateView === void 0 ? function() {} : _ref$didCreateView,\n                _ref$didWriteView = _ref.didWriteView,\n                didWriteView = _ref$didWriteView === void 0 ? function() {} : _ref$didWriteView,\n                _ref$ignoreRect = _ref.ignoreRect,\n                ignoreRect = _ref$ignoreRect === void 0 ? false : _ref$ignoreRect,\n                _ref$ignoreRectUpdate = _ref.ignoreRectUpdate,\n                ignoreRectUpdate = _ref$ignoreRectUpdate === void 0 ? false : _ref$ignoreRectUpdate,\n                _ref$mixins = _ref.mixins,\n                mixins = _ref$mixins === void 0 ? [] : _ref$mixins;\n            return function(\n                // each view requires reference to store\n                store\n            ) {\n                var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n                // root element should not be changed\n                var element = createElement(tag, 'filepond--' + name, attributes);\n\n                // style reference should also not be changed\n                var style = window.getComputedStyle(element, null);\n\n                // element rectangle\n                var rect = updateRect();\n                var frameRect = null;\n\n                // rest state\n                var isResting = false;\n\n                // pretty self explanatory\n                var childViews = [];\n\n                // loaded mixins\n                var activeMixins = [];\n\n                // references to created children\n                var ref = {};\n\n                // state used for each instance\n                var state = {};\n\n                // list of writers that will be called to update this view\n                var writers = [\n                    write, // default writer\n                ];\n\n                var readers = [\n                    read, // default reader\n                ];\n\n                var destroyers = [\n                    destroy, // default destroy\n                ];\n\n                // core view methods\n                var getElement = function getElement() {\n                    return element;\n                };\n                var getChildViews = function getChildViews() {\n                    return childViews.concat();\n                };\n                var getReference = function getReference() {\n                    return ref;\n                };\n                var createChildView = function createChildView(store) {\n                    return function(view, props) {\n                        return view(store, props);\n                    };\n                };\n                var getRect = function getRect() {\n                    if (frameRect) {\n                        return frameRect;\n                    }\n                    frameRect = getViewRect(rect, childViews, [0, 0], [1, 1]);\n                    return frameRect;\n                };\n                var getStyle = function getStyle() {\n                    return style;\n                };\n\n                /**\n                 * Read data from DOM\n                 * @private\n                 */\n                var _read = function _read() {\n                    frameRect = null;\n\n                    // read child views\n                    childViews.forEach(function(child) {\n                        return child._read();\n                    });\n\n                    var shouldUpdate = !(ignoreRectUpdate && rect.width && rect.height);\n                    if (shouldUpdate) {\n                        updateRect(rect, element, style);\n                    }\n\n                    // readers\n                    var api = { root: internalAPI, props: props, rect: rect };\n                    readers.forEach(function(reader) {\n                        return reader(api);\n                    });\n                };\n\n                /**\n                 * Write data to DOM\n                 * @private\n                 */\n                var _write = function _write(ts, frameActions, shouldOptimize) {\n                    // if no actions, we assume that the view is resting\n                    var resting = frameActions.length === 0;\n\n                    // writers\n                    writers.forEach(function(writer) {\n                        var writerResting = writer({\n                            props: props,\n                            root: internalAPI,\n                            actions: frameActions,\n                            timestamp: ts,\n                            shouldOptimize: shouldOptimize,\n                        });\n\n                        if (writerResting === false) {\n                            resting = false;\n                        }\n                    });\n\n                    // run mixins\n                    activeMixins.forEach(function(mixin) {\n                        // if one of the mixins is still busy after write operation, we are not resting\n                        var mixinResting = mixin.write(ts);\n                        if (mixinResting === false) {\n                            resting = false;\n                        }\n                    });\n\n                    // updates child views that are currently attached to the DOM\n                    childViews\n                        .filter(function(child) {\n                            return !!child.element.parentNode;\n                        })\n                        .forEach(function(child) {\n                            // if a child view is not resting, we are not resting\n                            var childResting = child._write(\n                                ts,\n                                filterFrameActionsForChild(child, frameActions),\n                                shouldOptimize\n                            );\n\n                            if (!childResting) {\n                                resting = false;\n                            }\n                        });\n\n                    // append new elements to DOM and update those\n                    childViews\n                        //.filter(child => !child.element.parentNode)\n                        .forEach(function(child, index) {\n                            // skip\n                            if (child.element.parentNode) {\n                                return;\n                            }\n\n                            // append to DOM\n                            internalAPI.appendChild(child.element, index);\n\n                            // call read (need to know the size of these elements)\n                            child._read();\n\n                            // re-call write\n                            child._write(\n                                ts,\n                                filterFrameActionsForChild(child, frameActions),\n                                shouldOptimize\n                            );\n\n                            // we just added somthing to the dom, no rest\n                            resting = false;\n                        });\n\n                    // update resting state\n                    isResting = resting;\n\n                    didWriteView({\n                        props: props,\n                        root: internalAPI,\n                        actions: frameActions,\n                        timestamp: ts,\n                    });\n\n                    // let parent know if we are resting\n                    return resting;\n                };\n\n                var _destroy = function _destroy() {\n                    activeMixins.forEach(function(mixin) {\n                        return mixin.destroy();\n                    });\n                    destroyers.forEach(function(destroyer) {\n                        destroyer({ root: internalAPI, props: props });\n                    });\n                    childViews.forEach(function(child) {\n                        return child._destroy();\n                    });\n                };\n\n                // sharedAPI\n                var sharedAPIDefinition = {\n                    element: {\n                        get: getElement,\n                    },\n\n                    style: {\n                        get: getStyle,\n                    },\n\n                    childViews: {\n                        get: getChildViews,\n                    },\n                };\n\n                // private API definition\n                var internalAPIDefinition = Object.assign({}, sharedAPIDefinition, {\n                    rect: {\n                        get: getRect,\n                    },\n\n                    // access to custom children references\n                    ref: {\n                        get: getReference,\n                    },\n\n                    // dom modifiers\n                    is: function is(needle) {\n                        return name === needle;\n                    },\n                    appendChild: appendChild(element),\n                    createChildView: createChildView(store),\n                    linkView: function linkView(view) {\n                        childViews.push(view);\n                        return view;\n                    },\n                    unlinkView: function unlinkView(view) {\n                        childViews.splice(childViews.indexOf(view), 1);\n                    },\n                    appendChildView: appendChildView(element, childViews),\n                    removeChildView: removeChildView(element, childViews),\n                    registerWriter: function registerWriter(writer) {\n                        return writers.push(writer);\n                    },\n                    registerReader: function registerReader(reader) {\n                        return readers.push(reader);\n                    },\n                    registerDestroyer: function registerDestroyer(destroyer) {\n                        return destroyers.push(destroyer);\n                    },\n                    invalidateLayout: function invalidateLayout() {\n                        return (element.layoutCalculated = false);\n                    },\n\n                    // access to data store\n                    dispatch: store.dispatch,\n                    query: store.query,\n                });\n\n                // public view API methods\n                var externalAPIDefinition = {\n                    element: {\n                        get: getElement,\n                    },\n\n                    childViews: {\n                        get: getChildViews,\n                    },\n\n                    rect: {\n                        get: getRect,\n                    },\n\n                    resting: {\n                        get: function get() {\n                            return isResting;\n                        },\n                    },\n\n                    isRectIgnored: function isRectIgnored() {\n                        return ignoreRect;\n                    },\n                    _read: _read,\n                    _write: _write,\n                    _destroy: _destroy,\n                };\n\n                // mixin API methods\n                var mixinAPIDefinition = Object.assign({}, sharedAPIDefinition, {\n                    rect: {\n                        get: function get() {\n                            return rect;\n                        },\n                    },\n                });\n\n                // add mixin functionality\n                Object.keys(mixins)\n                    .sort(function(a, b) {\n                        // move styles to the back of the mixin list (so adjustments of other mixins are applied to the props correctly)\n                        if (a === 'styles') {\n                            return 1;\n                        } else if (b === 'styles') {\n                            return -1;\n                        }\n                        return 0;\n                    })\n                    .forEach(function(key) {\n                        var mixinAPI = Mixins[key]({\n                            mixinConfig: mixins[key],\n                            viewProps: props,\n                            viewState: state,\n                            viewInternalAPI: internalAPIDefinition,\n                            viewExternalAPI: externalAPIDefinition,\n                            view: createObject(mixinAPIDefinition),\n                        });\n\n                        if (mixinAPI) {\n                            activeMixins.push(mixinAPI);\n                        }\n                    });\n\n                // construct private api\n                var internalAPI = createObject(internalAPIDefinition);\n\n                // create the view\n                create({\n                    root: internalAPI,\n                    props: props,\n                });\n\n                // append created child views to root node\n                var childCount = getChildCount(element); // need to know the current child count so appending happens in correct order\n                childViews.forEach(function(child, index) {\n                    internalAPI.appendChild(child.element, childCount + index);\n                });\n\n                // call did create\n                didCreateView(internalAPI);\n\n                // expose public api\n                return createObject(externalAPIDefinition);\n            };\n        };\n\n    var createPainter = function createPainter(read, write) {\n        var fps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 60;\n\n        var name = '__framePainter';\n\n        // set global painter\n        if (window[name]) {\n            window[name].readers.push(read);\n            window[name].writers.push(write);\n            return;\n        }\n\n        window[name] = {\n            readers: [read],\n            writers: [write],\n        };\n\n        var painter = window[name];\n\n        var interval = 1000 / fps;\n        var last = null;\n        var id = null;\n        var requestTick = null;\n        var cancelTick = null;\n\n        var setTimerType = function setTimerType() {\n            if (document.hidden) {\n                requestTick = function requestTick() {\n                    return window.setTimeout(function() {\n                        return tick(performance.now());\n                    }, interval);\n                };\n                cancelTick = function cancelTick() {\n                    return window.clearTimeout(id);\n                };\n            } else {\n                requestTick = function requestTick() {\n                    return window.requestAnimationFrame(tick);\n                };\n                cancelTick = function cancelTick() {\n                    return window.cancelAnimationFrame(id);\n                };\n            }\n        };\n\n        document.addEventListener('visibilitychange', function() {\n            if (cancelTick) cancelTick();\n            setTimerType();\n            tick(performance.now());\n        });\n\n        var tick = function tick(ts) {\n            // queue next tick\n            id = requestTick(tick);\n\n            // limit fps\n            if (!last) {\n                last = ts;\n            }\n\n            var delta = ts - last;\n\n            if (delta <= interval) {\n                // skip frame\n                return;\n            }\n\n            // align next frame\n            last = ts - (delta % interval);\n\n            // update view\n            painter.readers.forEach(function(read) {\n                return read();\n            });\n            painter.writers.forEach(function(write) {\n                return write(ts);\n            });\n        };\n\n        setTimerType();\n        tick(performance.now());\n\n        return {\n            pause: function pause() {\n                cancelTick(id);\n            },\n        };\n    };\n\n    var createRoute = function createRoute(routes, fn) {\n        return function(_ref) {\n            var root = _ref.root,\n                props = _ref.props,\n                _ref$actions = _ref.actions,\n                actions = _ref$actions === void 0 ? [] : _ref$actions,\n                timestamp = _ref.timestamp,\n                shouldOptimize = _ref.shouldOptimize;\n            actions\n                .filter(function(action) {\n                    return routes[action.type];\n                })\n                .forEach(function(action) {\n                    return routes[action.type]({\n                        root: root,\n                        props: props,\n                        action: action.data,\n                        timestamp: timestamp,\n                        shouldOptimize: shouldOptimize,\n                    });\n                });\n\n            if (fn) {\n                fn({\n                    root: root,\n                    props: props,\n                    actions: actions,\n                    timestamp: timestamp,\n                    shouldOptimize: shouldOptimize,\n                });\n            }\n        };\n    };\n\n    var insertBefore = function insertBefore(newNode, referenceNode) {\n        return referenceNode.parentNode.insertBefore(newNode, referenceNode);\n    };\n\n    var insertAfter = function insertAfter(newNode, referenceNode) {\n        return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);\n    };\n\n    var isArray = function isArray(value) {\n        return Array.isArray(value);\n    };\n\n    var isEmpty = function isEmpty(value) {\n        return value == null;\n    };\n\n    var trim = function trim(str) {\n        return str.trim();\n    };\n\n    var toString = function toString(value) {\n        return '' + value;\n    };\n\n    var toArray = function toArray(value) {\n        var splitter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ',';\n        if (isEmpty(value)) {\n            return [];\n        }\n        if (isArray(value)) {\n            return value;\n        }\n        return toString(value)\n            .split(splitter)\n            .map(trim)\n            .filter(function(str) {\n                return str.length;\n            });\n    };\n\n    var isBoolean = function isBoolean(value) {\n        return typeof value === 'boolean';\n    };\n\n    var toBoolean = function toBoolean(value) {\n        return isBoolean(value) ? value : value === 'true';\n    };\n\n    var isString = function isString(value) {\n        return typeof value === 'string';\n    };\n\n    var toNumber = function toNumber(value) {\n        return isNumber(value)\n            ? value\n            : isString(value)\n            ? toString(value).replace(/[a-z]+/gi, '')\n            : 0;\n    };\n\n    var toInt = function toInt(value) {\n        return parseInt(toNumber(value), 10);\n    };\n\n    var toFloat = function toFloat(value) {\n        return parseFloat(toNumber(value));\n    };\n\n    var isInt = function isInt(value) {\n        return isNumber(value) && isFinite(value) && Math.floor(value) === value;\n    };\n\n    var toBytes = function toBytes(value) {\n        var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;\n        // is in bytes\n        if (isInt(value)) {\n            return value;\n        }\n\n        // is natural file size\n        var naturalFileSize = toString(value).trim();\n\n        // if is value in megabytes\n        if (/MB$/i.test(naturalFileSize)) {\n            naturalFileSize = naturalFileSize.replace(/MB$i/, '').trim();\n            return toInt(naturalFileSize) * base * base;\n        }\n\n        // if is value in kilobytes\n        if (/KB/i.test(naturalFileSize)) {\n            naturalFileSize = naturalFileSize.replace(/KB$i/, '').trim();\n            return toInt(naturalFileSize) * base;\n        }\n\n        return toInt(naturalFileSize);\n    };\n\n    var isFunction = function isFunction(value) {\n        return typeof value === 'function';\n    };\n\n    var toFunctionReference = function toFunctionReference(string) {\n        var ref = self;\n        var levels = string.split('.');\n        var level = null;\n        while ((level = levels.shift())) {\n            ref = ref[level];\n            if (!ref) {\n                return null;\n            }\n        }\n        return ref;\n    };\n\n    var methods = {\n        process: 'POST',\n        patch: 'PATCH',\n        revert: 'DELETE',\n        fetch: 'GET',\n        restore: 'GET',\n        load: 'GET',\n    };\n\n    var createServerAPI = function createServerAPI(outline) {\n        var api = {};\n\n        api.url = isString(outline) ? outline : outline.url || '';\n        api.timeout = outline.timeout ? parseInt(outline.timeout, 10) : 0;\n        api.headers = outline.headers ? outline.headers : {};\n\n        forin(methods, function(key) {\n            api[key] = createAction(key, outline[key], methods[key], api.timeout, api.headers);\n        });\n\n        // remove process if no url or process on outline\n        api.process = outline.process || isString(outline) || outline.url ? api.process : null;\n\n        // special treatment for remove\n        api.remove = outline.remove || null;\n\n        // remove generic headers from api object\n        delete api.headers;\n\n        return api;\n    };\n\n    var createAction = function createAction(name, outline, method, timeout, headers) {\n        // is explicitely set to null so disable\n        if (outline === null) {\n            return null;\n        }\n\n        // if is custom function, done! Dev handles everything.\n        if (typeof outline === 'function') {\n            return outline;\n        }\n\n        // build action object\n        var action = {\n            url: method === 'GET' || method === 'PATCH' ? '?' + name + '=' : '',\n            method: method,\n            headers: headers,\n            withCredentials: false,\n            timeout: timeout,\n            onload: null,\n            ondata: null,\n            onerror: null,\n        };\n\n        // is a single url\n        if (isString(outline)) {\n            action.url = outline;\n            return action;\n        }\n\n        // overwrite\n        Object.assign(action, outline);\n\n        // see if should reformat headers;\n        if (isString(action.headers)) {\n            var parts = action.headers.split(/:(.+)/);\n            action.headers = {\n                header: parts[0],\n                value: parts[1],\n            };\n        }\n\n        // if is bool withCredentials\n        action.withCredentials = toBoolean(action.withCredentials);\n\n        return action;\n    };\n\n    var toServerAPI = function toServerAPI(value) {\n        return createServerAPI(value);\n    };\n\n    var isNull = function isNull(value) {\n        return value === null;\n    };\n\n    var isObject = function isObject(value) {\n        return typeof value === 'object' && value !== null;\n    };\n\n    var isAPI = function isAPI(value) {\n        return (\n            isObject(value) &&\n            isString(value.url) &&\n            isObject(value.process) &&\n            isObject(value.revert) &&\n            isObject(value.restore) &&\n            isObject(value.fetch)\n        );\n    };\n\n    var getType = function getType(value) {\n        if (isArray(value)) {\n            return 'array';\n        }\n\n        if (isNull(value)) {\n            return 'null';\n        }\n\n        if (isInt(value)) {\n            return 'int';\n        }\n\n        if (/^[0-9]+ ?(?:GB|MB|KB)$/gi.test(value)) {\n            return 'bytes';\n        }\n\n        if (isAPI(value)) {\n            return 'api';\n        }\n\n        return typeof value;\n    };\n\n    var replaceSingleQuotes = function replaceSingleQuotes(str) {\n        return str\n            .replace(/{\\s*'/g, '{\"')\n            .replace(/'\\s*}/g, '\"}')\n            .replace(/'\\s*:/g, '\":')\n            .replace(/:\\s*'/g, ':\"')\n            .replace(/,\\s*'/g, ',\"')\n            .replace(/'\\s*,/g, '\",');\n    };\n\n    var conversionTable = {\n        array: toArray,\n        boolean: toBoolean,\n        int: function int(value) {\n            return getType(value) === 'bytes' ? toBytes(value) : toInt(value);\n        },\n        number: toFloat,\n        float: toFloat,\n        bytes: toBytes,\n        string: function string(value) {\n            return isFunction(value) ? value : toString(value);\n        },\n        function: function _function(value) {\n            return toFunctionReference(value);\n        },\n        serverapi: toServerAPI,\n        object: function object(value) {\n            try {\n                return JSON.parse(replaceSingleQuotes(value));\n            } catch (e) {\n                return null;\n            }\n        },\n    };\n\n    var convertTo = function convertTo(value, type) {\n        return conversionTable[type](value);\n    };\n\n    var getValueByType = function getValueByType(newValue, defaultValue, valueType) {\n        // can always assign default value\n        if (newValue === defaultValue) {\n            return newValue;\n        }\n\n        // get the type of the new value\n        var newValueType = getType(newValue);\n\n        // is valid type?\n        if (newValueType !== valueType) {\n            // is string input, let's attempt to convert\n            var convertedValue = convertTo(newValue, valueType);\n\n            // what is the type now\n            newValueType = getType(convertedValue);\n\n            // no valid conversions found\n            if (convertedValue === null) {\n                throw 'Trying to assign value with incorrect type to \"' +\n                    option +\n                    '\", allowed type: \"' +\n                    valueType +\n                    '\"';\n            } else {\n                newValue = convertedValue;\n            }\n        }\n\n        // assign new value\n        return newValue;\n    };\n\n    var createOption = function createOption(defaultValue, valueType) {\n        var currentValue = defaultValue;\n        return {\n            enumerable: true,\n            get: function get() {\n                return currentValue;\n            },\n            set: function set(newValue) {\n                currentValue = getValueByType(newValue, defaultValue, valueType);\n            },\n        };\n    };\n\n    var createOptions = function createOptions(options) {\n        var obj = {};\n        forin(options, function(prop) {\n            var optionDefinition = options[prop];\n            obj[prop] = createOption(optionDefinition[0], optionDefinition[1]);\n        });\n        return createObject(obj);\n    };\n\n    var createInitialState = function createInitialState(options) {\n        return {\n            // model\n            items: [],\n\n            // timeout used for calling update items\n            listUpdateTimeout: null,\n\n            // timeout used for stacking metadata updates\n            itemUpdateTimeout: null,\n\n            // queue of items waiting to be processed\n            processingQueue: [],\n\n            // options\n            options: createOptions(options),\n        };\n    };\n\n    var fromCamels = function fromCamels(string) {\n        var separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '-';\n        return string\n            .split(/(?=[A-Z])/)\n            .map(function(part) {\n                return part.toLowerCase();\n            })\n            .join(separator);\n    };\n\n    var createOptionAPI = function createOptionAPI(store, options) {\n        var obj = {};\n        forin(options, function(key) {\n            obj[key] = {\n                get: function get() {\n                    return store.getState().options[key];\n                },\n                set: function set(value) {\n                    store.dispatch('SET_' + fromCamels(key, '_').toUpperCase(), {\n                        value: value,\n                    });\n                },\n            };\n        });\n        return obj;\n    };\n\n    var createOptionActions = function createOptionActions(options) {\n        return function(dispatch, query, state) {\n            var obj = {};\n            forin(options, function(key) {\n                var name = fromCamels(key, '_').toUpperCase();\n\n                obj['SET_' + name] = function(action) {\n                    try {\n                        state.options[key] = action.value;\n                    } catch (e) {} // nope, failed\n\n                    // we successfully set the value of this option\n                    dispatch('DID_SET_' + name, { value: state.options[key] });\n                };\n            });\n            return obj;\n        };\n    };\n\n    var createOptionQueries = function createOptionQueries(options) {\n        return function(state) {\n            var obj = {};\n            forin(options, function(key) {\n                obj['GET_' + fromCamels(key, '_').toUpperCase()] = function(action) {\n                    return state.options[key];\n                };\n            });\n            return obj;\n        };\n    };\n\n    var InteractionMethod = {\n        API: 1,\n        DROP: 2,\n        BROWSE: 3,\n        PASTE: 4,\n        NONE: 5,\n    };\n\n    var getUniqueId = function getUniqueId() {\n        return Math.random()\n            .toString(36)\n            .substring(2, 11);\n    };\n\n    function _typeof(obj) {\n        if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') {\n            _typeof = function(obj) {\n                return typeof obj;\n            };\n        } else {\n            _typeof = function(obj) {\n                return obj &&\n                    typeof Symbol === 'function' &&\n                    obj.constructor === Symbol &&\n                    obj !== Symbol.prototype\n                    ? 'symbol'\n                    : typeof obj;\n            };\n        }\n\n        return _typeof(obj);\n    }\n\n    var REACT_ELEMENT_TYPE;\n\n    function _jsx(type, props, key, children) {\n        if (!REACT_ELEMENT_TYPE) {\n            REACT_ELEMENT_TYPE =\n                (typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element')) ||\n                0xeac7;\n        }\n\n        var defaultProps = type && type.defaultProps;\n        var childrenLength = arguments.length - 3;\n\n        if (!props && childrenLength !== 0) {\n            props = {\n                children: void 0,\n            };\n        }\n\n        if (props && defaultProps) {\n            for (var propName in defaultProps) {\n                if (props[propName] === void 0) {\n                    props[propName] = defaultProps[propName];\n                }\n            }\n        } else if (!props) {\n            props = defaultProps || {};\n        }\n\n        if (childrenLength === 1) {\n            props.children = children;\n        } else if (childrenLength > 1) {\n            var childArray = new Array(childrenLength);\n\n            for (var i = 0; i < childrenLength; i++) {\n                childArray[i] = arguments[i + 3];\n            }\n\n            props.children = childArray;\n        }\n\n        return {\n            $$typeof: REACT_ELEMENT_TYPE,\n            type: type,\n            key: key === undefined ? null : '' + key,\n            ref: null,\n            props: props,\n            _owner: null,\n        };\n    }\n\n    function _asyncIterator(iterable) {\n        var method;\n\n        if (typeof Symbol !== 'undefined') {\n            if (Symbol.asyncIterator) {\n                method = iterable[Symbol.asyncIterator];\n                if (method != null) return method.call(iterable);\n            }\n\n            if (Symbol.iterator) {\n                method = iterable[Symbol.iterator];\n                if (method != null) return method.call(iterable);\n            }\n        }\n\n        throw new TypeError('Object is not async iterable');\n    }\n\n    function _AwaitValue(value) {\n        this.wrapped = value;\n    }\n\n    function _AsyncGenerator(gen) {\n        var front, back;\n\n        function send(key, arg) {\n            return new Promise(function(resolve, reject) {\n                var request = {\n                    key: key,\n                    arg: arg,\n                    resolve: resolve,\n                    reject: reject,\n                    next: null,\n                };\n\n                if (back) {\n                    back = back.next = request;\n                } else {\n                    front = back = request;\n                    resume(key, arg);\n                }\n            });\n        }\n\n        function resume(key, arg) {\n            try {\n                var result = gen[key](arg);\n                var value = result.value;\n                var wrappedAwait = value instanceof _AwaitValue;\n                Promise.resolve(wrappedAwait ? value.wrapped : value).then(\n                    function(arg) {\n                        if (wrappedAwait) {\n                            resume('next', arg);\n                            return;\n                        }\n\n                        settle(result.done ? 'return' : 'normal', arg);\n                    },\n                    function(err) {\n                        resume('throw', err);\n                    }\n                );\n            } catch (err) {\n                settle('throw', err);\n            }\n        }\n\n        function settle(type, value) {\n            switch (type) {\n                case 'return':\n                    front.resolve({\n                        value: value,\n                        done: true,\n                    });\n                    break;\n\n                case 'throw':\n                    front.reject(value);\n                    break;\n\n                default:\n                    front.resolve({\n                        value: value,\n                        done: false,\n                    });\n                    break;\n            }\n\n            front = front.next;\n\n            if (front) {\n                resume(front.key, front.arg);\n            } else {\n                back = null;\n            }\n        }\n\n        this._invoke = send;\n\n        if (typeof gen.return !== 'function') {\n            this.return = undefined;\n        }\n    }\n\n    if (typeof Symbol === 'function' && Symbol.asyncIterator) {\n        _AsyncGenerator.prototype[Symbol.asyncIterator] = function() {\n            return this;\n        };\n    }\n\n    _AsyncGenerator.prototype.next = function(arg) {\n        return this._invoke('next', arg);\n    };\n\n    _AsyncGenerator.prototype.throw = function(arg) {\n        return this._invoke('throw', arg);\n    };\n\n    _AsyncGenerator.prototype.return = function(arg) {\n        return this._invoke('return', arg);\n    };\n\n    function _wrapAsyncGenerator(fn) {\n        return function() {\n            return new _AsyncGenerator(fn.apply(this, arguments));\n        };\n    }\n\n    function _awaitAsyncGenerator(value) {\n        return new _AwaitValue(value);\n    }\n\n    function _asyncGeneratorDelegate(inner, awaitWrap) {\n        var iter = {},\n            waiting = false;\n\n        function pump(key, value) {\n            waiting = true;\n            value = new Promise(function(resolve) {\n                resolve(inner[key](value));\n            });\n            return {\n                done: false,\n                value: awaitWrap(value),\n            };\n        }\n\n        if (typeof Symbol === 'function' && Symbol.iterator) {\n            iter[Symbol.iterator] = function() {\n                return this;\n            };\n        }\n\n        iter.next = function(value) {\n            if (waiting) {\n                waiting = false;\n                return value;\n            }\n\n            return pump('next', value);\n        };\n\n        if (typeof inner.throw === 'function') {\n            iter.throw = function(value) {\n                if (waiting) {\n                    waiting = false;\n                    throw value;\n                }\n\n                return pump('throw', value);\n            };\n        }\n\n        if (typeof inner.return === 'function') {\n            iter.return = function(value) {\n                return pump('return', value);\n            };\n        }\n\n        return iter;\n    }\n\n    function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n        try {\n            var info = gen[key](arg);\n            var value = info.value;\n        } catch (error) {\n            reject(error);\n            return;\n        }\n\n        if (info.done) {\n            resolve(value);\n        } else {\n            Promise.resolve(value).then(_next, _throw);\n        }\n    }\n\n    function _asyncToGenerator(fn) {\n        return function() {\n            var self = this,\n                args = arguments;\n            return new Promise(function(resolve, reject) {\n                var gen = fn.apply(self, args);\n\n                function _next(value) {\n                    asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);\n                }\n\n                function _throw(err) {\n                    asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);\n                }\n\n                _next(undefined);\n            });\n        };\n    }\n\n    function _classCallCheck(instance, Constructor) {\n        if (!(instance instanceof Constructor)) {\n            throw new TypeError('Cannot call a class as a function');\n        }\n    }\n\n    function _defineProperties(target, props) {\n        for (var i = 0; i < props.length; i++) {\n            var descriptor = props[i];\n            descriptor.enumerable = descriptor.enumerable || false;\n            descriptor.configurable = true;\n            if ('value' in descriptor) descriptor.writable = true;\n            Object.defineProperty(target, descriptor.key, descriptor);\n        }\n    }\n\n    function _createClass(Constructor, protoProps, staticProps) {\n        if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n        if (staticProps) _defineProperties(Constructor, staticProps);\n        return Constructor;\n    }\n\n    function _defineEnumerableProperties(obj, descs) {\n        for (var key in descs) {\n            var desc = descs[key];\n            desc.configurable = desc.enumerable = true;\n            if ('value' in desc) desc.writable = true;\n            Object.defineProperty(obj, key, desc);\n        }\n\n        if (Object.getOwnPropertySymbols) {\n            var objectSymbols = Object.getOwnPropertySymbols(descs);\n\n            for (var i = 0; i < objectSymbols.length; i++) {\n                var sym = objectSymbols[i];\n                var desc = descs[sym];\n                desc.configurable = desc.enumerable = true;\n                if ('value' in desc) desc.writable = true;\n                Object.defineProperty(obj, sym, desc);\n            }\n        }\n\n        return obj;\n    }\n\n    function _defaults(obj, defaults) {\n        var keys = Object.getOwnPropertyNames(defaults);\n\n        for (var i = 0; i < keys.length; i++) {\n            var key = keys[i];\n            var value = Object.getOwnPropertyDescriptor(defaults, key);\n\n            if (value && value.configurable && obj[key] === undefined) {\n                Object.defineProperty(obj, key, value);\n            }\n        }\n\n        return obj;\n    }\n\n    function _defineProperty(obj, key, value) {\n        if (key in obj) {\n            Object.defineProperty(obj, key, {\n                value: value,\n                enumerable: true,\n                configurable: true,\n                writable: true,\n            });\n        } else {\n            obj[key] = value;\n        }\n\n        return obj;\n    }\n\n    function _extends() {\n        _extends =\n            Object.assign ||\n            function(target) {\n                for (var i = 1; i < arguments.length; i++) {\n                    var source = arguments[i];\n\n                    for (var key in source) {\n                        if (Object.prototype.hasOwnProperty.call(source, key)) {\n                            target[key] = source[key];\n                        }\n                    }\n                }\n\n                return target;\n            };\n\n        return _extends.apply(this, arguments);\n    }\n\n    function _objectSpread(target) {\n        for (var i = 1; i < arguments.length; i++) {\n            var source = arguments[i] != null ? arguments[i] : {};\n            var ownKeys = Object.keys(source);\n\n            if (typeof Object.getOwnPropertySymbols === 'function') {\n                ownKeys = ownKeys.concat(\n                    Object.getOwnPropertySymbols(source).filter(function(sym) {\n                        return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n                    })\n                );\n            }\n\n            ownKeys.forEach(function(key) {\n                _defineProperty(target, key, source[key]);\n            });\n        }\n\n        return target;\n    }\n\n    function ownKeys(object, enumerableOnly) {\n        var keys = Object.keys(object);\n\n        if (Object.getOwnPropertySymbols) {\n            var symbols = Object.getOwnPropertySymbols(object);\n            if (enumerableOnly)\n                symbols = symbols.filter(function(sym) {\n                    return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n                });\n            keys.push.apply(keys, symbols);\n        }\n\n        return keys;\n    }\n\n    function _objectSpread2(target) {\n        for (var i = 1; i < arguments.length; i++) {\n            var source = arguments[i] != null ? arguments[i] : {};\n\n            if (i % 2) {\n                ownKeys(source, true).forEach(function(key) {\n                    _defineProperty(target, key, source[key]);\n                });\n            } else if (Object.getOwnPropertyDescriptors) {\n                Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));\n            } else {\n                ownKeys(source).forEach(function(key) {\n                    Object.defineProperty(\n                        target,\n                        key,\n                        Object.getOwnPropertyDescriptor(source, key)\n                    );\n                });\n            }\n        }\n\n        return target;\n    }\n\n    function _inherits(subClass, superClass) {\n        if (typeof superClass !== 'function' && superClass !== null) {\n            throw new TypeError('Super expression must either be null or a function');\n        }\n\n        subClass.prototype = Object.create(superClass && superClass.prototype, {\n            constructor: {\n                value: subClass,\n                writable: true,\n                configurable: true,\n            },\n        });\n        if (superClass) _setPrototypeOf(subClass, superClass);\n    }\n\n    function _inheritsLoose(subClass, superClass) {\n        subClass.prototype = Object.create(superClass.prototype);\n        subClass.prototype.constructor = subClass;\n        subClass.__proto__ = superClass;\n    }\n\n    function _getPrototypeOf(o) {\n        _getPrototypeOf = Object.setPrototypeOf\n            ? Object.getPrototypeOf\n            : function _getPrototypeOf(o) {\n                  return o.__proto__ || Object.getPrototypeOf(o);\n              };\n        return _getPrototypeOf(o);\n    }\n\n    function _setPrototypeOf(o, p) {\n        _setPrototypeOf =\n            Object.setPrototypeOf ||\n            function _setPrototypeOf(o, p) {\n                o.__proto__ = p;\n                return o;\n            };\n\n        return _setPrototypeOf(o, p);\n    }\n\n    function isNativeReflectConstruct() {\n        if (typeof Reflect === 'undefined' || !Reflect.construct) return false;\n        if (Reflect.construct.sham) return false;\n        if (typeof Proxy === 'function') return true;\n\n        try {\n            Date.prototype.toString.call(Reflect.construct(Date, [], function() {}));\n            return true;\n        } catch (e) {\n            return false;\n        }\n    }\n\n    function _construct(Parent, args, Class) {\n        if (isNativeReflectConstruct()) {\n            _construct = Reflect.construct;\n        } else {\n            _construct = function _construct(Parent, args, Class) {\n                var a = [null];\n                a.push.apply(a, args);\n                var Constructor = Function.bind.apply(Parent, a);\n                var instance = new Constructor();\n                if (Class) _setPrototypeOf(instance, Class.prototype);\n                return instance;\n            };\n        }\n\n        return _construct.apply(null, arguments);\n    }\n\n    function _isNativeFunction(fn) {\n        return Function.toString.call(fn).indexOf('[native code]') !== -1;\n    }\n\n    function _wrapNativeSuper(Class) {\n        var _cache = typeof Map === 'function' ? new Map() : undefined;\n\n        _wrapNativeSuper = function _wrapNativeSuper(Class) {\n            if (Class === null || !_isNativeFunction(Class)) return Class;\n\n            if (typeof Class !== 'function') {\n                throw new TypeError('Super expression must either be null or a function');\n            }\n\n            if (typeof _cache !== 'undefined') {\n                if (_cache.has(Class)) return _cache.get(Class);\n\n                _cache.set(Class, Wrapper);\n            }\n\n            function Wrapper() {\n                return _construct(Class, arguments, _getPrototypeOf(this).constructor);\n            }\n\n            Wrapper.prototype = Object.create(Class.prototype, {\n                constructor: {\n                    value: Wrapper,\n                    enumerable: false,\n                    writable: true,\n                    configurable: true,\n                },\n            });\n            return _setPrototypeOf(Wrapper, Class);\n        };\n\n        return _wrapNativeSuper(Class);\n    }\n\n    function _instanceof(left, right) {\n        if (right != null && typeof Symbol !== 'undefined' && right[Symbol.hasInstance]) {\n            return !!right[Symbol.hasInstance](left);\n        } else {\n            return left instanceof right;\n        }\n    }\n\n    function _interopRequireDefault(obj) {\n        return obj && obj.__esModule\n            ? obj\n            : {\n                  default: obj,\n              };\n    }\n\n    function _interopRequireWildcard(obj) {\n        if (obj && obj.__esModule) {\n            return obj;\n        } else {\n            var newObj = {};\n\n            if (obj != null) {\n                for (var key in obj) {\n                    if (Object.prototype.hasOwnProperty.call(obj, key)) {\n                        var desc =\n                            Object.defineProperty && Object.getOwnPropertyDescriptor\n                                ? Object.getOwnPropertyDescriptor(obj, key)\n                                : {};\n\n                        if (desc.get || desc.set) {\n                            Object.defineProperty(newObj, key, desc);\n                        } else {\n                            newObj[key] = obj[key];\n                        }\n                    }\n                }\n            }\n\n            newObj.default = obj;\n            return newObj;\n        }\n    }\n\n    function _newArrowCheck(innerThis, boundThis) {\n        if (innerThis !== boundThis) {\n            throw new TypeError('Cannot instantiate an arrow function');\n        }\n    }\n\n    function _objectDestructuringEmpty(obj) {\n        if (obj == null) throw new TypeError('Cannot destructure undefined');\n    }\n\n    function _objectWithoutPropertiesLoose(source, excluded) {\n        if (source == null) return {};\n        var target = {};\n        var sourceKeys = Object.keys(source);\n        var key, i;\n\n        for (i = 0; i < sourceKeys.length; i++) {\n            key = sourceKeys[i];\n            if (excluded.indexOf(key) >= 0) continue;\n            target[key] = source[key];\n        }\n\n        return target;\n    }\n\n    function _objectWithoutProperties(source, excluded) {\n        if (source == null) return {};\n\n        var target = _objectWithoutPropertiesLoose(source, excluded);\n\n        var key, i;\n\n        if (Object.getOwnPropertySymbols) {\n            var sourceSymbolKeys = Object.getOwnPropertySymbols(source);\n\n            for (i = 0; i < sourceSymbolKeys.length; i++) {\n                key = sourceSymbolKeys[i];\n                if (excluded.indexOf(key) >= 0) continue;\n                if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n                target[key] = source[key];\n            }\n        }\n\n        return target;\n    }\n\n    function _assertThisInitialized(self) {\n        if (self === void 0) {\n            throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n        }\n\n        return self;\n    }\n\n    function _possibleConstructorReturn(self, call) {\n        if (call && (typeof call === 'object' || typeof call === 'function')) {\n            return call;\n        }\n\n        return _assertThisInitialized(self);\n    }\n\n    function _superPropBase(object, property) {\n        while (!Object.prototype.hasOwnProperty.call(object, property)) {\n            object = _getPrototypeOf(object);\n            if (object === null) break;\n        }\n\n        return object;\n    }\n\n    function _get(target, property, receiver) {\n        if (typeof Reflect !== 'undefined' && Reflect.get) {\n            _get = Reflect.get;\n        } else {\n            _get = function _get(target, property, receiver) {\n                var base = _superPropBase(target, property);\n\n                if (!base) return;\n                var desc = Object.getOwnPropertyDescriptor(base, property);\n\n                if (desc.get) {\n                    return desc.get.call(receiver);\n                }\n\n                return desc.value;\n            };\n        }\n\n        return _get(target, property, receiver || target);\n    }\n\n    function set(target, property, value, receiver) {\n        if (typeof Reflect !== 'undefined' && Reflect.set) {\n            set = Reflect.set;\n        } else {\n            set = function set(target, property, value, receiver) {\n                var base = _superPropBase(target, property);\n\n                var desc;\n\n                if (base) {\n                    desc = Object.getOwnPropertyDescriptor(base, property);\n\n                    if (desc.set) {\n                        desc.set.call(receiver, value);\n                        return true;\n                    } else if (!desc.writable) {\n                        return false;\n                    }\n                }\n\n                desc = Object.getOwnPropertyDescriptor(receiver, property);\n\n                if (desc) {\n                    if (!desc.writable) {\n                        return false;\n                    }\n\n                    desc.value = value;\n                    Object.defineProperty(receiver, property, desc);\n                } else {\n                    _defineProperty(receiver, property, value);\n                }\n\n                return true;\n            };\n        }\n\n        return set(target, property, value, receiver);\n    }\n\n    function _set(target, property, value, receiver, isStrict) {\n        var s = set(target, property, value, receiver || target);\n\n        if (!s && isStrict) {\n            throw new Error('failed to set property');\n        }\n\n        return value;\n    }\n\n    function _taggedTemplateLiteral(strings, raw) {\n        if (!raw) {\n            raw = strings.slice(0);\n        }\n\n        return Object.freeze(\n            Object.defineProperties(strings, {\n                raw: {\n                    value: Object.freeze(raw),\n                },\n            })\n        );\n    }\n\n    function _taggedTemplateLiteralLoose(strings, raw) {\n        if (!raw) {\n            raw = strings.slice(0);\n        }\n\n        strings.raw = raw;\n        return strings;\n    }\n\n    function _temporalRef(val, name) {\n        if (val === _temporalUndefined) {\n            throw new ReferenceError(name + ' is not defined - temporal dead zone');\n        } else {\n            return val;\n        }\n    }\n\n    function _readOnlyError(name) {\n        throw new Error('\"' + name + '\" is read-only');\n    }\n\n    function _classNameTDZError(name) {\n        throw new Error('Class \"' + name + '\" cannot be referenced in computed property keys.');\n    }\n\n    var _temporalUndefined = {};\n\n    function _slicedToArray(arr, i) {\n        return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();\n    }\n\n    function _slicedToArrayLoose(arr, i) {\n        return _arrayWithHoles(arr) || _iterableToArrayLimitLoose(arr, i) || _nonIterableRest();\n    }\n\n    function _toArray(arr) {\n        return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest();\n    }\n\n    function _toConsumableArray(arr) {\n        return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();\n    }\n\n    function _arrayWithoutHoles(arr) {\n        if (Array.isArray(arr)) {\n            for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];\n\n            return arr2;\n        }\n    }\n\n    function _arrayWithHoles(arr) {\n        if (Array.isArray(arr)) return arr;\n    }\n\n    function _iterableToArray(iter) {\n        if (\n            Symbol.iterator in Object(iter) ||\n            Object.prototype.toString.call(iter) === '[object Arguments]'\n        )\n            return Array.from(iter);\n    }\n\n    function _iterableToArrayLimit(arr, i) {\n        var _arr = [];\n        var _n = true;\n        var _d = false;\n        var _e = undefined;\n\n        try {\n            for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n                _arr.push(_s.value);\n\n                if (i && _arr.length === i) break;\n            }\n        } catch (err) {\n            _d = true;\n            _e = err;\n        } finally {\n            try {\n                if (!_n && _i['return'] != null) _i['return']();\n            } finally {\n                if (_d) throw _e;\n            }\n        }\n\n        return _arr;\n    }\n\n    function _iterableToArrayLimitLoose(arr, i) {\n        var _arr = [];\n\n        for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done; ) {\n            _arr.push(_step.value);\n\n            if (i && _arr.length === i) break;\n        }\n\n        return _arr;\n    }\n\n    function _nonIterableSpread() {\n        throw new TypeError('Invalid attempt to spread non-iterable instance');\n    }\n\n    function _nonIterableRest() {\n        throw new TypeError('Invalid attempt to destructure non-iterable instance');\n    }\n\n    function _skipFirstGeneratorNext(fn) {\n        return function() {\n            var it = fn.apply(this, arguments);\n            it.next();\n            return it;\n        };\n    }\n\n    function _toPrimitive(input, hint) {\n        if (typeof input !== 'object' || input === null) return input;\n        var prim = input[Symbol.toPrimitive];\n\n        if (prim !== undefined) {\n            var res = prim.call(input, hint || 'default');\n            if (typeof res !== 'object') return res;\n            throw new TypeError('@@toPrimitive must return a primitive value.');\n        }\n\n        return (hint === 'string' ? String : Number)(input);\n    }\n\n    function _toPropertyKey(arg) {\n        var key = _toPrimitive(arg, 'string');\n\n        return typeof key === 'symbol' ? key : String(key);\n    }\n\n    function _initializerWarningHelper(descriptor, context) {\n        throw new Error(\n            'Decorating class property failed. Please ensure that ' +\n                'proposal-class-properties is enabled and set to use loose mode. ' +\n                'To use proposal-class-properties in spec mode with decorators, wait for ' +\n                'the next major version of decorators in stage 2.'\n        );\n    }\n\n    function _initializerDefineProperty(target, property, descriptor, context) {\n        if (!descriptor) return;\n        Object.defineProperty(target, property, {\n            enumerable: descriptor.enumerable,\n            configurable: descriptor.configurable,\n            writable: descriptor.writable,\n            value: descriptor.initializer ? descriptor.initializer.call(context) : void 0,\n        });\n    }\n\n    function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {\n        var desc = {};\n        Object.keys(descriptor).forEach(function(key) {\n            desc[key] = descriptor[key];\n        });\n        desc.enumerable = !!desc.enumerable;\n        desc.configurable = !!desc.configurable;\n\n        if ('value' in desc || desc.initializer) {\n            desc.writable = true;\n        }\n\n        desc = decorators\n            .slice()\n            .reverse()\n            .reduce(function(desc, decorator) {\n                return decorator(target, property, desc) || desc;\n            }, desc);\n\n        if (context && desc.initializer !== void 0) {\n            desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n            desc.initializer = undefined;\n        }\n\n        if (desc.initializer === void 0) {\n            Object.defineProperty(target, property, desc);\n            desc = null;\n        }\n\n        return desc;\n    }\n\n    var id = 0;\n\n    function _classPrivateFieldLooseKey(name) {\n        return '__private_' + id++ + '_' + name;\n    }\n\n    function _classPrivateFieldLooseBase(receiver, privateKey) {\n        if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {\n            throw new TypeError('attempted to use private field on non-instance');\n        }\n\n        return receiver;\n    }\n\n    function _classPrivateFieldGet(receiver, privateMap) {\n        var descriptor = privateMap.get(receiver);\n\n        if (!descriptor) {\n            throw new TypeError('attempted to get private field on non-instance');\n        }\n\n        if (descriptor.get) {\n            return descriptor.get.call(receiver);\n        }\n\n        return descriptor.value;\n    }\n\n    function _classPrivateFieldSet(receiver, privateMap, value) {\n        var descriptor = privateMap.get(receiver);\n\n        if (!descriptor) {\n            throw new TypeError('attempted to set private field on non-instance');\n        }\n\n        if (descriptor.set) {\n            descriptor.set.call(receiver, value);\n        } else {\n            if (!descriptor.writable) {\n                throw new TypeError('attempted to set read only private field');\n            }\n\n            descriptor.value = value;\n        }\n\n        return value;\n    }\n\n    function _classPrivateFieldDestructureSet(receiver, privateMap) {\n        if (!privateMap.has(receiver)) {\n            throw new TypeError('attempted to set private field on non-instance');\n        }\n\n        var descriptor = privateMap.get(receiver);\n\n        if (descriptor.set) {\n            if (!('__destrObj' in descriptor)) {\n                descriptor.__destrObj = {\n                    set value(v) {\n                        descriptor.set.call(receiver, v);\n                    },\n                };\n            }\n\n            return descriptor.__destrObj;\n        } else {\n            if (!descriptor.writable) {\n                throw new TypeError('attempted to set read only private field');\n            }\n\n            return descriptor;\n        }\n    }\n\n    function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) {\n        if (receiver !== classConstructor) {\n            throw new TypeError('Private static access of wrong provenance');\n        }\n\n        return descriptor.value;\n    }\n\n    function _classStaticPrivateFieldSpecSet(receiver, classConstructor, descriptor, value) {\n        if (receiver !== classConstructor) {\n            throw new TypeError('Private static access of wrong provenance');\n        }\n\n        if (!descriptor.writable) {\n            throw new TypeError('attempted to set read only private field');\n        }\n\n        descriptor.value = value;\n        return value;\n    }\n\n    function _classStaticPrivateMethodGet(receiver, classConstructor, method) {\n        if (receiver !== classConstructor) {\n            throw new TypeError('Private static access of wrong provenance');\n        }\n\n        return method;\n    }\n\n    function _classStaticPrivateMethodSet() {\n        throw new TypeError('attempted to set read only static private field');\n    }\n\n    function _decorate(decorators, factory, superClass, mixins) {\n        var api = _getDecoratorsApi();\n\n        if (mixins) {\n            for (var i = 0; i < mixins.length; i++) {\n                api = mixins[i](api);\n            }\n        }\n\n        var r = factory(function initialize(O) {\n            api.initializeInstanceElements(O, decorated.elements);\n        }, superClass);\n        var decorated = api.decorateClass(\n            _coalesceClassElements(r.d.map(_createElementDescriptor)),\n            decorators\n        );\n        api.initializeClassElements(r.F, decorated.elements);\n        return api.runClassFinishers(r.F, decorated.finishers);\n    }\n\n    function _getDecoratorsApi() {\n        _getDecoratorsApi = function() {\n            return api;\n        };\n\n        var api = {\n            elementsDefinitionOrder: [['method'], ['field']],\n            initializeInstanceElements: function(O, elements) {\n                ['method', 'field'].forEach(function(kind) {\n                    elements.forEach(function(element) {\n                        if (element.kind === kind && element.placement === 'own') {\n                            this.defineClassElement(O, element);\n                        }\n                    }, this);\n                }, this);\n            },\n            initializeClassElements: function(F, elements) {\n                var proto = F.prototype;\n                ['method', 'field'].forEach(function(kind) {\n                    elements.forEach(function(element) {\n                        var placement = element.placement;\n\n                        if (\n                            element.kind === kind &&\n                            (placement === 'static' || placement === 'prototype')\n                        ) {\n                            var receiver = placement === 'static' ? F : proto;\n                            this.defineClassElement(receiver, element);\n                        }\n                    }, this);\n                }, this);\n            },\n            defineClassElement: function(receiver, element) {\n                var descriptor = element.descriptor;\n\n                if (element.kind === 'field') {\n                    var initializer = element.initializer;\n                    descriptor = {\n                        enumerable: descriptor.enumerable,\n                        writable: descriptor.writable,\n                        configurable: descriptor.configurable,\n                        value: initializer === void 0 ? void 0 : initializer.call(receiver),\n                    };\n                }\n\n                Object.defineProperty(receiver, element.key, descriptor);\n            },\n            decorateClass: function(elements, decorators) {\n                var newElements = [];\n                var finishers = [];\n                var placements = {\n                    static: [],\n                    prototype: [],\n                    own: [],\n                };\n                elements.forEach(function(element) {\n                    this.addElementPlacement(element, placements);\n                }, this);\n                elements.forEach(function(element) {\n                    if (!_hasDecorators(element)) return newElements.push(element);\n                    var elementFinishersExtras = this.decorateElement(element, placements);\n                    newElements.push(elementFinishersExtras.element);\n                    newElements.push.apply(newElements, elementFinishersExtras.extras);\n                    finishers.push.apply(finishers, elementFinishersExtras.finishers);\n                }, this);\n\n                if (!decorators) {\n                    return {\n                        elements: newElements,\n                        finishers: finishers,\n                    };\n                }\n\n                var result = this.decorateConstructor(newElements, decorators);\n                finishers.push.apply(finishers, result.finishers);\n                result.finishers = finishers;\n                return result;\n            },\n            addElementPlacement: function(element, placements, silent) {\n                var keys = placements[element.placement];\n\n                if (!silent && keys.indexOf(element.key) !== -1) {\n                    throw new TypeError('Duplicated element (' + element.key + ')');\n                }\n\n                keys.push(element.key);\n            },\n            decorateElement: function(element, placements) {\n                var extras = [];\n                var finishers = [];\n\n                for (var decorators = element.decorators, i = decorators.length - 1; i >= 0; i--) {\n                    var keys = placements[element.placement];\n                    keys.splice(keys.indexOf(element.key), 1);\n                    var elementObject = this.fromElementDescriptor(element);\n                    var elementFinisherExtras = this.toElementFinisherExtras(\n                        (0, decorators[i])(elementObject) || elementObject\n                    );\n                    element = elementFinisherExtras.element;\n                    this.addElementPlacement(element, placements);\n\n                    if (elementFinisherExtras.finisher) {\n                        finishers.push(elementFinisherExtras.finisher);\n                    }\n\n                    var newExtras = elementFinisherExtras.extras;\n\n                    if (newExtras) {\n                        for (var j = 0; j < newExtras.length; j++) {\n                            this.addElementPlacement(newExtras[j], placements);\n                        }\n\n                        extras.push.apply(extras, newExtras);\n                    }\n                }\n\n                return {\n                    element: element,\n                    finishers: finishers,\n                    extras: extras,\n                };\n            },\n            decorateConstructor: function(elements, decorators) {\n                var finishers = [];\n\n                for (var i = decorators.length - 1; i >= 0; i--) {\n                    var obj = this.fromClassDescriptor(elements);\n                    var elementsAndFinisher = this.toClassDescriptor(\n                        (0, decorators[i])(obj) || obj\n                    );\n\n                    if (elementsAndFinisher.finisher !== undefined) {\n                        finishers.push(elementsAndFinisher.finisher);\n                    }\n\n                    if (elementsAndFinisher.elements !== undefined) {\n                        elements = elementsAndFinisher.elements;\n\n                        for (var j = 0; j < elements.length - 1; j++) {\n                            for (var k = j + 1; k < elements.length; k++) {\n                                if (\n                                    elements[j].key === elements[k].key &&\n                                    elements[j].placement === elements[k].placement\n                                ) {\n                                    throw new TypeError(\n                                        'Duplicated element (' + elements[j].key + ')'\n                                    );\n                                }\n                            }\n                        }\n                    }\n                }\n\n                return {\n                    elements: elements,\n                    finishers: finishers,\n                };\n            },\n            fromElementDescriptor: function(element) {\n                var obj = {\n                    kind: element.kind,\n                    key: element.key,\n                    placement: element.placement,\n                    descriptor: element.descriptor,\n                };\n                var desc = {\n                    value: 'Descriptor',\n                    configurable: true,\n                };\n                Object.defineProperty(obj, Symbol.toStringTag, desc);\n                if (element.kind === 'field') obj.initializer = element.initializer;\n                return obj;\n            },\n            toElementDescriptors: function(elementObjects) {\n                if (elementObjects === undefined) return;\n                return _toArray(elementObjects).map(function(elementObject) {\n                    var element = this.toElementDescriptor(elementObject);\n                    this.disallowProperty(elementObject, 'finisher', 'An element descriptor');\n                    this.disallowProperty(elementObject, 'extras', 'An element descriptor');\n                    return element;\n                }, this);\n            },\n            toElementDescriptor: function(elementObject) {\n                var kind = String(elementObject.kind);\n\n                if (kind !== 'method' && kind !== 'field') {\n                    throw new TypeError(\n                        'An element descriptor\\'s .kind property must be either \"method\" or' +\n                            ' \"field\", but a decorator created an element descriptor with' +\n                            ' .kind \"' +\n                            kind +\n                            '\"'\n                    );\n                }\n\n                var key = _toPropertyKey(elementObject.key);\n\n                var placement = String(elementObject.placement);\n\n                if (placement !== 'static' && placement !== 'prototype' && placement !== 'own') {\n                    throw new TypeError(\n                        'An element descriptor\\'s .placement property must be one of \"static\",' +\n                            ' \"prototype\" or \"own\", but a decorator created an element descriptor' +\n                            ' with .placement \"' +\n                            placement +\n                            '\"'\n                    );\n                }\n\n                var descriptor = elementObject.descriptor;\n                this.disallowProperty(elementObject, 'elements', 'An element descriptor');\n                var element = {\n                    kind: kind,\n                    key: key,\n                    placement: placement,\n                    descriptor: Object.assign({}, descriptor),\n                };\n\n                if (kind !== 'field') {\n                    this.disallowProperty(elementObject, 'initializer', 'A method descriptor');\n                } else {\n                    this.disallowProperty(\n                        descriptor,\n                        'get',\n                        'The property descriptor of a field descriptor'\n                    );\n                    this.disallowProperty(\n                        descriptor,\n                        'set',\n                        'The property descriptor of a field descriptor'\n                    );\n                    this.disallowProperty(\n                        descriptor,\n                        'value',\n                        'The property descriptor of a field descriptor'\n                    );\n                    element.initializer = elementObject.initializer;\n                }\n\n                return element;\n            },\n            toElementFinisherExtras: function(elementObject) {\n                var element = this.toElementDescriptor(elementObject);\n\n                var finisher = _optionalCallableProperty(elementObject, 'finisher');\n\n                var extras = this.toElementDescriptors(elementObject.extras);\n                return {\n                    element: element,\n                    finisher: finisher,\n                    extras: extras,\n                };\n            },\n            fromClassDescriptor: function(elements) {\n                var obj = {\n                    kind: 'class',\n                    elements: elements.map(this.fromElementDescriptor, this),\n                };\n                var desc = {\n                    value: 'Descriptor',\n                    configurable: true,\n                };\n                Object.defineProperty(obj, Symbol.toStringTag, desc);\n                return obj;\n            },\n            toClassDescriptor: function(obj) {\n                var kind = String(obj.kind);\n\n                if (kind !== 'class') {\n                    throw new TypeError(\n                        'A class descriptor\\'s .kind property must be \"class\", but a decorator' +\n                            ' created a class descriptor with .kind \"' +\n                            kind +\n                            '\"'\n                    );\n                }\n\n                this.disallowProperty(obj, 'key', 'A class descriptor');\n                this.disallowProperty(obj, 'placement', 'A class descriptor');\n                this.disallowProperty(obj, 'descriptor', 'A class descriptor');\n                this.disallowProperty(obj, 'initializer', 'A class descriptor');\n                this.disallowProperty(obj, 'extras', 'A class descriptor');\n\n                var finisher = _optionalCallableProperty(obj, 'finisher');\n\n                var elements = this.toElementDescriptors(obj.elements);\n                return {\n                    elements: elements,\n                    finisher: finisher,\n                };\n            },\n            runClassFinishers: function(constructor, finishers) {\n                for (var i = 0; i < finishers.length; i++) {\n                    var newConstructor = (0, finishers[i])(constructor);\n\n                    if (newConstructor !== undefined) {\n                        if (typeof newConstructor !== 'function') {\n                            throw new TypeError('Finishers must return a constructor.');\n                        }\n\n                        constructor = newConstructor;\n                    }\n                }\n\n                return constructor;\n            },\n            disallowProperty: function(obj, name, objectType) {\n                if (obj[name] !== undefined) {\n                    throw new TypeError(objectType + \" can't have a .\" + name + ' property.');\n                }\n            },\n        };\n        return api;\n    }\n\n    function _createElementDescriptor(def) {\n        var key = _toPropertyKey(def.key);\n\n        var descriptor;\n\n        if (def.kind === 'method') {\n            descriptor = {\n                value: def.value,\n                writable: true,\n                configurable: true,\n                enumerable: false,\n            };\n        } else if (def.kind === 'get') {\n            descriptor = {\n                get: def.value,\n                configurable: true,\n                enumerable: false,\n            };\n        } else if (def.kind === 'set') {\n            descriptor = {\n                set: def.value,\n                configurable: true,\n                enumerable: false,\n            };\n        } else if (def.kind === 'field') {\n            descriptor = {\n                configurable: true,\n                writable: true,\n                enumerable: true,\n            };\n        }\n\n        var element = {\n            kind: def.kind === 'field' ? 'field' : 'method',\n            key: key,\n            placement: def.static ? 'static' : def.kind === 'field' ? 'own' : 'prototype',\n            descriptor: descriptor,\n        };\n        if (def.decorators) element.decorators = def.decorators;\n        if (def.kind === 'field') element.initializer = def.value;\n        return element;\n    }\n\n    function _coalesceGetterSetter(element, other) {\n        if (element.descriptor.get !== undefined) {\n            other.descriptor.get = element.descriptor.get;\n        } else {\n            other.descriptor.set = element.descriptor.set;\n        }\n    }\n\n    function _coalesceClassElements(elements) {\n        var newElements = [];\n\n        var isSameElement = function(other) {\n            return (\n                other.kind === 'method' &&\n                other.key === element.key &&\n                other.placement === element.placement\n            );\n        };\n\n        for (var i = 0; i < elements.length; i++) {\n            var element = elements[i];\n            var other;\n\n            if (element.kind === 'method' && (other = newElements.find(isSameElement))) {\n                if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) {\n                    if (_hasDecorators(element) || _hasDecorators(other)) {\n                        throw new ReferenceError(\n                            'Duplicated methods (' + element.key + \") can't be decorated.\"\n                        );\n                    }\n\n                    other.descriptor = element.descriptor;\n                } else {\n                    if (_hasDecorators(element)) {\n                        if (_hasDecorators(other)) {\n                            throw new ReferenceError(\n                                \"Decorators can't be placed on different accessors with for \" +\n                                    'the same property (' +\n                                    element.key +\n                                    ').'\n                            );\n                        }\n\n                        other.decorators = element.decorators;\n                    }\n\n                    _coalesceGetterSetter(element, other);\n                }\n            } else {\n                newElements.push(element);\n            }\n        }\n\n        return newElements;\n    }\n\n    function _hasDecorators(element) {\n        return element.decorators && element.decorators.length;\n    }\n\n    function _isDataDescriptor(desc) {\n        return desc !== undefined && !(desc.value === undefined && desc.writable === undefined);\n    }\n\n    function _optionalCallableProperty(obj, name) {\n        var value = obj[name];\n\n        if (value !== undefined && typeof value !== 'function') {\n            throw new TypeError(\"Expected '\" + name + \"' to be a function\");\n        }\n\n        return value;\n    }\n\n    function _classPrivateMethodGet(receiver, privateSet, fn) {\n        if (!privateSet.has(receiver)) {\n            throw new TypeError('attempted to get private field on non-instance');\n        }\n\n        return fn;\n    }\n\n    function _classPrivateMethodSet() {\n        throw new TypeError('attempted to reassign private method');\n    }\n\n    function _wrapRegExp(re, groups) {\n        _wrapRegExp = function(re, groups) {\n            return new BabelRegExp(re, groups);\n        };\n\n        var _RegExp = _wrapNativeSuper(RegExp);\n\n        var _super = RegExp.prototype;\n\n        var _groups = new WeakMap();\n\n        function BabelRegExp(re, groups) {\n            var _this = _RegExp.call(this, re);\n\n            _groups.set(_this, groups);\n\n            return _this;\n        }\n\n        _inherits(BabelRegExp, _RegExp);\n\n        BabelRegExp.prototype.exec = function(str) {\n            var result = _super.exec.call(this, str);\n\n            if (result) result.groups = buildGroups(result, this);\n            return result;\n        };\n\n        BabelRegExp.prototype[Symbol.replace] = function(str, substitution) {\n            if (typeof substitution === 'string') {\n                var groups = _groups.get(this);\n\n                return _super[Symbol.replace].call(\n                    this,\n                    str,\n                    substitution.replace(/\\$<([^>]+)>/g, function(_, name) {\n                        return '$' + groups[name];\n                    })\n                );\n            } else if (typeof substitution === 'function') {\n                var _this = this;\n\n                return _super[Symbol.replace].call(this, str, function() {\n                    var args = [];\n                    args.push.apply(args, arguments);\n\n                    if (typeof args[args.length - 1] !== 'object') {\n                        args.push(buildGroups(args, _this));\n                    }\n\n                    return substitution.apply(this, args);\n                });\n            } else {\n                return _super[Symbol.replace].call(this, str, substitution);\n            }\n        };\n\n        function buildGroups(result, re) {\n            var g = _groups.get(re);\n\n            return Object.keys(g).reduce(function(groups, name) {\n                groups[name] = result[g[name]];\n                return groups;\n            }, Object.create(null));\n        }\n\n        return _wrapRegExp.apply(this, arguments);\n    }\n\n    var arrayRemove = function arrayRemove(arr, index) {\n        return arr.splice(index, 1);\n    };\n\n    var run = function run(cb, sync) {\n        if (sync) {\n            cb();\n        } else if (document.hidden) {\n            Promise.resolve(1).then(cb);\n        } else {\n            setTimeout(cb, 0);\n        }\n    };\n\n    var on = function on() {\n        var listeners = [];\n        var off = function off(event, cb) {\n            arrayRemove(\n                listeners,\n                listeners.findIndex(function(listener) {\n                    return listener.event === event && (listener.cb === cb || !cb);\n                })\n            );\n        };\n        var _fire = function fire(event, args, sync) {\n            listeners\n                .filter(function(listener) {\n                    return listener.event === event;\n                })\n                .map(function(listener) {\n                    return listener.cb;\n                })\n                .forEach(function(cb) {\n                    return run(function() {\n                        return cb.apply(void 0, _toConsumableArray(args));\n                    }, sync);\n                });\n        };\n        return {\n            fireSync: function fireSync(event) {\n                for (\n                    var _len = arguments.length,\n                        args = new Array(_len > 1 ? _len - 1 : 0),\n                        _key = 1;\n                    _key < _len;\n                    _key++\n                ) {\n                    args[_key - 1] = arguments[_key];\n                }\n                _fire(event, args, true);\n            },\n            fire: function fire(event) {\n                for (\n                    var _len2 = arguments.length,\n                        args = new Array(_len2 > 1 ? _len2 - 1 : 0),\n                        _key2 = 1;\n                    _key2 < _len2;\n                    _key2++\n                ) {\n                    args[_key2 - 1] = arguments[_key2];\n                }\n                _fire(event, args, false);\n            },\n            on: function on(event, cb) {\n                listeners.push({ event: event, cb: cb });\n            },\n            onOnce: function onOnce(event, _cb) {\n                listeners.push({\n                    event: event,\n                    cb: function cb() {\n                        off(event, _cb);\n                        _cb.apply(void 0, arguments);\n                    },\n                });\n            },\n            off: off,\n        };\n    };\n\n    var copyObjectPropertiesToObject = function copyObjectPropertiesToObject(\n        src,\n        target,\n        excluded\n    ) {\n        Object.getOwnPropertyNames(src)\n            .filter(function(property) {\n                return !excluded.includes(property);\n            })\n            .forEach(function(key) {\n                return Object.defineProperty(\n                    target,\n                    key,\n                    Object.getOwnPropertyDescriptor(src, key)\n                );\n            });\n    };\n\n    var PRIVATE = [\n        'fire',\n        'process',\n        'revert',\n        'load',\n        'on',\n        'off',\n        'onOnce',\n        'retryLoad',\n        'extend',\n        'archive',\n        'archived',\n        'release',\n        'released',\n        'requestProcessing',\n        'freeze',\n    ];\n\n    var createItemAPI = function createItemAPI(item) {\n        var api = {};\n        copyObjectPropertiesToObject(item, api, PRIVATE);\n        return api;\n    };\n\n    var removeReleasedItems = function removeReleasedItems(items) {\n        items.forEach(function(item, index) {\n            if (item.released) {\n                arrayRemove(items, index);\n            }\n        });\n    };\n\n    var ItemStatus = {\n        INIT: 1,\n        IDLE: 2,\n        PROCESSING_QUEUED: 9,\n        PROCESSING: 3,\n        PROCESSING_COMPLETE: 5,\n        PROCESSING_ERROR: 6,\n        PROCESSING_REVERT_ERROR: 10,\n        LOADING: 7,\n        LOAD_ERROR: 8,\n    };\n\n    var FileOrigin = {\n        INPUT: 1,\n        LIMBO: 2,\n        LOCAL: 3,\n    };\n\n    var getNonNumeric = function getNonNumeric(str) {\n        return /[^0-9]+/.exec(str);\n    };\n\n    var getDecimalSeparator = function getDecimalSeparator() {\n        return getNonNumeric((1.1).toLocaleString())[0];\n    };\n\n    var getThousandsSeparator = function getThousandsSeparator() {\n        // Added for browsers that do not return the thousands separator (happend on native browser Android 4.4.4)\n        // We check against the normal toString output and if they're the same return a comma when decimal separator is a dot\n        var decimalSeparator = getDecimalSeparator();\n        var thousandsStringWithSeparator = (1000.0).toLocaleString();\n        var thousandsStringWithoutSeparator = (1000.0).toString();\n        if (thousandsStringWithSeparator !== thousandsStringWithoutSeparator) {\n            return getNonNumeric(thousandsStringWithSeparator)[0];\n        }\n        return decimalSeparator === '.' ? ',' : '.';\n    };\n\n    var Type = {\n        BOOLEAN: 'boolean',\n        INT: 'int',\n        NUMBER: 'number',\n        STRING: 'string',\n        ARRAY: 'array',\n        OBJECT: 'object',\n        FUNCTION: 'function',\n        ACTION: 'action',\n        SERVER_API: 'serverapi',\n        REGEX: 'regex',\n    };\n\n    // all registered filters\n    var filters = [];\n\n    // loops over matching filters and passes options to each filter, returning the mapped results\n    var applyFilterChain = function applyFilterChain(key, value, utils) {\n        return new Promise(function(resolve, reject) {\n            // find matching filters for this key\n            var matchingFilters = filters\n                .filter(function(f) {\n                    return f.key === key;\n                })\n                .map(function(f) {\n                    return f.cb;\n                });\n\n            // resolve now\n            if (matchingFilters.length === 0) {\n                resolve(value);\n                return;\n            }\n\n            // first filter to kick things of\n            var initialFilter = matchingFilters.shift();\n\n            // chain filters\n            matchingFilters\n                .reduce(\n                    // loop over promises passing value to next promise\n                    function(current, next) {\n                        return current.then(function(value) {\n                            return next(value, utils);\n                        });\n                    },\n\n                    // call initial filter, will return a promise\n                    initialFilter(value, utils)\n\n                    // all executed\n                )\n                .then(function(value) {\n                    return resolve(value);\n                })\n                .catch(function(error) {\n                    return reject(error);\n                });\n        });\n    };\n\n    var applyFilters = function applyFilters(key, value, utils) {\n        return filters\n            .filter(function(f) {\n                return f.key === key;\n            })\n            .map(function(f) {\n                return f.cb(value, utils);\n            });\n    };\n\n    // adds a new filter to the list\n    var addFilter = function addFilter(key, cb) {\n        return filters.push({ key: key, cb: cb });\n    };\n\n    var extendDefaultOptions = function extendDefaultOptions(additionalOptions) {\n        return Object.assign(defaultOptions, additionalOptions);\n    };\n\n    var getOptions = function getOptions() {\n        return Object.assign({}, defaultOptions);\n    };\n\n    var setOptions = function setOptions(opts) {\n        forin(opts, function(key, value) {\n            // key does not exist, so this option cannot be set\n            if (!defaultOptions[key]) {\n                return;\n            }\n            defaultOptions[key][0] = getValueByType(\n                value,\n                defaultOptions[key][0],\n                defaultOptions[key][1]\n            );\n        });\n    };\n\n    // default options on app\n    var defaultOptions = {\n        // the id to add to the root element\n        id: [null, Type.STRING],\n\n        // input field name to use\n        name: ['filepond', Type.STRING],\n\n        // disable the field\n        disabled: [false, Type.BOOLEAN],\n\n        // classname to put on wrapper\n        className: [null, Type.STRING],\n\n        // is the field required\n        required: [false, Type.BOOLEAN],\n\n        // Allow media capture when value is set\n        captureMethod: [null, Type.STRING],\n        // - \"camera\", \"microphone\" or \"camcorder\",\n        // - Does not work with multiple on apple devices\n        // - If set, acceptedFileTypes must be made to match with media wildcard \"image/*\", \"audio/*\" or \"video/*\"\n\n        // sync `acceptedFileTypes` property with `accept` attribute\n        allowSyncAcceptAttribute: [true, Type.BOOLEAN],\n\n        // Feature toggles\n        allowDrop: [true, Type.BOOLEAN], // Allow dropping of files\n        allowBrowse: [true, Type.BOOLEAN], // Allow browsing the file system\n        allowPaste: [true, Type.BOOLEAN], // Allow pasting files\n        allowMultiple: [false, Type.BOOLEAN], // Allow multiple files (disabled by default, as multiple attribute is also required on input to allow multiple)\n        allowReplace: [true, Type.BOOLEAN], // Allow dropping a file on other file to replace it (only works when multiple is set to false)\n        allowRevert: [true, Type.BOOLEAN], // Allows user to revert file upload\n        allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file\n        allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button\n        allowReorder: [false, Type.BOOLEAN], // Allow reordering of files\n        allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)\n\n        // Try store file if `server` not set\n        storeAsFile: [false, Type.BOOLEAN],\n\n        // Revert mode\n        forceRevert: [false, Type.BOOLEAN], // Set to 'force' to require the file to be reverted before removal\n\n        // Input requirements\n        maxFiles: [null, Type.INT], // Max number of files\n        checkValidity: [false, Type.BOOLEAN], // Enables custom validity messages\n\n        // Where to put file\n        itemInsertLocationFreedom: [true, Type.BOOLEAN], // Set to false to always add items to begin or end of list\n        itemInsertLocation: ['before', Type.STRING], // Default index in list to add items that have been dropped at the top of the list\n        itemInsertInterval: [75, Type.INT],\n\n        // Drag 'n Drop related\n        dropOnPage: [false, Type.BOOLEAN], // Allow dropping of files anywhere on page (prevents browser from opening file if dropped outside of Up)\n        dropOnElement: [true, Type.BOOLEAN], // Drop needs to happen on element (set to false to also load drops outside of Up)\n        dropValidation: [false, Type.BOOLEAN], // Enable or disable validating files on drop\n        ignoredFiles: [['.ds_store', 'thumbs.db', 'desktop.ini'], Type.ARRAY],\n\n        // Upload related\n        instantUpload: [true, Type.BOOLEAN], // Should upload files immediately on drop\n        maxParallelUploads: [2, Type.INT], // Maximum files to upload in parallel\n        allowMinimumUploadDuration: [true, Type.BOOLEAN], // if true uploads take at least 750 ms, this ensures the user sees the upload progress giving trust the upload actually happened\n\n        // Chunks\n        chunkUploads: [false, Type.BOOLEAN], // Enable chunked uploads\n        chunkForce: [false, Type.BOOLEAN], // Force use of chunk uploads even for files smaller than chunk size\n        chunkSize: [5000000, Type.INT], // Size of chunks (5MB default)\n        chunkRetryDelays: [[500, 1000, 3000], Type.ARRAY], // Amount of times to retry upload of a chunk when it fails\n\n        // The server api end points to use for uploading (see docs)\n        server: [null, Type.SERVER_API],\n\n        // File size calculations, can set to 1024, this is only used for display, properties use file size base 1000\n        fileSizeBase: [1000, Type.INT],\n\n        // Labels and status messages\n        labelFileSizeBytes: ['bytes', Type.STRING],\n        labelFileSizeKilobytes: ['KB', Type.STRING],\n        labelFileSizeMegabytes: ['MB', Type.STRING],\n        labelFileSizeGigabytes: ['GB', Type.STRING],\n\n        labelDecimalSeparator: [getDecimalSeparator(), Type.STRING], // Default is locale separator\n        labelThousandsSeparator: [getThousandsSeparator(), Type.STRING], // Default is locale separator\n\n        labelIdle: [\n            'Drag & Drop your files or <span class=\"filepond--label-action\">Browse</span>',\n            Type.STRING,\n        ],\n\n        labelInvalidField: ['Field contains invalid files', Type.STRING],\n        labelFileWaitingForSize: ['Waiting for size', Type.STRING],\n        labelFileSizeNotAvailable: ['Size not available', Type.STRING],\n        labelFileCountSingular: ['file in list', Type.STRING],\n        labelFileCountPlural: ['files in list', Type.STRING],\n        labelFileLoading: ['Loading', Type.STRING],\n        labelFileAdded: ['Added', Type.STRING], // assistive only\n        labelFileLoadError: ['Error during load', Type.STRING],\n        labelFileRemoved: ['Removed', Type.STRING], // assistive only\n        labelFileRemoveError: ['Error during remove', Type.STRING],\n        labelFileProcessing: ['Uploading', Type.STRING],\n        labelFileProcessingComplete: ['Upload complete', Type.STRING],\n        labelFileProcessingAborted: ['Upload cancelled', Type.STRING],\n        labelFileProcessingError: ['Error during upload', Type.STRING],\n        labelFileProcessingRevertError: ['Error during revert', Type.STRING],\n\n        labelTapToCancel: ['tap to cancel', Type.STRING],\n        labelTapToRetry: ['tap to retry', Type.STRING],\n        labelTapToUndo: ['tap to undo', Type.STRING],\n\n        labelButtonRemoveItem: ['Remove', Type.STRING],\n        labelButtonAbortItemLoad: ['Abort', Type.STRING],\n        labelButtonRetryItemLoad: ['Retry', Type.STRING],\n        labelButtonAbortItemProcessing: ['Cancel', Type.STRING],\n        labelButtonUndoItemProcessing: ['Undo', Type.STRING],\n        labelButtonRetryItemProcessing: ['Retry', Type.STRING],\n        labelButtonProcessItem: ['Upload', Type.STRING],\n\n        // make sure width and height plus viewpox are even numbers so icons are nicely centered\n        iconRemove: [\n            '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.586 13l-2.293 2.293a1 1 0 0 0 1.414 1.414L13 14.414l2.293 2.293a1 1 0 0 0 1.414-1.414L14.414 13l2.293-2.293a1 1 0 0 0-1.414-1.414L13 11.586l-2.293-2.293a1 1 0 0 0-1.414 1.414L11.586 13z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n            Type.STRING,\n        ],\n\n        iconProcess: [\n            '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M14 10.414v3.585a1 1 0 0 1-2 0v-3.585l-1.293 1.293a1 1 0 0 1-1.414-1.415l3-3a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1-1.414 1.415L14 10.414zM9 18a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2H9z\" fill=\"currentColor\" fill-rule=\"evenodd\"/></svg>',\n            Type.STRING,\n        ],\n\n        iconRetry: [\n            '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10.81 9.185l-.038.02A4.997 4.997 0 0 0 8 13.683a5 5 0 0 0 5 5 5 5 0 0 0 5-5 1 1 0 0 1 2 0A7 7 0 1 1 9.722 7.496l-.842-.21a.999.999 0 1 1 .484-1.94l3.23.806c.535.133.86.675.73 1.21l-.804 3.233a.997.997 0 0 1-1.21.73.997.997 0 0 1-.73-1.21l.23-.928v-.002z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n            Type.STRING,\n        ],\n\n        iconUndo: [\n            '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.185 10.81l.02-.038A4.997 4.997 0 0 1 13.683 8a5 5 0 0 1 5 5 5 5 0 0 1-5 5 1 1 0 0 0 0 2A7 7 0 1 0 7.496 9.722l-.21-.842a.999.999 0 1 0-1.94.484l.806 3.23c.133.535.675.86 1.21.73l3.233-.803a.997.997 0 0 0 .73-1.21.997.997 0 0 0-1.21-.73l-.928.23-.002-.001z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n            Type.STRING,\n        ],\n\n        iconDone: [\n            '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M18.293 9.293a1 1 0 0 1 1.414 1.414l-7.002 7a1 1 0 0 1-1.414 0l-3.998-4a1 1 0 1 1 1.414-1.414L12 15.586l6.294-6.293z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n            Type.STRING,\n        ],\n\n        // event handlers\n        oninit: [null, Type.FUNCTION],\n        onwarning: [null, Type.FUNCTION],\n        onerror: [null, Type.FUNCTION],\n        onactivatefile: [null, Type.FUNCTION],\n        oninitfile: [null, Type.FUNCTION],\n        onaddfilestart: [null, Type.FUNCTION],\n        onaddfileprogress: [null, Type.FUNCTION],\n        onaddfile: [null, Type.FUNCTION],\n        onprocessfilestart: [null, Type.FUNCTION],\n        onprocessfileprogress: [null, Type.FUNCTION],\n        onprocessfileabort: [null, Type.FUNCTION],\n        onprocessfilerevert: [null, Type.FUNCTION],\n        onprocessfile: [null, Type.FUNCTION],\n        onprocessfiles: [null, Type.FUNCTION],\n        onremovefile: [null, Type.FUNCTION],\n        onpreparefile: [null, Type.FUNCTION],\n        onupdatefiles: [null, Type.FUNCTION],\n        onreorderfiles: [null, Type.FUNCTION],\n\n        // hooks\n        beforeDropFile: [null, Type.FUNCTION],\n        beforeAddFile: [null, Type.FUNCTION],\n        beforeRemoveFile: [null, Type.FUNCTION],\n        beforePrepareFile: [null, Type.FUNCTION],\n\n        // styles\n        stylePanelLayout: [null, Type.STRING], // null 'integrated', 'compact', 'circle'\n        stylePanelAspectRatio: [null, Type.STRING], // null or '3:2' or 1\n        styleItemPanelAspectRatio: [null, Type.STRING],\n        styleButtonRemoveItemPosition: ['left', Type.STRING],\n        styleButtonProcessItemPosition: ['right', Type.STRING],\n        styleLoadIndicatorPosition: ['right', Type.STRING],\n        styleProgressIndicatorPosition: ['right', Type.STRING],\n        styleButtonRemoveItemAlign: [false, Type.BOOLEAN],\n\n        // custom initial files array\n        files: [[], Type.ARRAY],\n\n        // show support by displaying credits\n        credits: [['https://filepond.com', 'Powered by FilePond'], Type.ARRAY],\n    };\n\n    var getItemByQuery = function getItemByQuery(items, query) {\n        // just return first index\n        if (isEmpty(query)) {\n            return items[0] || null;\n        }\n\n        // query is index\n        if (isInt(query)) {\n            return items[query] || null;\n        }\n\n        // if query is item, get the id\n        if (typeof query === 'object') {\n            query = query.id;\n        }\n\n        // assume query is a string and return item by id\n        return (\n            items.find(function(item) {\n                return item.id === query;\n            }) || null\n        );\n    };\n\n    var getNumericAspectRatioFromString = function getNumericAspectRatioFromString(aspectRatio) {\n        if (isEmpty(aspectRatio)) {\n            return aspectRatio;\n        }\n        if (/:/.test(aspectRatio)) {\n            var parts = aspectRatio.split(':');\n            return parts[1] / parts[0];\n        }\n        return parseFloat(aspectRatio);\n    };\n\n    var getActiveItems = function getActiveItems(items) {\n        return items.filter(function(item) {\n            return !item.archived;\n        });\n    };\n\n    var Status = {\n        EMPTY: 0,\n        IDLE: 1, // waiting\n        ERROR: 2, // a file is in error state\n        BUSY: 3, // busy processing or loading\n        READY: 4, // all files uploaded\n    };\n\n    var res = null;\n    var canUpdateFileInput = function canUpdateFileInput() {\n        if (res === null) {\n            try {\n                var dataTransfer = new DataTransfer();\n                dataTransfer.items.add(new File(['hello world'], 'This_Works.txt'));\n                var el = document.createElement('input');\n                el.setAttribute('type', 'file');\n                el.files = dataTransfer.files;\n                res = el.files.length === 1;\n            } catch (err) {\n                res = false;\n            }\n        }\n        return res;\n    };\n\n    var ITEM_ERROR = [\n        ItemStatus.LOAD_ERROR,\n        ItemStatus.PROCESSING_ERROR,\n        ItemStatus.PROCESSING_REVERT_ERROR,\n    ];\n\n    var ITEM_BUSY = [\n        ItemStatus.LOADING,\n        ItemStatus.PROCESSING,\n        ItemStatus.PROCESSING_QUEUED,\n        ItemStatus.INIT,\n    ];\n\n    var ITEM_READY = [ItemStatus.PROCESSING_COMPLETE];\n\n    var isItemInErrorState = function isItemInErrorState(item) {\n        return ITEM_ERROR.includes(item.status);\n    };\n    var isItemInBusyState = function isItemInBusyState(item) {\n        return ITEM_BUSY.includes(item.status);\n    };\n    var isItemInReadyState = function isItemInReadyState(item) {\n        return ITEM_READY.includes(item.status);\n    };\n\n    var isAsync = function isAsync(state) {\n        return (\n            isObject(state.options.server) &&\n            (isObject(state.options.server.process) || isFunction(state.options.server.process))\n        );\n    };\n\n    var queries = function queries(state) {\n        return {\n            GET_STATUS: function GET_STATUS() {\n                var items = getActiveItems(state.items);\n                var EMPTY = Status.EMPTY,\n                    ERROR = Status.ERROR,\n                    BUSY = Status.BUSY,\n                    IDLE = Status.IDLE,\n                    READY = Status.READY;\n\n                if (items.length === 0) return EMPTY;\n\n                if (items.some(isItemInErrorState)) return ERROR;\n\n                if (items.some(isItemInBusyState)) return BUSY;\n\n                if (items.some(isItemInReadyState)) return READY;\n\n                return IDLE;\n            },\n\n            GET_ITEM: function GET_ITEM(query) {\n                return getItemByQuery(state.items, query);\n            },\n\n            GET_ACTIVE_ITEM: function GET_ACTIVE_ITEM(query) {\n                return getItemByQuery(getActiveItems(state.items), query);\n            },\n\n            GET_ACTIVE_ITEMS: function GET_ACTIVE_ITEMS() {\n                return getActiveItems(state.items);\n            },\n\n            GET_ITEMS: function GET_ITEMS() {\n                return state.items;\n            },\n\n            GET_ITEM_NAME: function GET_ITEM_NAME(query) {\n                var item = getItemByQuery(state.items, query);\n                return item ? item.filename : null;\n            },\n\n            GET_ITEM_SIZE: function GET_ITEM_SIZE(query) {\n                var item = getItemByQuery(state.items, query);\n                return item ? item.fileSize : null;\n            },\n\n            GET_STYLES: function GET_STYLES() {\n                return Object.keys(state.options)\n                    .filter(function(key) {\n                        return /^style/.test(key);\n                    })\n                    .map(function(option) {\n                        return {\n                            name: option,\n                            value: state.options[option],\n                        };\n                    });\n            },\n\n            GET_PANEL_ASPECT_RATIO: function GET_PANEL_ASPECT_RATIO() {\n                var isShapeCircle = /circle/.test(state.options.stylePanelLayout);\n                var aspectRatio = isShapeCircle\n                    ? 1\n                    : getNumericAspectRatioFromString(state.options.stylePanelAspectRatio);\n                return aspectRatio;\n            },\n\n            GET_ITEM_PANEL_ASPECT_RATIO: function GET_ITEM_PANEL_ASPECT_RATIO() {\n                return state.options.styleItemPanelAspectRatio;\n            },\n\n            GET_ITEMS_BY_STATUS: function GET_ITEMS_BY_STATUS(status) {\n                return getActiveItems(state.items).filter(function(item) {\n                    return item.status === status;\n                });\n            },\n\n            GET_TOTAL_ITEMS: function GET_TOTAL_ITEMS() {\n                return getActiveItems(state.items).length;\n            },\n\n            SHOULD_UPDATE_FILE_INPUT: function SHOULD_UPDATE_FILE_INPUT() {\n                return state.options.storeAsFile && canUpdateFileInput() && !isAsync(state);\n            },\n\n            IS_ASYNC: function IS_ASYNC() {\n                return isAsync(state);\n            },\n\n            GET_FILE_SIZE_LABELS: function GET_FILE_SIZE_LABELS(query) {\n                return {\n                    labelBytes: query('GET_LABEL_FILE_SIZE_BYTES') || undefined,\n                    labelKilobytes: query('GET_LABEL_FILE_SIZE_KILOBYTES') || undefined,\n                    labelMegabytes: query('GET_LABEL_FILE_SIZE_MEGABYTES') || undefined,\n                    labelGigabytes: query('GET_LABEL_FILE_SIZE_GIGABYTES') || undefined,\n                };\n            },\n        };\n    };\n\n    var hasRoomForItem = function hasRoomForItem(state) {\n        var count = getActiveItems(state.items).length;\n\n        // if cannot have multiple items, to add one item it should currently not contain items\n        if (!state.options.allowMultiple) {\n            return count === 0;\n        }\n\n        // if allows multiple items, we check if a max item count has been set, if not, there's no limit\n        var maxFileCount = state.options.maxFiles;\n        if (maxFileCount === null) {\n            return true;\n        }\n\n        // we check if the current count is smaller than the max count, if so, another file can still be added\n        if (count < maxFileCount) {\n            return true;\n        }\n\n        // no more room for another file\n        return false;\n    };\n\n    var limit = function limit(value, min, max) {\n        return Math.max(Math.min(max, value), min);\n    };\n\n    var arrayInsert = function arrayInsert(arr, index, item) {\n        return arr.splice(index, 0, item);\n    };\n\n    var insertItem = function insertItem(items, item, index) {\n        if (isEmpty(item)) {\n            return null;\n        }\n\n        // if index is undefined, append\n        if (typeof index === 'undefined') {\n            items.push(item);\n            return item;\n        }\n\n        // limit the index to the size of the items array\n        index = limit(index, 0, items.length);\n\n        // add item to array\n        arrayInsert(items, index, item);\n\n        // expose\n        return item;\n    };\n\n    var isBase64DataURI = function isBase64DataURI(str) {\n        return /^\\s*data:([a-z]+\\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\\-._~:@\\/?%\\s]*)\\s*$/i.test(\n            str\n        );\n    };\n\n    var getFilenameFromURL = function getFilenameFromURL(url) {\n        return ('' + url)\n            .split('/')\n            .pop()\n            .split('?')\n            .shift();\n    };\n\n    var getExtensionFromFilename = function getExtensionFromFilename(name) {\n        return name.split('.').pop();\n    };\n\n    var guesstimateExtension = function guesstimateExtension(type) {\n        // if no extension supplied, exit here\n        if (typeof type !== 'string') {\n            return '';\n        }\n\n        // get subtype\n        var subtype = type.split('/').pop();\n\n        // is svg subtype\n        if (/svg/.test(subtype)) {\n            return 'svg';\n        }\n\n        if (/zip|compressed/.test(subtype)) {\n            return 'zip';\n        }\n\n        if (/plain/.test(subtype)) {\n            return 'txt';\n        }\n\n        if (/msword/.test(subtype)) {\n            return 'doc';\n        }\n\n        // if is valid subtype\n        if (/[a-z]+/.test(subtype)) {\n            // always use jpg extension\n            if (subtype === 'jpeg') {\n                return 'jpg';\n            }\n\n            // return subtype\n            return subtype;\n        }\n\n        return '';\n    };\n\n    var leftPad = function leftPad(value) {\n        var padding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n        return (padding + value).slice(-padding.length);\n    };\n\n    var getDateString = function getDateString() {\n        var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date();\n        return (\n            date.getFullYear() +\n            '-' +\n            leftPad(date.getMonth() + 1, '00') +\n            '-' +\n            leftPad(date.getDate(), '00') +\n            '_' +\n            leftPad(date.getHours(), '00') +\n            '-' +\n            leftPad(date.getMinutes(), '00') +\n            '-' +\n            leftPad(date.getSeconds(), '00')\n        );\n    };\n\n    var getFileFromBlob = function getFileFromBlob(blob, filename) {\n        var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n        var extension = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n        var file =\n            typeof type === 'string'\n                ? blob.slice(0, blob.size, type)\n                : blob.slice(0, blob.size, blob.type);\n        file.lastModifiedDate = new Date();\n\n        // copy relative path\n        if (blob._relativePath) file._relativePath = blob._relativePath;\n\n        // if blob has name property, use as filename if no filename supplied\n        if (!isString(filename)) {\n            filename = getDateString();\n        }\n\n        // if filename supplied but no extension and filename has extension\n        if (filename && extension === null && getExtensionFromFilename(filename)) {\n            file.name = filename;\n        } else {\n            extension = extension || guesstimateExtension(file.type);\n            file.name = filename + (extension ? '.' + extension : '');\n        }\n\n        return file;\n    };\n\n    var getBlobBuilder = function getBlobBuilder() {\n        return (window.BlobBuilder =\n            window.BlobBuilder ||\n            window.WebKitBlobBuilder ||\n            window.MozBlobBuilder ||\n            window.MSBlobBuilder);\n    };\n\n    var createBlob = function createBlob(arrayBuffer, mimeType) {\n        var BB = getBlobBuilder();\n\n        if (BB) {\n            var bb = new BB();\n            bb.append(arrayBuffer);\n            return bb.getBlob(mimeType);\n        }\n\n        return new Blob([arrayBuffer], {\n            type: mimeType,\n        });\n    };\n\n    var getBlobFromByteStringWithMimeType = function getBlobFromByteStringWithMimeType(\n        byteString,\n        mimeType\n    ) {\n        var ab = new ArrayBuffer(byteString.length);\n        var ia = new Uint8Array(ab);\n\n        for (var i = 0; i < byteString.length; i++) {\n            ia[i] = byteString.charCodeAt(i);\n        }\n\n        return createBlob(ab, mimeType);\n    };\n\n    var getMimeTypeFromBase64DataURI = function getMimeTypeFromBase64DataURI(dataURI) {\n        return (/^data:(.+);/.exec(dataURI) || [])[1] || null;\n    };\n\n    var getBase64DataFromBase64DataURI = function getBase64DataFromBase64DataURI(dataURI) {\n        // get data part of string (remove data:image/jpeg...,)\n        var data = dataURI.split(',')[1];\n\n        // remove any whitespace as that causes InvalidCharacterError in IE\n        return data.replace(/\\s/g, '');\n    };\n\n    var getByteStringFromBase64DataURI = function getByteStringFromBase64DataURI(dataURI) {\n        return atob(getBase64DataFromBase64DataURI(dataURI));\n    };\n\n    var getBlobFromBase64DataURI = function getBlobFromBase64DataURI(dataURI) {\n        var mimeType = getMimeTypeFromBase64DataURI(dataURI);\n        var byteString = getByteStringFromBase64DataURI(dataURI);\n\n        return getBlobFromByteStringWithMimeType(byteString, mimeType);\n    };\n\n    var getFileFromBase64DataURI = function getFileFromBase64DataURI(dataURI, filename, extension) {\n        return getFileFromBlob(getBlobFromBase64DataURI(dataURI), filename, null, extension);\n    };\n\n    var getFileNameFromHeader = function getFileNameFromHeader(header) {\n        // test if is content disposition header, if not exit\n        if (!/^content-disposition:/i.test(header)) return null;\n\n        // get filename parts\n        var matches = header\n            .split(/filename=|filename\\*=.+''/)\n            .splice(1)\n            .map(function(name) {\n                return name.trim().replace(/^[\"']|[;\"']{0,2}$/g, '');\n            })\n            .filter(function(name) {\n                return name.length;\n            });\n\n        return matches.length ? decodeURI(matches[matches.length - 1]) : null;\n    };\n\n    var getFileSizeFromHeader = function getFileSizeFromHeader(header) {\n        if (/content-length:/i.test(header)) {\n            var size = header.match(/[0-9]+/)[0];\n            return size ? parseInt(size, 10) : null;\n        }\n        return null;\n    };\n\n    var getTranfserIdFromHeader = function getTranfserIdFromHeader(header) {\n        if (/x-content-transfer-id:/i.test(header)) {\n            var id = (header.split(':')[1] || '').trim();\n            return id || null;\n        }\n        return null;\n    };\n\n    var getFileInfoFromHeaders = function getFileInfoFromHeaders(headers) {\n        var info = {\n            source: null,\n            name: null,\n            size: null,\n        };\n\n        var rows = headers.split('\\n');\n        var _iteratorNormalCompletion = true;\n        var _didIteratorError = false;\n        var _iteratorError = undefined;\n        try {\n            for (\n                var _iterator = rows[Symbol.iterator](), _step;\n                !(_iteratorNormalCompletion = (_step = _iterator.next()).done);\n                _iteratorNormalCompletion = true\n            ) {\n                var header = _step.value;\n\n                var name = getFileNameFromHeader(header);\n                if (name) {\n                    info.name = name;\n                    continue;\n                }\n\n                var size = getFileSizeFromHeader(header);\n                if (size) {\n                    info.size = size;\n                    continue;\n                }\n\n                var source = getTranfserIdFromHeader(header);\n                if (source) {\n                    info.source = source;\n                    continue;\n                }\n            }\n        } catch (err) {\n            _didIteratorError = true;\n            _iteratorError = err;\n        } finally {\n            try {\n                if (!_iteratorNormalCompletion && _iterator.return != null) {\n                    _iterator.return();\n                }\n            } finally {\n                if (_didIteratorError) {\n                    throw _iteratorError;\n                }\n            }\n        }\n\n        return info;\n    };\n\n    var createFileLoader = function createFileLoader(fetchFn) {\n        var state = {\n            source: null,\n            complete: false,\n            progress: 0,\n            size: null,\n            timestamp: null,\n            duration: 0,\n            request: null,\n        };\n\n        var getProgress = function getProgress() {\n            return state.progress;\n        };\n        var abort = function abort() {\n            if (state.request && state.request.abort) {\n                state.request.abort();\n            }\n        };\n\n        // load source\n        var load = function load() {\n            // get quick reference\n            var source = state.source;\n\n            api.fire('init', source);\n\n            // Load Files\n            if (source instanceof File) {\n                api.fire('load', source);\n            } else if (source instanceof Blob) {\n                // Load blobs, set default name to current date\n                api.fire('load', getFileFromBlob(source, source.name));\n            } else if (isBase64DataURI(source)) {\n                // Load base 64, set default name to current date\n                api.fire('load', getFileFromBase64DataURI(source));\n            } else {\n                // Deal as if is external URL, let's load it!\n                loadURL(source);\n            }\n        };\n\n        // loads a url\n        var loadURL = function loadURL(url) {\n            // is remote url and no fetch method supplied\n            if (!fetchFn) {\n                api.fire('error', {\n                    type: 'error',\n                    body: \"Can't load URL\",\n                    code: 400,\n                });\n\n                return;\n            }\n\n            // set request start\n            state.timestamp = Date.now();\n\n            // load file\n            state.request = fetchFn(\n                url,\n                function(response) {\n                    // update duration\n                    state.duration = Date.now() - state.timestamp;\n\n                    // done!\n                    state.complete = true;\n\n                    // turn blob response into a file\n                    if (response instanceof Blob) {\n                        response = getFileFromBlob(\n                            response,\n                            response.name || getFilenameFromURL(url)\n                        );\n                    }\n\n                    api.fire(\n                        'load',\n                        // if has received blob, we go with blob, if no response, we return null\n                        response instanceof Blob ? response : response ? response.body : null\n                    );\n                },\n                function(error) {\n                    api.fire(\n                        'error',\n                        typeof error === 'string'\n                            ? {\n                                  type: 'error',\n                                  code: 0,\n                                  body: error,\n                              }\n                            : error\n                    );\n                },\n                function(computable, current, total) {\n                    // collected some meta data already\n                    if (total) {\n                        state.size = total;\n                    }\n\n                    // update duration\n                    state.duration = Date.now() - state.timestamp;\n\n                    // if we can't compute progress, we're not going to fire progress events\n                    if (!computable) {\n                        state.progress = null;\n                        return;\n                    }\n\n                    // update progress percentage\n                    state.progress = current / total;\n\n                    // expose\n                    api.fire('progress', state.progress);\n                },\n                function() {\n                    api.fire('abort');\n                },\n                function(response) {\n                    var fileinfo = getFileInfoFromHeaders(\n                        typeof response === 'string' ? response : response.headers\n                    );\n                    api.fire('meta', {\n                        size: state.size || fileinfo.size,\n                        filename: fileinfo.name,\n                        source: fileinfo.source,\n                    });\n                }\n            );\n        };\n\n        var api = Object.assign({}, on(), {\n            setSource: function setSource(source) {\n                return (state.source = source);\n            },\n            getProgress: getProgress, // file load progress\n            abort: abort, // abort file load\n            load: load, // start load\n        });\n\n        return api;\n    };\n\n    var isGet = function isGet(method) {\n        return /GET|HEAD/.test(method);\n    };\n\n    var sendRequest = function sendRequest(data, url, options) {\n        var api = {\n            onheaders: function onheaders() {},\n            onprogress: function onprogress() {},\n            onload: function onload() {},\n            ontimeout: function ontimeout() {},\n            onerror: function onerror() {},\n            onabort: function onabort() {},\n            abort: function abort() {\n                aborted = true;\n                xhr.abort();\n            },\n        };\n\n        // timeout identifier, only used when timeout is defined\n        var aborted = false;\n        var headersReceived = false;\n\n        // set default options\n        options = Object.assign(\n            {\n                method: 'POST',\n                headers: {},\n                withCredentials: false,\n            },\n            options\n        );\n\n        // encode url\n        url = encodeURI(url);\n\n        // if method is GET, add any received data to url\n\n        if (isGet(options.method) && data) {\n            url =\n                '' +\n                url +\n                encodeURIComponent(typeof data === 'string' ? data : JSON.stringify(data));\n        }\n\n        // create request\n        var xhr = new XMLHttpRequest();\n\n        // progress of load\n        var process = isGet(options.method) ? xhr : xhr.upload;\n        process.onprogress = function(e) {\n            // no progress event when aborted ( onprogress is called once after abort() )\n            if (aborted) {\n                return;\n            }\n\n            api.onprogress(e.lengthComputable, e.loaded, e.total);\n        };\n\n        // tries to get header info to the app as fast as possible\n        xhr.onreadystatechange = function() {\n            // not interesting in these states ('unsent' and 'openend' as they don't give us any additional info)\n            if (xhr.readyState < 2) {\n                return;\n            }\n\n            // no server response\n            if (xhr.readyState === 4 && xhr.status === 0) {\n                return;\n            }\n\n            if (headersReceived) {\n                return;\n            }\n\n            headersReceived = true;\n\n            // we've probably received some useful data in response headers\n            api.onheaders(xhr);\n        };\n\n        // load successful\n        xhr.onload = function() {\n            // is classified as valid response\n            if (xhr.status >= 200 && xhr.status < 300) {\n                api.onload(xhr);\n            } else {\n                api.onerror(xhr);\n            }\n        };\n\n        // error during load\n        xhr.onerror = function() {\n            return api.onerror(xhr);\n        };\n\n        // request aborted\n        xhr.onabort = function() {\n            aborted = true;\n            api.onabort();\n        };\n\n        // request timeout\n        xhr.ontimeout = function() {\n            return api.ontimeout(xhr);\n        };\n\n        // open up open up!\n        xhr.open(options.method, url, true);\n\n        // set timeout if defined (do it after open so IE11 plays ball)\n        if (isInt(options.timeout)) {\n            xhr.timeout = options.timeout;\n        }\n\n        // add headers\n        Object.keys(options.headers).forEach(function(key) {\n            var value = unescape(encodeURIComponent(options.headers[key]));\n            xhr.setRequestHeader(key, value);\n        });\n\n        // set type of response\n        if (options.responseType) {\n            xhr.responseType = options.responseType;\n        }\n\n        // set credentials\n        if (options.withCredentials) {\n            xhr.withCredentials = true;\n        }\n\n        // let's send our data\n        xhr.send(data);\n\n        return api;\n    };\n\n    var createResponse = function createResponse(type, code, body, headers) {\n        return {\n            type: type,\n            code: code,\n            body: body,\n            headers: headers,\n        };\n    };\n\n    var createTimeoutResponse = function createTimeoutResponse(cb) {\n        return function(xhr) {\n            cb(createResponse('error', 0, 'Timeout', xhr.getAllResponseHeaders()));\n        };\n    };\n\n    var hasQS = function hasQS(str) {\n        return /\\?/.test(str);\n    };\n    var buildURL = function buildURL() {\n        var url = '';\n        for (var _len = arguments.length, parts = new Array(_len), _key = 0; _key < _len; _key++) {\n            parts[_key] = arguments[_key];\n        }\n        parts.forEach(function(part) {\n            url += hasQS(url) && hasQS(part) ? part.replace(/\\?/, '&') : part;\n        });\n        return url;\n    };\n\n    var createFetchFunction = function createFetchFunction() {\n        var apiUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n        var action = arguments.length > 1 ? arguments[1] : undefined;\n        // custom handler (should also handle file, load, error, progress and abort)\n        if (typeof action === 'function') {\n            return action;\n        }\n\n        // no action supplied\n        if (!action || !isString(action.url)) {\n            return null;\n        }\n\n        // set onload hanlder\n        var onload =\n            action.onload ||\n            function(res) {\n                return res;\n            };\n        var onerror =\n            action.onerror ||\n            function(res) {\n                return null;\n            };\n\n        // internal handler\n        return function(url, load, error, progress, abort, headers) {\n            // do local or remote request based on if the url is external\n            var request = sendRequest(\n                url,\n                buildURL(apiUrl, action.url),\n                Object.assign({}, action, {\n                    responseType: 'blob',\n                })\n            );\n\n            request.onload = function(xhr) {\n                // get headers\n                var headers = xhr.getAllResponseHeaders();\n\n                // get filename\n                var filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n                // create response\n                load(\n                    createResponse(\n                        'load',\n                        xhr.status,\n                        action.method === 'HEAD'\n                            ? null\n                            : getFileFromBlob(onload(xhr.response), filename),\n                        headers\n                    )\n                );\n            };\n\n            request.onerror = function(xhr) {\n                error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.onheaders = function(xhr) {\n                headers(createResponse('headers', xhr.status, null, xhr.getAllResponseHeaders()));\n            };\n\n            request.ontimeout = createTimeoutResponse(error);\n            request.onprogress = progress;\n            request.onabort = abort;\n\n            // should return request\n            return request;\n        };\n    };\n\n    var ChunkStatus = {\n        QUEUED: 0,\n        COMPLETE: 1,\n        PROCESSING: 2,\n        ERROR: 3,\n        WAITING: 4,\n    };\n\n    /*\n                                                       function signature:\n                                                         (file, metadata, load, error, progress, abort, transfer, options) => {\n                                                           return {\n                                                           abort:() => {}\n                                                         }\n                                                       }\n                                                       */\n\n    // apiUrl, action, name, file, metadata, load, error, progress, abort, transfer, options\n    var processFileChunked = function processFileChunked(\n        apiUrl,\n        action,\n        name,\n        file,\n        metadata,\n        load,\n        error,\n        progress,\n        abort,\n        transfer,\n        options\n    ) {\n        // all chunks\n        var chunks = [];\n        var chunkTransferId = options.chunkTransferId,\n            chunkServer = options.chunkServer,\n            chunkSize = options.chunkSize,\n            chunkRetryDelays = options.chunkRetryDelays;\n\n        // default state\n        var state = {\n            serverId: chunkTransferId,\n            aborted: false,\n        };\n\n        // set onload handlers\n        var ondata =\n            action.ondata ||\n            function(fd) {\n                return fd;\n            };\n        var onload =\n            action.onload ||\n            function(xhr, method) {\n                return method === 'HEAD' ? xhr.getResponseHeader('Upload-Offset') : xhr.response;\n            };\n        var onerror =\n            action.onerror ||\n            function(res) {\n                return null;\n            };\n\n        // create server hook\n        var requestTransferId = function requestTransferId(cb) {\n            var formData = new FormData();\n\n            // add metadata under same name\n            if (isObject(metadata)) formData.append(name, JSON.stringify(metadata));\n\n            var headers =\n                typeof action.headers === 'function'\n                    ? action.headers(file, metadata)\n                    : Object.assign(\n                          {},\n\n                          action.headers,\n                          {\n                              'Upload-Length': file.size,\n                          }\n                      );\n\n            var requestParams = Object.assign({}, action, {\n                headers: headers,\n            });\n\n            // send request object\n            var request = sendRequest(\n                ondata(formData),\n                buildURL(apiUrl, action.url),\n                requestParams\n            );\n\n            request.onload = function(xhr) {\n                return cb(onload(xhr, requestParams.method));\n            };\n\n            request.onerror = function(xhr) {\n                return error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.ontimeout = createTimeoutResponse(error);\n        };\n\n        var requestTransferOffset = function requestTransferOffset(cb) {\n            var requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n            var headers =\n                typeof action.headers === 'function'\n                    ? action.headers(state.serverId)\n                    : Object.assign(\n                          {},\n\n                          action.headers\n                      );\n\n            var requestParams = {\n                headers: headers,\n                method: 'HEAD',\n            };\n\n            var request = sendRequest(null, requestUrl, requestParams);\n\n            request.onload = function(xhr) {\n                return cb(onload(xhr, requestParams.method));\n            };\n\n            request.onerror = function(xhr) {\n                return error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.ontimeout = createTimeoutResponse(error);\n        };\n\n        // create chunks\n        var lastChunkIndex = Math.floor(file.size / chunkSize);\n        for (var i = 0; i <= lastChunkIndex; i++) {\n            var offset = i * chunkSize;\n            var data = file.slice(offset, offset + chunkSize, 'application/offset+octet-stream');\n            chunks[i] = {\n                index: i,\n                size: data.size,\n                offset: offset,\n                data: data,\n                file: file,\n                progress: 0,\n                retries: _toConsumableArray(chunkRetryDelays),\n                status: ChunkStatus.QUEUED,\n                error: null,\n                request: null,\n                timeout: null,\n            };\n        }\n\n        var completeProcessingChunks = function completeProcessingChunks() {\n            return load(state.serverId);\n        };\n\n        var canProcessChunk = function canProcessChunk(chunk) {\n            return chunk.status === ChunkStatus.QUEUED || chunk.status === ChunkStatus.ERROR;\n        };\n\n        var processChunk = function processChunk(chunk) {\n            // processing is paused, wait here\n            if (state.aborted) return;\n\n            // get next chunk to process\n            chunk = chunk || chunks.find(canProcessChunk);\n\n            // no more chunks to process\n            if (!chunk) {\n                // all done?\n                if (\n                    chunks.every(function(chunk) {\n                        return chunk.status === ChunkStatus.COMPLETE;\n                    })\n                ) {\n                    completeProcessingChunks();\n                }\n\n                // no chunk to handle\n                return;\n            }\n\n            // now processing this chunk\n            chunk.status = ChunkStatus.PROCESSING;\n            chunk.progress = null;\n\n            // allow parsing of formdata\n            var ondata =\n                chunkServer.ondata ||\n                function(fd) {\n                    return fd;\n                };\n            var onerror =\n                chunkServer.onerror ||\n                function(res) {\n                    return null;\n                };\n            var onload = chunkServer.onload || function() {};\n\n            // send request object\n            var requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n            var headers =\n                typeof chunkServer.headers === 'function'\n                    ? chunkServer.headers(chunk)\n                    : Object.assign(\n                          {},\n\n                          chunkServer.headers,\n                          {\n                              'Content-Type': 'application/offset+octet-stream',\n                              'Upload-Offset': chunk.offset,\n                              'Upload-Length': file.size,\n                              'Upload-Name': file.name,\n                          }\n                      );\n\n            var request = (chunk.request = sendRequest(\n                ondata(chunk.data),\n                requestUrl,\n                Object.assign({}, chunkServer, {\n                    headers: headers,\n                })\n            ));\n\n            request.onload = function(xhr) {\n                // allow hooking into request result\n                onload(xhr, chunk.index, chunks.length);\n\n                // done!\n                chunk.status = ChunkStatus.COMPLETE;\n\n                // remove request reference\n                chunk.request = null;\n\n                // start processing more chunks\n                processChunks();\n            };\n\n            request.onprogress = function(lengthComputable, loaded, total) {\n                chunk.progress = lengthComputable ? loaded : null;\n                updateTotalProgress();\n            };\n\n            request.onerror = function(xhr) {\n                chunk.status = ChunkStatus.ERROR;\n                chunk.request = null;\n                chunk.error = onerror(xhr.response) || xhr.statusText;\n                if (!retryProcessChunk(chunk)) {\n                    error(\n                        createResponse(\n                            'error',\n                            xhr.status,\n                            onerror(xhr.response) || xhr.statusText,\n                            xhr.getAllResponseHeaders()\n                        )\n                    );\n                }\n            };\n\n            request.ontimeout = function(xhr) {\n                chunk.status = ChunkStatus.ERROR;\n                chunk.request = null;\n                if (!retryProcessChunk(chunk)) {\n                    createTimeoutResponse(error)(xhr);\n                }\n            };\n\n            request.onabort = function() {\n                chunk.status = ChunkStatus.QUEUED;\n                chunk.request = null;\n                abort();\n            };\n        };\n\n        var retryProcessChunk = function retryProcessChunk(chunk) {\n            // no more retries left\n            if (chunk.retries.length === 0) return false;\n\n            // new retry\n            chunk.status = ChunkStatus.WAITING;\n            clearTimeout(chunk.timeout);\n            chunk.timeout = setTimeout(function() {\n                processChunk(chunk);\n            }, chunk.retries.shift());\n\n            // we're going to retry\n            return true;\n        };\n\n        var updateTotalProgress = function updateTotalProgress() {\n            // calculate total progress fraction\n            var totalBytesTransfered = chunks.reduce(function(p, chunk) {\n                if (p === null || chunk.progress === null) return null;\n                return p + chunk.progress;\n            }, 0);\n\n            // can't compute progress\n            if (totalBytesTransfered === null) return progress(false, 0, 0);\n\n            // calculate progress values\n            var totalSize = chunks.reduce(function(total, chunk) {\n                return total + chunk.size;\n            }, 0);\n\n            // can update progress indicator\n            progress(true, totalBytesTransfered, totalSize);\n        };\n\n        // process new chunks\n        var processChunks = function processChunks() {\n            var totalProcessing = chunks.filter(function(chunk) {\n                return chunk.status === ChunkStatus.PROCESSING;\n            }).length;\n            if (totalProcessing >= 1) return;\n            processChunk();\n        };\n\n        var abortChunks = function abortChunks() {\n            chunks.forEach(function(chunk) {\n                clearTimeout(chunk.timeout);\n                if (chunk.request) {\n                    chunk.request.abort();\n                }\n            });\n        };\n\n        // let's go!\n        if (!state.serverId) {\n            requestTransferId(function(serverId) {\n                // stop here if aborted, might have happened in between request and callback\n                if (state.aborted) return;\n\n                // pass back to item so we can use it if something goes wrong\n                transfer(serverId);\n\n                // store internally\n                state.serverId = serverId;\n                processChunks();\n            });\n        } else {\n            requestTransferOffset(function(offset) {\n                // stop here if aborted, might have happened in between request and callback\n                if (state.aborted) return;\n\n                // mark chunks with lower offset as complete\n                chunks\n                    .filter(function(chunk) {\n                        return chunk.offset < offset;\n                    })\n                    .forEach(function(chunk) {\n                        chunk.status = ChunkStatus.COMPLETE;\n                        chunk.progress = chunk.size;\n                    });\n\n                // continue processing\n                processChunks();\n            });\n        }\n\n        return {\n            abort: function abort() {\n                state.aborted = true;\n                abortChunks();\n            },\n        };\n    };\n\n    /*\n                                                               function signature:\n                                                                 (file, metadata, load, error, progress, abort) => {\n                                                                   return {\n                                                                   abort:() => {}\n                                                                 }\n                                                               }\n                                                               */\n    var createFileProcessorFunction = function createFileProcessorFunction(\n        apiUrl,\n        action,\n        name,\n        options\n    ) {\n        return function(file, metadata, load, error, progress, abort, transfer) {\n            // no file received\n            if (!file) return;\n\n            // if was passed a file, and we can chunk it, exit here\n            var canChunkUpload = options.chunkUploads;\n            var shouldChunkUpload = canChunkUpload && file.size > options.chunkSize;\n            var willChunkUpload = canChunkUpload && (shouldChunkUpload || options.chunkForce);\n            if (file instanceof Blob && willChunkUpload)\n                return processFileChunked(\n                    apiUrl,\n                    action,\n                    name,\n                    file,\n                    metadata,\n                    load,\n                    error,\n                    progress,\n                    abort,\n                    transfer,\n                    options\n                );\n\n            // set handlers\n            var ondata =\n                action.ondata ||\n                function(fd) {\n                    return fd;\n                };\n            var onload =\n                action.onload ||\n                function(res) {\n                    return res;\n                };\n            var onerror =\n                action.onerror ||\n                function(res) {\n                    return null;\n                };\n\n            var headers =\n                typeof action.headers === 'function'\n                    ? action.headers(file, metadata) || {}\n                    : Object.assign(\n                          {},\n\n                          action.headers\n                      );\n\n            var requestParams = Object.assign({}, action, {\n                headers: headers,\n            });\n\n            // create formdata object\n            var formData = new FormData();\n\n            // add metadata under same name\n            if (isObject(metadata)) {\n                formData.append(name, JSON.stringify(metadata));\n            }\n\n            // Turn into an array of objects so no matter what the input, we can handle it the same way\n            (file instanceof Blob ? [{ name: null, file: file }] : file).forEach(function(item) {\n                formData.append(\n                    name,\n                    item.file,\n                    item.name === null ? item.file.name : '' + item.name + item.file.name\n                );\n            });\n\n            // send request object\n            var request = sendRequest(\n                ondata(formData),\n                buildURL(apiUrl, action.url),\n                requestParams\n            );\n            request.onload = function(xhr) {\n                load(\n                    createResponse(\n                        'load',\n                        xhr.status,\n                        onload(xhr.response),\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.onerror = function(xhr) {\n                error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.ontimeout = createTimeoutResponse(error);\n            request.onprogress = progress;\n            request.onabort = abort;\n\n            // should return request\n            return request;\n        };\n    };\n\n    var createProcessorFunction = function createProcessorFunction() {\n        var apiUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n        var action = arguments.length > 1 ? arguments[1] : undefined;\n        var name = arguments.length > 2 ? arguments[2] : undefined;\n        var options = arguments.length > 3 ? arguments[3] : undefined;\n\n        // custom handler (should also handle file, load, error, progress and abort)\n        if (typeof action === 'function')\n            return function() {\n                for (\n                    var _len = arguments.length, params = new Array(_len), _key = 0;\n                    _key < _len;\n                    _key++\n                ) {\n                    params[_key] = arguments[_key];\n                }\n                return action.apply(void 0, [name].concat(params, [options]));\n            };\n\n        // no action supplied\n        if (!action || !isString(action.url)) return null;\n\n        // internal handler\n        return createFileProcessorFunction(apiUrl, action, name, options);\n    };\n\n    /*\n                                                      function signature:\n                                                      (uniqueFileId, load, error) => { }\n                                                      */\n    var createRevertFunction = function createRevertFunction() {\n        var apiUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n        var action = arguments.length > 1 ? arguments[1] : undefined;\n        // is custom implementation\n        if (typeof action === 'function') {\n            return action;\n        }\n\n        // no action supplied, return stub function, interface will work, but file won't be removed\n        if (!action || !isString(action.url)) {\n            return function(uniqueFileId, load) {\n                return load();\n            };\n        }\n\n        // set onload hanlder\n        var onload =\n            action.onload ||\n            function(res) {\n                return res;\n            };\n        var onerror =\n            action.onerror ||\n            function(res) {\n                return null;\n            };\n\n        // internal implementation\n        return function(uniqueFileId, load, error) {\n            var request = sendRequest(\n                uniqueFileId,\n                apiUrl + action.url,\n                action // contains method, headers and withCredentials properties\n            );\n            request.onload = function(xhr) {\n                load(\n                    createResponse(\n                        'load',\n                        xhr.status,\n                        onload(xhr.response),\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.onerror = function(xhr) {\n                error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            };\n\n            request.ontimeout = createTimeoutResponse(error);\n\n            return request;\n        };\n    };\n\n    var getRandomNumber = function getRandomNumber() {\n        var min = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n        var max = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;\n        return min + Math.random() * (max - min);\n    };\n\n    var createPerceivedPerformanceUpdater = function createPerceivedPerformanceUpdater(cb) {\n        var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;\n        var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n        var tickMin = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 25;\n        var tickMax = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 250;\n        var timeout = null;\n        var start = Date.now();\n\n        var tick = function tick() {\n            var runtime = Date.now() - start;\n            var delay = getRandomNumber(tickMin, tickMax);\n\n            if (runtime + delay > duration) {\n                delay = runtime + delay - duration;\n            }\n\n            var progress = runtime / duration;\n            if (progress >= 1 || document.hidden) {\n                cb(1);\n                return;\n            }\n\n            cb(progress);\n\n            timeout = setTimeout(tick, delay);\n        };\n\n        if (duration > 0) tick();\n\n        return {\n            clear: function clear() {\n                clearTimeout(timeout);\n            },\n        };\n    };\n\n    var createFileProcessor = function createFileProcessor(processFn, options) {\n        var state = {\n            complete: false,\n            perceivedProgress: 0,\n            perceivedPerformanceUpdater: null,\n            progress: null,\n            timestamp: null,\n            perceivedDuration: 0,\n            duration: 0,\n            request: null,\n            response: null,\n        };\n        var allowMinimumUploadDuration = options.allowMinimumUploadDuration;\n\n        var process = function process(file, metadata) {\n            var progressFn = function progressFn() {\n                // we've not yet started the real download, stop here\n                // the request might not go through, for instance, there might be some server trouble\n                // if state.progress is null, the server does not allow computing progress and we show the spinner instead\n                if (state.duration === 0 || state.progress === null) return;\n\n                // as we're now processing, fire the progress event\n                api.fire('progress', api.getProgress());\n            };\n\n            var completeFn = function completeFn() {\n                state.complete = true;\n                api.fire('load-perceived', state.response.body);\n            };\n\n            // let's start processing\n            api.fire('start');\n\n            // set request start\n            state.timestamp = Date.now();\n\n            // create perceived performance progress indicator\n            state.perceivedPerformanceUpdater = createPerceivedPerformanceUpdater(\n                function(progress) {\n                    state.perceivedProgress = progress;\n                    state.perceivedDuration = Date.now() - state.timestamp;\n\n                    progressFn();\n\n                    // if fake progress is done, and a response has been received,\n                    // and we've not yet called the complete method\n                    if (state.response && state.perceivedProgress === 1 && !state.complete) {\n                        // we done!\n                        completeFn();\n                    }\n                },\n                // random delay as in a list of files you start noticing\n                // files uploading at the exact same speed\n                allowMinimumUploadDuration ? getRandomNumber(750, 1500) : 0\n            );\n\n            // remember request so we can abort it later\n            state.request = processFn(\n                // the file to process\n                file,\n\n                // the metadata to send along\n                metadata,\n\n                // callbacks (load, error, progress, abort, transfer)\n                // load expects the body to be a server id if\n                // you want to make use of revert\n                function(response) {\n                    // we put the response in state so we can access\n                    // it outside of this method\n                    state.response = isObject(response)\n                        ? response\n                        : {\n                              type: 'load',\n                              code: 200,\n                              body: '' + response,\n                              headers: {},\n                          };\n\n                    // update duration\n                    state.duration = Date.now() - state.timestamp;\n\n                    // force progress to 1 as we're now done\n                    state.progress = 1;\n\n                    // actual load is done let's share results\n                    api.fire('load', state.response.body);\n\n                    // we are really done\n                    // if perceived progress is 1 ( wait for perceived progress to complete )\n                    // or if server does not support progress ( null )\n                    if (\n                        !allowMinimumUploadDuration ||\n                        (allowMinimumUploadDuration && state.perceivedProgress === 1)\n                    ) {\n                        completeFn();\n                    }\n                },\n\n                // error is expected to be an object with type, code, body\n                function(error) {\n                    // cancel updater\n                    state.perceivedPerformanceUpdater.clear();\n\n                    // update others about this error\n                    api.fire(\n                        'error',\n                        isObject(error)\n                            ? error\n                            : {\n                                  type: 'error',\n                                  code: 0,\n                                  body: '' + error,\n                              }\n                    );\n                },\n\n                // actual processing progress\n                function(computable, current, total) {\n                    // update actual duration\n                    state.duration = Date.now() - state.timestamp;\n\n                    // update actual progress\n                    state.progress = computable ? current / total : null;\n\n                    progressFn();\n                },\n\n                // abort does not expect a value\n                function() {\n                    // stop updater\n                    state.perceivedPerformanceUpdater.clear();\n\n                    // fire the abort event so we can switch visuals\n                    api.fire('abort', state.response ? state.response.body : null);\n                },\n\n                // register the id for this transfer\n                function(transferId) {\n                    api.fire('transfer', transferId);\n                }\n            );\n        };\n\n        var abort = function abort() {\n            // no request running, can't abort\n            if (!state.request) return;\n\n            // stop updater\n            state.perceivedPerformanceUpdater.clear();\n\n            // abort actual request\n            if (state.request.abort) state.request.abort();\n\n            // if has response object, we've completed the request\n            state.complete = true;\n        };\n\n        var reset = function reset() {\n            abort();\n            state.complete = false;\n            state.perceivedProgress = 0;\n            state.progress = 0;\n            state.timestamp = null;\n            state.perceivedDuration = 0;\n            state.duration = 0;\n            state.request = null;\n            state.response = null;\n        };\n\n        var getProgress = allowMinimumUploadDuration\n            ? function() {\n                  return state.progress ? Math.min(state.progress, state.perceivedProgress) : null;\n              }\n            : function() {\n                  return state.progress || null;\n              };\n\n        var getDuration = allowMinimumUploadDuration\n            ? function() {\n                  return Math.min(state.duration, state.perceivedDuration);\n              }\n            : function() {\n                  return state.duration;\n              };\n\n        var api = Object.assign({}, on(), {\n            process: process, // start processing file\n            abort: abort, // abort active process request\n            getProgress: getProgress,\n            getDuration: getDuration,\n            reset: reset,\n        });\n\n        return api;\n    };\n\n    var getFilenameWithoutExtension = function getFilenameWithoutExtension(name) {\n        return name.substring(0, name.lastIndexOf('.')) || name;\n    };\n\n    var createFileStub = function createFileStub(source) {\n        var data = [source.name, source.size, source.type];\n\n        // is blob or base64, then we need to set the name\n        if (source instanceof Blob || isBase64DataURI(source)) {\n            data[0] = source.name || getDateString();\n        } else if (isBase64DataURI(source)) {\n            // if is base64 data uri we need to determine the average size and type\n            data[1] = source.length;\n            data[2] = getMimeTypeFromBase64DataURI(source);\n        } else if (isString(source)) {\n            // url\n            data[0] = getFilenameFromURL(source);\n            data[1] = 0;\n            data[2] = 'application/octet-stream';\n        }\n\n        return {\n            name: data[0],\n            size: data[1],\n            type: data[2],\n        };\n    };\n\n    var isFile = function isFile(value) {\n        return !!(value instanceof File || (value instanceof Blob && value.name));\n    };\n\n    var deepCloneObject = function deepCloneObject(src) {\n        if (!isObject(src)) return src;\n        var target = isArray(src) ? [] : {};\n        for (var key in src) {\n            if (!src.hasOwnProperty(key)) continue;\n            var v = src[key];\n            target[key] = v && isObject(v) ? deepCloneObject(v) : v;\n        }\n        return target;\n    };\n\n    var createItem = function createItem() {\n        var origin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n        var serverFileReference =\n            arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n        var file = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n        // unique id for this item, is used to identify the item across views\n        var id = getUniqueId();\n\n        /**\n         * Internal item state\n         */\n        var state = {\n            // is archived\n            archived: false,\n\n            // if is frozen, no longer fires events\n            frozen: false,\n\n            // removed from view\n            released: false,\n\n            // original source\n            source: null,\n\n            // file model reference\n            file: file,\n\n            // id of file on server\n            serverFileReference: serverFileReference,\n\n            // id of file transfer on server\n            transferId: null,\n\n            // is aborted\n            processingAborted: false,\n\n            // current item status\n            status: serverFileReference ? ItemStatus.PROCESSING_COMPLETE : ItemStatus.INIT,\n\n            // active processes\n            activeLoader: null,\n            activeProcessor: null,\n        };\n\n        // callback used when abort processing is called to link back to the resolve method\n        var abortProcessingRequestComplete = null;\n\n        /**\n         * Externally added item metadata\n         */\n        var metadata = {};\n\n        // item data\n        var setStatus = function setStatus(status) {\n            return (state.status = status);\n        };\n\n        // fire event unless the item has been archived\n        var fire = function fire(event) {\n            if (state.released || state.frozen) return;\n            for (\n                var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1;\n                _key < _len;\n                _key++\n            ) {\n                params[_key - 1] = arguments[_key];\n            }\n            api.fire.apply(api, [event].concat(params));\n        };\n\n        // file data\n        var getFileExtension = function getFileExtension() {\n            return getExtensionFromFilename(state.file.name);\n        };\n        var getFileType = function getFileType() {\n            return state.file.type;\n        };\n        var getFileSize = function getFileSize() {\n            return state.file.size;\n        };\n        var getFile = function getFile() {\n            return state.file;\n        };\n\n        //\n        // logic to load a file\n        //\n        var load = function load(source, loader, onload) {\n            // remember the original item source\n            state.source = source;\n\n            // source is known\n            api.fireSync('init');\n\n            // file stub is already there\n            if (state.file) {\n                api.fireSync('load-skip');\n                return;\n            }\n\n            // set a stub file object while loading the actual data\n            state.file = createFileStub(source);\n\n            // starts loading\n            loader.on('init', function() {\n                fire('load-init');\n            });\n\n            // we'eve received a size indication, let's update the stub\n            loader.on('meta', function(meta) {\n                // set size of file stub\n                state.file.size = meta.size;\n\n                // set name of file stub\n                state.file.filename = meta.filename;\n\n                // if has received source, we done\n                if (meta.source) {\n                    origin = FileOrigin.LIMBO;\n                    state.serverFileReference = meta.source;\n                    state.status = ItemStatus.PROCESSING_COMPLETE;\n                }\n\n                // size has been updated\n                fire('load-meta');\n            });\n\n            // the file is now loading we need to update the progress indicators\n            loader.on('progress', function(progress) {\n                setStatus(ItemStatus.LOADING);\n\n                fire('load-progress', progress);\n            });\n\n            // an error was thrown while loading the file, we need to switch to error state\n            loader.on('error', function(error) {\n                setStatus(ItemStatus.LOAD_ERROR);\n\n                fire('load-request-error', error);\n            });\n\n            // user or another process aborted the file load (cannot retry)\n            loader.on('abort', function() {\n                setStatus(ItemStatus.INIT);\n                fire('load-abort');\n            });\n\n            // done loading\n            loader.on('load', function(file) {\n                // as we've now loaded the file the loader is no longer required\n                state.activeLoader = null;\n\n                // called when file has loaded succesfully\n                var success = function success(result) {\n                    // set (possibly) transformed file\n                    state.file = isFile(result) ? result : state.file;\n\n                    // file received\n                    if (origin === FileOrigin.LIMBO && state.serverFileReference) {\n                        setStatus(ItemStatus.PROCESSING_COMPLETE);\n                    } else {\n                        setStatus(ItemStatus.IDLE);\n                    }\n\n                    fire('load');\n                };\n\n                var error = function error(result) {\n                    // set original file\n                    state.file = file;\n                    fire('load-meta');\n\n                    setStatus(ItemStatus.LOAD_ERROR);\n                    fire('load-file-error', result);\n                };\n\n                // if we already have a server file reference, we don't need to call the onload method\n                if (state.serverFileReference) {\n                    success(file);\n                    return;\n                }\n\n                // no server id, let's give this file the full treatment\n                onload(file, success, error);\n            });\n\n            // set loader source data\n            loader.setSource(source);\n\n            // set as active loader\n            state.activeLoader = loader;\n\n            // load the source data\n            loader.load();\n        };\n\n        var retryLoad = function retryLoad() {\n            if (!state.activeLoader) {\n                return;\n            }\n            state.activeLoader.load();\n        };\n\n        var abortLoad = function abortLoad() {\n            if (state.activeLoader) {\n                state.activeLoader.abort();\n                return;\n            }\n            setStatus(ItemStatus.INIT);\n            fire('load-abort');\n        };\n\n        //\n        // logic to process a file\n        //\n        var process = function process(processor, onprocess) {\n            // processing was aborted\n            if (state.processingAborted) {\n                state.processingAborted = false;\n                return;\n            }\n\n            // now processing\n            setStatus(ItemStatus.PROCESSING);\n\n            // reset abort callback\n            abortProcessingRequestComplete = null;\n\n            // if no file loaded we'll wait for the load event\n            if (!(state.file instanceof Blob)) {\n                api.on('load', function() {\n                    process(processor, onprocess);\n                });\n                return;\n            }\n\n            // setup processor\n            processor.on('load', function(serverFileReference) {\n                // need this id to be able to revert the upload\n                state.transferId = null;\n                state.serverFileReference = serverFileReference;\n            });\n\n            // register transfer id\n            processor.on('transfer', function(transferId) {\n                // need this id to be able to revert the upload\n                state.transferId = transferId;\n            });\n\n            processor.on('load-perceived', function(serverFileReference) {\n                // no longer required\n                state.activeProcessor = null;\n\n                // need this id to be able to rever the upload\n                state.transferId = null;\n                state.serverFileReference = serverFileReference;\n\n                setStatus(ItemStatus.PROCESSING_COMPLETE);\n                fire('process-complete', serverFileReference);\n            });\n\n            processor.on('start', function() {\n                fire('process-start');\n            });\n\n            processor.on('error', function(error) {\n                state.activeProcessor = null;\n                setStatus(ItemStatus.PROCESSING_ERROR);\n                fire('process-error', error);\n            });\n\n            processor.on('abort', function(serverFileReference) {\n                state.activeProcessor = null;\n\n                // if file was uploaded but processing was cancelled during perceived processor time store file reference\n                state.serverFileReference = serverFileReference;\n\n                setStatus(ItemStatus.IDLE);\n                fire('process-abort');\n\n                // has timeout so doesn't interfere with remove action\n                if (abortProcessingRequestComplete) {\n                    abortProcessingRequestComplete();\n                }\n            });\n\n            processor.on('progress', function(progress) {\n                fire('process-progress', progress);\n            });\n\n            // when successfully transformed\n            var success = function success(file) {\n                // if was archived in the mean time, don't process\n                if (state.archived) return;\n\n                // process file!\n                processor.process(file, Object.assign({}, metadata));\n            };\n\n            // something went wrong during transform phase\n            var error = console.error;\n\n            // start processing the file\n            onprocess(state.file, success, error);\n\n            // set as active processor\n            state.activeProcessor = processor;\n        };\n\n        var requestProcessing = function requestProcessing() {\n            state.processingAborted = false;\n            setStatus(ItemStatus.PROCESSING_QUEUED);\n        };\n\n        var abortProcessing = function abortProcessing() {\n            return new Promise(function(resolve) {\n                if (!state.activeProcessor) {\n                    state.processingAborted = true;\n\n                    setStatus(ItemStatus.IDLE);\n                    fire('process-abort');\n\n                    resolve();\n                    return;\n                }\n\n                abortProcessingRequestComplete = function abortProcessingRequestComplete() {\n                    resolve();\n                };\n\n                state.activeProcessor.abort();\n            });\n        };\n\n        //\n        // logic to revert a processed file\n        //\n        var revert = function revert(revertFileUpload, forceRevert) {\n            return new Promise(function(resolve, reject) {\n                // a completed upload will have a serverFileReference, a failed chunked upload where\n                // getting a serverId succeeded but >=0 chunks have been uploaded will have transferId set\n                var serverTransferId =\n                    state.serverFileReference !== null\n                        ? state.serverFileReference\n                        : state.transferId;\n\n                // cannot revert without a server id for this process\n                if (serverTransferId === null) {\n                    resolve();\n                    return;\n                }\n\n                // revert the upload (fire and forget)\n                revertFileUpload(\n                    serverTransferId,\n                    function() {\n                        // reset file server id and transfer id as now it's not available on the server\n                        state.serverFileReference = null;\n                        state.transferId = null;\n                        resolve();\n                    },\n                    function(error) {\n                        // don't set error state when reverting is optional, it will always resolve\n                        if (!forceRevert) {\n                            resolve();\n                            return;\n                        }\n\n                        // oh no errors\n                        setStatus(ItemStatus.PROCESSING_REVERT_ERROR);\n                        fire('process-revert-error');\n                        reject(error);\n                    }\n                );\n\n                // fire event\n                setStatus(ItemStatus.IDLE);\n                fire('process-revert');\n            });\n        };\n\n        // exposed methods\n        var _setMetadata = function setMetadata(key, value, silent) {\n            var keys = key.split('.');\n            var root = keys[0];\n            var last = keys.pop();\n            var data = metadata;\n            keys.forEach(function(key) {\n                return (data = data[key]);\n            });\n\n            // compare old value against new value, if they're the same, we're not updating\n            if (JSON.stringify(data[last]) === JSON.stringify(value)) return;\n\n            // update value\n            data[last] = value;\n\n            // fire update\n            fire('metadata-update', {\n                key: root,\n                value: metadata[root],\n                silent: silent,\n            });\n        };\n\n        var getMetadata = function getMetadata(key) {\n            return deepCloneObject(key ? metadata[key] : metadata);\n        };\n\n        var api = Object.assign(\n            {\n                id: {\n                    get: function get() {\n                        return id;\n                    },\n                },\n                origin: {\n                    get: function get() {\n                        return origin;\n                    },\n                    set: function set(value) {\n                        return (origin = value);\n                    },\n                },\n                serverId: {\n                    get: function get() {\n                        return state.serverFileReference;\n                    },\n                },\n                transferId: {\n                    get: function get() {\n                        return state.transferId;\n                    },\n                },\n                status: {\n                    get: function get() {\n                        return state.status;\n                    },\n                },\n                filename: {\n                    get: function get() {\n                        return state.file.name;\n                    },\n                },\n                filenameWithoutExtension: {\n                    get: function get() {\n                        return getFilenameWithoutExtension(state.file.name);\n                    },\n                },\n                fileExtension: { get: getFileExtension },\n                fileType: { get: getFileType },\n                fileSize: { get: getFileSize },\n                file: { get: getFile },\n                relativePath: {\n                    get: function get() {\n                        return state.file._relativePath;\n                    },\n                },\n\n                source: {\n                    get: function get() {\n                        return state.source;\n                    },\n                },\n\n                getMetadata: getMetadata,\n                setMetadata: function setMetadata(key, value, silent) {\n                    if (isObject(key)) {\n                        var data = key;\n                        Object.keys(data).forEach(function(key) {\n                            _setMetadata(key, data[key], value);\n                        });\n                        return key;\n                    }\n                    _setMetadata(key, value, silent);\n                    return value;\n                },\n\n                extend: function extend(name, handler) {\n                    return (itemAPI[name] = handler);\n                },\n\n                abortLoad: abortLoad,\n                retryLoad: retryLoad,\n                requestProcessing: requestProcessing,\n                abortProcessing: abortProcessing,\n\n                load: load,\n                process: process,\n                revert: revert,\n            },\n\n            on(),\n            {\n                freeze: function freeze() {\n                    return (state.frozen = true);\n                },\n\n                release: function release() {\n                    return (state.released = true);\n                },\n                released: {\n                    get: function get() {\n                        return state.released;\n                    },\n                },\n\n                archive: function archive() {\n                    return (state.archived = true);\n                },\n                archived: {\n                    get: function get() {\n                        return state.archived;\n                    },\n                },\n\n                // replace source and file object\n                setFile: function setFile(file) {\n                    return (state.file = file);\n                },\n            }\n        );\n\n        // create it here instead of returning it instantly so we can extend it later\n        var itemAPI = createObject(api);\n\n        return itemAPI;\n    };\n\n    var getItemIndexByQuery = function getItemIndexByQuery(items, query) {\n        // just return first index\n        if (isEmpty(query)) {\n            return 0;\n        }\n\n        // invalid queries\n        if (!isString(query)) {\n            return -1;\n        }\n\n        // return item by id (or -1 if not found)\n        return items.findIndex(function(item) {\n            return item.id === query;\n        });\n    };\n\n    var getItemById = function getItemById(items, itemId) {\n        var index = getItemIndexByQuery(items, itemId);\n        if (index < 0) {\n            return;\n        }\n        return items[index] || null;\n    };\n\n    var fetchBlob = function fetchBlob(url, load, error, progress, abort, headers) {\n        var request = sendRequest(null, url, {\n            method: 'GET',\n            responseType: 'blob',\n        });\n\n        request.onload = function(xhr) {\n            // get headers\n            var headers = xhr.getAllResponseHeaders();\n\n            // get filename\n            var filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n            // create response\n            load(\n                createResponse('load', xhr.status, getFileFromBlob(xhr.response, filename), headers)\n            );\n        };\n\n        request.onerror = function(xhr) {\n            error(createResponse('error', xhr.status, xhr.statusText, xhr.getAllResponseHeaders()));\n        };\n\n        request.onheaders = function(xhr) {\n            headers(createResponse('headers', xhr.status, null, xhr.getAllResponseHeaders()));\n        };\n\n        request.ontimeout = createTimeoutResponse(error);\n        request.onprogress = progress;\n        request.onabort = abort;\n\n        // should return request\n        return request;\n    };\n\n    var getDomainFromURL = function getDomainFromURL(url) {\n        if (url.indexOf('//') === 0) {\n            url = location.protocol + url;\n        }\n        return url\n            .toLowerCase()\n            .replace('blob:', '')\n            .replace(/([a-z])?:\\/\\//, '$1')\n            .split('/')[0];\n    };\n\n    var isExternalURL = function isExternalURL(url) {\n        return (\n            (url.indexOf(':') > -1 || url.indexOf('//') > -1) &&\n            getDomainFromURL(location.href) !== getDomainFromURL(url)\n        );\n    };\n\n    var dynamicLabel = function dynamicLabel(label) {\n        return function() {\n            return isFunction(label) ? label.apply(void 0, arguments) : label;\n        };\n    };\n\n    var isMockItem = function isMockItem(item) {\n        return !isFile(item.file);\n    };\n\n    var listUpdated = function listUpdated(dispatch, state) {\n        clearTimeout(state.listUpdateTimeout);\n        state.listUpdateTimeout = setTimeout(function() {\n            dispatch('DID_UPDATE_ITEMS', { items: getActiveItems(state.items) });\n        }, 0);\n    };\n\n    var optionalPromise = function optionalPromise(fn) {\n        for (\n            var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1;\n            _key < _len;\n            _key++\n        ) {\n            params[_key - 1] = arguments[_key];\n        }\n        return new Promise(function(resolve) {\n            if (!fn) {\n                return resolve(true);\n            }\n\n            var result = fn.apply(void 0, params);\n\n            if (result == null) {\n                return resolve(true);\n            }\n\n            if (typeof result === 'boolean') {\n                return resolve(result);\n            }\n\n            if (typeof result.then === 'function') {\n                result.then(resolve);\n            }\n        });\n    };\n\n    var sortItems = function sortItems(state, compare) {\n        state.items.sort(function(a, b) {\n            return compare(createItemAPI(a), createItemAPI(b));\n        });\n    };\n\n    // returns item based on state\n    var getItemByQueryFromState = function getItemByQueryFromState(state, itemHandler) {\n        return function() {\n            var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n            var query = _ref.query,\n                _ref$success = _ref.success,\n                success = _ref$success === void 0 ? function() {} : _ref$success,\n                _ref$failure = _ref.failure,\n                failure = _ref$failure === void 0 ? function() {} : _ref$failure,\n                options = _objectWithoutProperties(_ref, ['query', 'success', 'failure']);\n            var item = getItemByQuery(state.items, query);\n            if (!item) {\n                failure({\n                    error: createResponse('error', 0, 'Item not found'),\n                    file: null,\n                });\n\n                return;\n            }\n            itemHandler(item, success, failure, options || {});\n        };\n    };\n\n    var actions = function actions(dispatch, query, state) {\n        return {\n            /**\n             * Aborts all ongoing processes\n             */\n            ABORT_ALL: function ABORT_ALL() {\n                getActiveItems(state.items).forEach(function(item) {\n                    item.freeze();\n                    item.abortLoad();\n                    item.abortProcessing();\n                });\n            },\n\n            /**\n             * Sets initial files\n             */\n            DID_SET_FILES: function DID_SET_FILES(_ref2) {\n                var _ref2$value = _ref2.value,\n                    value = _ref2$value === void 0 ? [] : _ref2$value;\n                // map values to file objects\n                var files = value.map(function(file) {\n                    return {\n                        source: file.source ? file.source : file,\n                        options: file.options,\n                    };\n                });\n\n                // loop over files, if file is in list, leave it be, if not, remove\n                // test if items should be moved\n                var activeItems = getActiveItems(state.items);\n\n                activeItems.forEach(function(item) {\n                    // if item not is in new value, remove\n                    if (\n                        !files.find(function(file) {\n                            return file.source === item.source || file.source === item.file;\n                        })\n                    ) {\n                        dispatch('REMOVE_ITEM', { query: item, remove: false });\n                    }\n                });\n\n                // add new files\n                activeItems = getActiveItems(state.items);\n                files.forEach(function(file, index) {\n                    // if file is already in list\n                    if (\n                        activeItems.find(function(item) {\n                            return item.source === file.source || item.file === file.source;\n                        })\n                    )\n                        return;\n\n                    // not in list, add\n                    dispatch(\n                        'ADD_ITEM',\n                        Object.assign({}, file, {\n                            interactionMethod: InteractionMethod.NONE,\n                            index: index,\n                        })\n                    );\n                });\n            },\n\n            DID_UPDATE_ITEM_METADATA: function DID_UPDATE_ITEM_METADATA(_ref3) {\n                var id = _ref3.id,\n                    action = _ref3.action,\n                    change = _ref3.change;\n                // don't do anything\n                if (change.silent) return;\n\n                // if is called multiple times in close succession we combined all calls together to save resources\n                clearTimeout(state.itemUpdateTimeout);\n                state.itemUpdateTimeout = setTimeout(function() {\n                    var item = getItemById(state.items, id);\n\n                    // only revert and attempt to upload when we're uploading to a server\n                    if (!query('IS_ASYNC')) {\n                        // should we update the output data\n                        applyFilterChain('SHOULD_PREPARE_OUTPUT', false, {\n                            item: item,\n                            query: query,\n                            action: action,\n                            change: change,\n                        }).then(function(shouldPrepareOutput) {\n                            // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                            var beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                            if (beforePrepareFile)\n                                shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                            if (!shouldPrepareOutput) return;\n\n                            dispatch(\n                                'REQUEST_PREPARE_OUTPUT',\n                                {\n                                    query: id,\n                                    item: item,\n                                    success: function success(file) {\n                                        dispatch('DID_PREPARE_OUTPUT', { id: id, file: file });\n                                    },\n                                },\n\n                                true\n                            );\n                        });\n\n                        return;\n                    }\n\n                    // if is local item we need to enable upload button so change can be propagated to server\n                    if (item.origin === FileOrigin.LOCAL) {\n                        dispatch('DID_LOAD_ITEM', {\n                            id: item.id,\n                            error: null,\n                            serverFileReference: item.source,\n                        });\n                    }\n\n                    // for async scenarios\n                    var upload = function upload() {\n                        // we push this forward a bit so the interface is updated correctly\n                        setTimeout(function() {\n                            dispatch('REQUEST_ITEM_PROCESSING', { query: id });\n                        }, 32);\n                    };\n\n                    var revert = function revert(doUpload) {\n                        item.revert(\n                            createRevertFunction(\n                                state.options.server.url,\n                                state.options.server.revert\n                            ),\n                            query('GET_FORCE_REVERT')\n                        )\n                            .then(doUpload ? upload : function() {})\n                            .catch(function() {});\n                    };\n\n                    var abort = function abort(doUpload) {\n                        item.abortProcessing().then(doUpload ? upload : function() {});\n                    };\n\n                    // if we should re-upload the file immediately\n                    if (item.status === ItemStatus.PROCESSING_COMPLETE) {\n                        return revert(state.options.instantUpload);\n                    }\n\n                    // if currently uploading, cancel upload\n                    if (item.status === ItemStatus.PROCESSING) {\n                        return abort(state.options.instantUpload);\n                    }\n\n                    if (state.options.instantUpload) {\n                        upload();\n                    }\n                }, 0);\n            },\n\n            MOVE_ITEM: function MOVE_ITEM(_ref4) {\n                var query = _ref4.query,\n                    index = _ref4.index;\n                var item = getItemByQuery(state.items, query);\n                if (!item) return;\n                var currentIndex = state.items.indexOf(item);\n                index = limit(index, 0, state.items.length - 1);\n                if (currentIndex === index) return;\n                state.items.splice(index, 0, state.items.splice(currentIndex, 1)[0]);\n            },\n\n            SORT: function SORT(_ref5) {\n                var compare = _ref5.compare;\n                sortItems(state, compare);\n                dispatch('DID_SORT_ITEMS', {\n                    items: query('GET_ACTIVE_ITEMS'),\n                });\n            },\n\n            ADD_ITEMS: function ADD_ITEMS(_ref6) {\n                var items = _ref6.items,\n                    index = _ref6.index,\n                    interactionMethod = _ref6.interactionMethod,\n                    _ref6$success = _ref6.success,\n                    success = _ref6$success === void 0 ? function() {} : _ref6$success,\n                    _ref6$failure = _ref6.failure,\n                    failure = _ref6$failure === void 0 ? function() {} : _ref6$failure;\n                var currentIndex = index;\n\n                if (index === -1 || typeof index === 'undefined') {\n                    var insertLocation = query('GET_ITEM_INSERT_LOCATION');\n                    var totalItems = query('GET_TOTAL_ITEMS');\n                    currentIndex = insertLocation === 'before' ? 0 : totalItems;\n                }\n\n                var ignoredFiles = query('GET_IGNORED_FILES');\n                var isValidFile = function isValidFile(source) {\n                    return isFile(source)\n                        ? !ignoredFiles.includes(source.name.toLowerCase())\n                        : !isEmpty(source);\n                };\n                var validItems = items.filter(isValidFile);\n\n                var promises = validItems.map(function(source) {\n                    return new Promise(function(resolve, reject) {\n                        dispatch('ADD_ITEM', {\n                            interactionMethod: interactionMethod,\n                            source: source.source || source,\n                            success: resolve,\n                            failure: reject,\n                            index: currentIndex++,\n                            options: source.options || {},\n                        });\n                    });\n                });\n\n                Promise.all(promises)\n                    .then(success)\n                    .catch(failure);\n            },\n\n            /**\n             * @param source\n             * @param index\n             * @param interactionMethod\n             */\n            ADD_ITEM: function ADD_ITEM(_ref7) {\n                var source = _ref7.source,\n                    _ref7$index = _ref7.index,\n                    index = _ref7$index === void 0 ? -1 : _ref7$index,\n                    interactionMethod = _ref7.interactionMethod,\n                    _ref7$success = _ref7.success,\n                    success = _ref7$success === void 0 ? function() {} : _ref7$success,\n                    _ref7$failure = _ref7.failure,\n                    failure = _ref7$failure === void 0 ? function() {} : _ref7$failure,\n                    _ref7$options = _ref7.options,\n                    options = _ref7$options === void 0 ? {} : _ref7$options;\n                // if no source supplied\n                if (isEmpty(source)) {\n                    failure({\n                        error: createResponse('error', 0, 'No source'),\n                        file: null,\n                    });\n\n                    return;\n                }\n\n                // filter out invalid file items, used to filter dropped directory contents\n                if (\n                    isFile(source) &&\n                    state.options.ignoredFiles.includes(source.name.toLowerCase())\n                ) {\n                    // fail silently\n                    return;\n                }\n\n                // test if there's still room in the list of files\n                if (!hasRoomForItem(state)) {\n                    // if multiple allowed, we can't replace\n                    // or if only a single item is allowed but we're not allowed to replace it we exit\n                    if (\n                        state.options.allowMultiple ||\n                        (!state.options.allowMultiple && !state.options.allowReplace)\n                    ) {\n                        var error = createResponse('warning', 0, 'Max files');\n\n                        dispatch('DID_THROW_MAX_FILES', {\n                            source: source,\n                            error: error,\n                        });\n\n                        failure({ error: error, file: null });\n\n                        return;\n                    }\n\n                    // let's replace the item\n                    // id of first item we're about to remove\n                    var _item = getActiveItems(state.items)[0];\n\n                    // if has been processed remove it from the server as well\n                    if (\n                        _item.status === ItemStatus.PROCESSING_COMPLETE ||\n                        _item.status === ItemStatus.PROCESSING_REVERT_ERROR\n                    ) {\n                        var forceRevert = query('GET_FORCE_REVERT');\n                        _item\n                            .revert(\n                                createRevertFunction(\n                                    state.options.server.url,\n                                    state.options.server.revert\n                                ),\n                                forceRevert\n                            )\n                            .then(function() {\n                                if (!forceRevert) return;\n\n                                // try to add now\n                                dispatch('ADD_ITEM', {\n                                    source: source,\n                                    index: index,\n                                    interactionMethod: interactionMethod,\n                                    success: success,\n                                    failure: failure,\n                                    options: options,\n                                });\n                            })\n                            .catch(function() {}); // no need to handle this catch state for now\n\n                        if (forceRevert) return;\n                    }\n\n                    // remove first item as it will be replaced by this item\n                    dispatch('REMOVE_ITEM', { query: _item.id });\n                }\n\n                // where did the file originate\n                var origin =\n                    options.type === 'local'\n                        ? FileOrigin.LOCAL\n                        : options.type === 'limbo'\n                        ? FileOrigin.LIMBO\n                        : FileOrigin.INPUT;\n\n                // create a new blank item\n                var item = createItem(\n                    // where did this file come from\n                    origin,\n\n                    // an input file never has a server file reference\n                    origin === FileOrigin.INPUT ? null : source,\n\n                    // file mock data, if defined\n                    options.file\n                );\n\n                // set initial meta data\n                Object.keys(options.metadata || {}).forEach(function(key) {\n                    item.setMetadata(key, options.metadata[key]);\n                });\n\n                // created the item, let plugins add methods\n                applyFilters('DID_CREATE_ITEM', item, { query: query, dispatch: dispatch });\n\n                // where to insert new items\n                var itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n\n                // adjust index if is not allowed to pick location\n                if (!state.options.itemInsertLocationFreedom) {\n                    index = itemInsertLocation === 'before' ? -1 : state.items.length;\n                }\n\n                // add item to list\n                insertItem(state.items, item, index);\n\n                // sort items in list\n                if (isFunction(itemInsertLocation) && source) {\n                    sortItems(state, itemInsertLocation);\n                }\n\n                // get a quick reference to the item id\n                var id = item.id;\n\n                // observe item events\n                item.on('init', function() {\n                    dispatch('DID_INIT_ITEM', { id: id });\n                });\n\n                item.on('load-init', function() {\n                    dispatch('DID_START_ITEM_LOAD', { id: id });\n                });\n\n                item.on('load-meta', function() {\n                    dispatch('DID_UPDATE_ITEM_META', { id: id });\n                });\n\n                item.on('load-progress', function(progress) {\n                    dispatch('DID_UPDATE_ITEM_LOAD_PROGRESS', { id: id, progress: progress });\n                });\n\n                item.on('load-request-error', function(error) {\n                    var mainStatus = dynamicLabel(state.options.labelFileLoadError)(error);\n\n                    // is client error, no way to recover\n                    if (error.code >= 400 && error.code < 500) {\n                        dispatch('DID_THROW_ITEM_INVALID', {\n                            id: id,\n                            error: error,\n                            status: {\n                                main: mainStatus,\n                                sub: error.code + ' (' + error.body + ')',\n                            },\n                        });\n\n                        // reject the file so can be dealt with through API\n                        failure({ error: error, file: createItemAPI(item) });\n                        return;\n                    }\n\n                    // is possible server error, so might be possible to retry\n                    dispatch('DID_THROW_ITEM_LOAD_ERROR', {\n                        id: id,\n                        error: error,\n                        status: {\n                            main: mainStatus,\n                            sub: state.options.labelTapToRetry,\n                        },\n                    });\n                });\n\n                item.on('load-file-error', function(error) {\n                    dispatch('DID_THROW_ITEM_INVALID', {\n                        id: id,\n                        error: error.status,\n                        status: error.status,\n                    });\n\n                    failure({ error: error.status, file: createItemAPI(item) });\n                });\n\n                item.on('load-abort', function() {\n                    dispatch('REMOVE_ITEM', { query: id });\n                });\n\n                item.on('load-skip', function() {\n                    item.on('metadata-update', function(change) {\n                        if (!isFile(item.file)) return;\n                        dispatch('DID_UPDATE_ITEM_METADATA', { id: id, change: change });\n                    });\n\n                    dispatch('COMPLETE_LOAD_ITEM', {\n                        query: id,\n                        item: item,\n                        data: {\n                            source: source,\n                            success: success,\n                        },\n                    });\n                });\n\n                item.on('load', function() {\n                    var handleAdd = function handleAdd(shouldAdd) {\n                        // no should not add this file\n                        if (!shouldAdd) {\n                            dispatch('REMOVE_ITEM', {\n                                query: id,\n                            });\n\n                            return;\n                        }\n\n                        // now interested in metadata updates\n                        item.on('metadata-update', function(change) {\n                            dispatch('DID_UPDATE_ITEM_METADATA', { id: id, change: change });\n                        });\n\n                        // let plugins decide if the output data should be prepared at this point\n                        // means we'll do this and wait for idle state\n                        applyFilterChain('SHOULD_PREPARE_OUTPUT', false, {\n                            item: item,\n                            query: query,\n                        }).then(function(shouldPrepareOutput) {\n                            // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                            var beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                            if (beforePrepareFile)\n                                shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                            var loadComplete = function loadComplete() {\n                                dispatch('COMPLETE_LOAD_ITEM', {\n                                    query: id,\n                                    item: item,\n                                    data: {\n                                        source: source,\n                                        success: success,\n                                    },\n                                });\n\n                                listUpdated(dispatch, state);\n                            };\n\n                            // exit\n                            if (shouldPrepareOutput) {\n                                // wait for idle state and then run PREPARE_OUTPUT\n                                dispatch(\n                                    'REQUEST_PREPARE_OUTPUT',\n                                    {\n                                        query: id,\n                                        item: item,\n                                        success: function success(file) {\n                                            dispatch('DID_PREPARE_OUTPUT', { id: id, file: file });\n                                            loadComplete();\n                                        },\n                                    },\n\n                                    true\n                                );\n\n                                return;\n                            }\n\n                            loadComplete();\n                        });\n                    };\n\n                    // item loaded, allow plugins to\n                    // - read data (quickly)\n                    // - add metadata\n                    applyFilterChain('DID_LOAD_ITEM', item, { query: query, dispatch: dispatch })\n                        .then(function() {\n                            optionalPromise(query('GET_BEFORE_ADD_FILE'), createItemAPI(item)).then(\n                                handleAdd\n                            );\n                        })\n                        .catch(function(e) {\n                            if (!e || !e.error || !e.status) return handleAdd(false);\n                            dispatch('DID_THROW_ITEM_INVALID', {\n                                id: id,\n                                error: e.error,\n                                status: e.status,\n                            });\n                        });\n                });\n\n                item.on('process-start', function() {\n                    dispatch('DID_START_ITEM_PROCESSING', { id: id });\n                });\n\n                item.on('process-progress', function(progress) {\n                    dispatch('DID_UPDATE_ITEM_PROCESS_PROGRESS', { id: id, progress: progress });\n                });\n\n                item.on('process-error', function(error) {\n                    dispatch('DID_THROW_ITEM_PROCESSING_ERROR', {\n                        id: id,\n                        error: error,\n                        status: {\n                            main: dynamicLabel(state.options.labelFileProcessingError)(error),\n                            sub: state.options.labelTapToRetry,\n                        },\n                    });\n                });\n\n                item.on('process-revert-error', function(error) {\n                    dispatch('DID_THROW_ITEM_PROCESSING_REVERT_ERROR', {\n                        id: id,\n                        error: error,\n                        status: {\n                            main: dynamicLabel(state.options.labelFileProcessingRevertError)(error),\n                            sub: state.options.labelTapToRetry,\n                        },\n                    });\n                });\n\n                item.on('process-complete', function(serverFileReference) {\n                    dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                        id: id,\n                        error: null,\n                        serverFileReference: serverFileReference,\n                    });\n\n                    dispatch('DID_DEFINE_VALUE', { id: id, value: serverFileReference });\n                });\n\n                item.on('process-abort', function() {\n                    dispatch('DID_ABORT_ITEM_PROCESSING', { id: id });\n                });\n\n                item.on('process-revert', function() {\n                    dispatch('DID_REVERT_ITEM_PROCESSING', { id: id });\n                    dispatch('DID_DEFINE_VALUE', { id: id, value: null });\n                });\n\n                // let view know the item has been inserted\n                dispatch('DID_ADD_ITEM', {\n                    id: id,\n                    index: index,\n                    interactionMethod: interactionMethod,\n                });\n\n                listUpdated(dispatch, state);\n\n                // start loading the source\n                var _ref8 = state.options.server || {},\n                    url = _ref8.url,\n                    load = _ref8.load,\n                    restore = _ref8.restore,\n                    fetch = _ref8.fetch;\n\n                item.load(\n                    source,\n\n                    // this creates a function that loads the file based on the type of file (string, base64, blob, file) and location of file (local, remote, limbo)\n                    createFileLoader(\n                        origin === FileOrigin.INPUT\n                            ? // input, if is remote, see if should use custom fetch, else use default fetchBlob\n                              isString(source) && isExternalURL(source)\n                                ? fetch\n                                    ? createFetchFunction(url, fetch)\n                                    : fetchBlob // remote url\n                                : fetchBlob // try to fetch url\n                            : // limbo or local\n                            origin === FileOrigin.LIMBO\n                            ? createFetchFunction(url, restore) // limbo\n                            : createFetchFunction(url, load) // local\n                    ),\n\n                    // called when the file is loaded so it can be piped through the filters\n                    function(file, success, error) {\n                        // let's process the file\n                        applyFilterChain('LOAD_FILE', file, { query: query })\n                            .then(success)\n                            .catch(error);\n                    }\n                );\n            },\n\n            REQUEST_PREPARE_OUTPUT: function REQUEST_PREPARE_OUTPUT(_ref9) {\n                var item = _ref9.item,\n                    success = _ref9.success,\n                    _ref9$failure = _ref9.failure,\n                    failure = _ref9$failure === void 0 ? function() {} : _ref9$failure;\n                // error response if item archived\n                var err = {\n                    error: createResponse('error', 0, 'Item not found'),\n                    file: null,\n                };\n\n                // don't handle archived items, an item could have been archived (load aborted) while waiting to be prepared\n                if (item.archived) return failure(err);\n\n                // allow plugins to alter the file data\n                applyFilterChain('PREPARE_OUTPUT', item.file, { query: query, item: item }).then(\n                    function(result) {\n                        applyFilterChain('COMPLETE_PREPARE_OUTPUT', result, {\n                            query: query,\n                            item: item,\n                        }).then(function(result) {\n                            // don't handle archived items, an item could have been archived (load aborted) while being prepared\n                            if (item.archived) return failure(err);\n\n                            // we done!\n                            success(result);\n                        });\n                    }\n                );\n            },\n\n            COMPLETE_LOAD_ITEM: function COMPLETE_LOAD_ITEM(_ref10) {\n                var item = _ref10.item,\n                    data = _ref10.data;\n                var success = data.success,\n                    source = data.source;\n\n                // sort items in list\n                var itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n                if (isFunction(itemInsertLocation) && source) {\n                    sortItems(state, itemInsertLocation);\n                }\n\n                // let interface know the item has loaded\n                dispatch('DID_LOAD_ITEM', {\n                    id: item.id,\n                    error: null,\n                    serverFileReference: item.origin === FileOrigin.INPUT ? null : source,\n                });\n\n                // item has been successfully loaded and added to the\n                // list of items so can now be safely returned for use\n                success(createItemAPI(item));\n\n                // if this is a local server file we need to show a different state\n                if (item.origin === FileOrigin.LOCAL) {\n                    dispatch('DID_LOAD_LOCAL_ITEM', { id: item.id });\n                    return;\n                }\n\n                // if is a temp server file we prevent async upload call here (as the file is already on the server)\n                if (item.origin === FileOrigin.LIMBO) {\n                    dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                        id: item.id,\n                        error: null,\n                        serverFileReference: source,\n                    });\n\n                    dispatch('DID_DEFINE_VALUE', {\n                        id: item.id,\n                        value: item.serverId || source,\n                    });\n\n                    return;\n                }\n\n                // id we are allowed to upload the file immediately, lets do it\n                if (query('IS_ASYNC') && state.options.instantUpload) {\n                    dispatch('REQUEST_ITEM_PROCESSING', { query: item.id });\n                }\n            },\n\n            RETRY_ITEM_LOAD: getItemByQueryFromState(state, function(item) {\n                // try loading the source one more time\n                item.retryLoad();\n            }),\n\n            REQUEST_ITEM_PREPARE: getItemByQueryFromState(state, function(item, _success, failure) {\n                dispatch(\n                    'REQUEST_PREPARE_OUTPUT',\n                    {\n                        query: item.id,\n                        item: item,\n                        success: function success(file) {\n                            dispatch('DID_PREPARE_OUTPUT', { id: item.id, file: file });\n                            _success({\n                                file: item,\n                                output: file,\n                            });\n                        },\n                        failure: failure,\n                    },\n\n                    true\n                );\n            }),\n\n            REQUEST_ITEM_PROCESSING: getItemByQueryFromState(state, function(\n                item,\n                success,\n                failure\n            ) {\n                // cannot be queued (or is already queued)\n                var itemCanBeQueuedForProcessing =\n                    // waiting for something\n                    item.status === ItemStatus.IDLE ||\n                    // processing went wrong earlier\n                    item.status === ItemStatus.PROCESSING_ERROR;\n\n                // not ready to be processed\n                if (!itemCanBeQueuedForProcessing) {\n                    var processNow = function processNow() {\n                        return dispatch('REQUEST_ITEM_PROCESSING', {\n                            query: item,\n                            success: success,\n                            failure: failure,\n                        });\n                    };\n\n                    var process = function process() {\n                        return document.hidden ? processNow() : setTimeout(processNow, 32);\n                    };\n\n                    // if already done processing or tried to revert but didn't work, try again\n                    if (\n                        item.status === ItemStatus.PROCESSING_COMPLETE ||\n                        item.status === ItemStatus.PROCESSING_REVERT_ERROR\n                    ) {\n                        item.revert(\n                            createRevertFunction(\n                                state.options.server.url,\n                                state.options.server.revert\n                            ),\n                            query('GET_FORCE_REVERT')\n                        )\n                            .then(process)\n                            .catch(function() {}); // don't continue with processing if something went wrong\n                    } else if (item.status === ItemStatus.PROCESSING) {\n                        item.abortProcessing().then(process);\n                    }\n\n                    return;\n                }\n\n                // already queued for processing\n                if (item.status === ItemStatus.PROCESSING_QUEUED) return;\n\n                item.requestProcessing();\n\n                dispatch('DID_REQUEST_ITEM_PROCESSING', { id: item.id });\n\n                dispatch('PROCESS_ITEM', { query: item, success: success, failure: failure }, true);\n            }),\n\n            PROCESS_ITEM: getItemByQueryFromState(state, function(item, success, failure) {\n                var maxParallelUploads = query('GET_MAX_PARALLEL_UPLOADS');\n                var totalCurrentUploads = query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING)\n                    .length;\n\n                // queue and wait till queue is freed up\n                if (totalCurrentUploads === maxParallelUploads) {\n                    // queue for later processing\n                    state.processingQueue.push({\n                        id: item.id,\n                        success: success,\n                        failure: failure,\n                    });\n\n                    // stop it!\n                    return;\n                }\n\n                // if was not queued or is already processing exit here\n                if (item.status === ItemStatus.PROCESSING) return;\n\n                var processNext = function processNext() {\n                    // process queueud items\n                    var queueEntry = state.processingQueue.shift();\n\n                    // no items left\n                    if (!queueEntry) return;\n\n                    // get item reference\n                    var id = queueEntry.id,\n                        success = queueEntry.success,\n                        failure = queueEntry.failure;\n                    var itemReference = getItemByQuery(state.items, id);\n\n                    // if item was archived while in queue, jump to next\n                    if (!itemReference || itemReference.archived) {\n                        processNext();\n                        return;\n                    }\n\n                    // process queued item\n                    dispatch(\n                        'PROCESS_ITEM',\n                        { query: id, success: success, failure: failure },\n                        true\n                    );\n                };\n\n                // we done function\n                item.onOnce('process-complete', function() {\n                    success(createItemAPI(item));\n                    processNext();\n\n                    // if origin is local, and we're instant uploading, trigger remove of original\n                    // as revert will remove file from list\n                    var server = state.options.server;\n                    var instantUpload = state.options.instantUpload;\n                    if (\n                        instantUpload &&\n                        item.origin === FileOrigin.LOCAL &&\n                        isFunction(server.remove)\n                    ) {\n                        var noop = function noop() {};\n                        item.origin = FileOrigin.LIMBO;\n                        state.options.server.remove(item.source, noop, noop);\n                    }\n\n                    // All items processed? No errors?\n                    var allItemsProcessed =\n                        query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING_COMPLETE).length ===\n                        state.items.length;\n                    if (allItemsProcessed) {\n                        dispatch('DID_COMPLETE_ITEM_PROCESSING_ALL');\n                    }\n                });\n\n                // we error function\n                item.onOnce('process-error', function(error) {\n                    failure({ error: error, file: createItemAPI(item) });\n                    processNext();\n                });\n\n                // abort function\n                item.onOnce('process-abort', function() {\n                    processNext();\n                });\n\n                // start file processing\n                var options = state.options;\n                item.process(\n                    createFileProcessor(\n                        createProcessorFunction(\n                            options.server.url,\n                            options.server.process,\n                            options.name,\n                            {\n                                chunkTransferId: item.transferId,\n                                chunkServer: options.server.patch,\n                                chunkUploads: options.chunkUploads,\n                                chunkForce: options.chunkForce,\n                                chunkSize: options.chunkSize,\n                                chunkRetryDelays: options.chunkRetryDelays,\n                            }\n                        ),\n\n                        {\n                            allowMinimumUploadDuration: query('GET_ALLOW_MINIMUM_UPLOAD_DURATION'),\n                        }\n                    ),\n\n                    // called when the file is about to be processed so it can be piped through the transform filters\n                    function(file, success, error) {\n                        // allow plugins to alter the file data\n                        applyFilterChain('PREPARE_OUTPUT', file, { query: query, item: item })\n                            .then(function(file) {\n                                dispatch('DID_PREPARE_OUTPUT', { id: item.id, file: file });\n\n                                success(file);\n                            })\n                            .catch(error);\n                    }\n                );\n            }),\n\n            RETRY_ITEM_PROCESSING: getItemByQueryFromState(state, function(item) {\n                dispatch('REQUEST_ITEM_PROCESSING', { query: item });\n            }),\n\n            REQUEST_REMOVE_ITEM: getItemByQueryFromState(state, function(item) {\n                optionalPromise(query('GET_BEFORE_REMOVE_FILE'), createItemAPI(item)).then(function(\n                    shouldRemove\n                ) {\n                    if (!shouldRemove) {\n                        return;\n                    }\n                    dispatch('REMOVE_ITEM', { query: item });\n                });\n            }),\n\n            RELEASE_ITEM: getItemByQueryFromState(state, function(item) {\n                item.release();\n            }),\n\n            REMOVE_ITEM: getItemByQueryFromState(state, function(item, success, failure, options) {\n                var removeFromView = function removeFromView() {\n                    // get id reference\n                    var id = item.id;\n\n                    // archive the item, this does not remove it from the list\n                    getItemById(state.items, id).archive();\n\n                    // tell the view the item has been removed\n                    dispatch('DID_REMOVE_ITEM', { error: null, id: id, item: item });\n\n                    // now the list has been modified\n                    listUpdated(dispatch, state);\n\n                    // correctly removed\n                    success(createItemAPI(item));\n                };\n\n                // if this is a local file and the `server.remove` function has been configured,\n                // send source there so dev can remove file from server\n                var server = state.options.server;\n                if (\n                    item.origin === FileOrigin.LOCAL &&\n                    server &&\n                    isFunction(server.remove) &&\n                    options.remove !== false\n                ) {\n                    dispatch('DID_START_ITEM_REMOVE', { id: item.id });\n\n                    server.remove(\n                        item.source,\n                        function() {\n                            return removeFromView();\n                        },\n                        function(status) {\n                            dispatch('DID_THROW_ITEM_REMOVE_ERROR', {\n                                id: item.id,\n                                error: createResponse('error', 0, status, null),\n                                status: {\n                                    main: dynamicLabel(state.options.labelFileRemoveError)(status),\n                                    sub: state.options.labelTapToRetry,\n                                },\n                            });\n                        }\n                    );\n                } else {\n                    // if is requesting revert and can revert need to call revert handler (not calling request_ because that would also trigger beforeRemoveHook)\n                    if (\n                        (options.revert &&\n                            item.origin !== FileOrigin.LOCAL &&\n                            item.serverId !== null) ||\n                        // if chunked uploads are enabled and we're uploading in chunks for this specific file\n                        // or if the file isn't big enough for chunked uploads but chunkForce is set then call\n                        // revert before removing from the view...\n                        (state.options.chunkUploads && item.file.size > state.options.chunkSize) ||\n                        (state.options.chunkUploads && state.options.chunkForce)\n                    ) {\n                        item.revert(\n                            createRevertFunction(\n                                state.options.server.url,\n                                state.options.server.revert\n                            ),\n                            query('GET_FORCE_REVERT')\n                        );\n                    }\n\n                    // can now safely remove from view\n                    removeFromView();\n                }\n            }),\n\n            ABORT_ITEM_LOAD: getItemByQueryFromState(state, function(item) {\n                item.abortLoad();\n            }),\n\n            ABORT_ITEM_PROCESSING: getItemByQueryFromState(state, function(item) {\n                // test if is already processed\n                if (item.serverId) {\n                    dispatch('REVERT_ITEM_PROCESSING', { id: item.id });\n                    return;\n                }\n\n                // abort\n                item.abortProcessing().then(function() {\n                    var shouldRemove = state.options.instantUpload;\n                    if (shouldRemove) {\n                        dispatch('REMOVE_ITEM', { query: item.id });\n                    }\n                });\n            }),\n\n            REQUEST_REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, function(item) {\n                // not instant uploading, revert immediately\n                if (!state.options.instantUpload) {\n                    dispatch('REVERT_ITEM_PROCESSING', { query: item });\n                    return;\n                }\n\n                // if we're instant uploading the file will also be removed if we revert,\n                // so if a before remove file hook is defined we need to run it now\n                var handleRevert = function handleRevert(shouldRevert) {\n                    if (!shouldRevert) return;\n                    dispatch('REVERT_ITEM_PROCESSING', { query: item });\n                };\n\n                var fn = query('GET_BEFORE_REMOVE_FILE');\n                if (!fn) {\n                    return handleRevert(true);\n                }\n\n                var requestRemoveResult = fn(createItemAPI(item));\n                if (requestRemoveResult == null) {\n                    // undefined or null\n                    return handleRevert(true);\n                }\n\n                if (typeof requestRemoveResult === 'boolean') {\n                    return handleRevert(requestRemoveResult);\n                }\n\n                if (typeof requestRemoveResult.then === 'function') {\n                    requestRemoveResult.then(handleRevert);\n                }\n            }),\n\n            REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, function(item) {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                )\n                    .then(function() {\n                        var shouldRemove = state.options.instantUpload || isMockItem(item);\n                        if (shouldRemove) {\n                            dispatch('REMOVE_ITEM', { query: item.id });\n                        }\n                    })\n                    .catch(function() {});\n            }),\n\n            SET_OPTIONS: function SET_OPTIONS(_ref11) {\n                var options = _ref11.options;\n                // get all keys passed\n                var optionKeys = Object.keys(options);\n\n                // get prioritized keyed to include (remove once not in options object)\n                var prioritizedOptionKeys = PrioritizedOptions.filter(function(key) {\n                    return optionKeys.includes(key);\n                });\n\n                // order the keys, prioritized first, then rest\n                var orderedOptionKeys = [].concat(\n                    _toConsumableArray(prioritizedOptionKeys),\n                    _toConsumableArray(\n                        Object.keys(options).filter(function(key) {\n                            return !prioritizedOptionKeys.includes(key);\n                        })\n                    )\n                );\n\n                // dispatch set event for each option\n                orderedOptionKeys.forEach(function(key) {\n                    dispatch('SET_' + fromCamels(key, '_').toUpperCase(), {\n                        value: options[key],\n                    });\n                });\n            },\n        };\n    };\n\n    var PrioritizedOptions = ['server'];\n\n    var formatFilename = function formatFilename(name) {\n        return name;\n    };\n\n    var createElement$1 = function createElement(tagName) {\n        return document.createElement(tagName);\n    };\n\n    var text = function text(node, value) {\n        var textNode = node.childNodes[0];\n        if (!textNode) {\n            textNode = document.createTextNode(value);\n            node.appendChild(textNode);\n        } else if (value !== textNode.nodeValue) {\n            textNode.nodeValue = value;\n        }\n    };\n\n    var polarToCartesian = function polarToCartesian(centerX, centerY, radius, angleInDegrees) {\n        var angleInRadians = (((angleInDegrees % 360) - 90) * Math.PI) / 180.0;\n        return {\n            x: centerX + radius * Math.cos(angleInRadians),\n            y: centerY + radius * Math.sin(angleInRadians),\n        };\n    };\n\n    var describeArc = function describeArc(x, y, radius, startAngle, endAngle, arcSweep) {\n        var start = polarToCartesian(x, y, radius, endAngle);\n        var end = polarToCartesian(x, y, radius, startAngle);\n        return ['M', start.x, start.y, 'A', radius, radius, 0, arcSweep, 0, end.x, end.y].join(' ');\n    };\n\n    var percentageArc = function percentageArc(x, y, radius, from, to) {\n        var arcSweep = 1;\n        if (to > from && to - from <= 0.5) {\n            arcSweep = 0;\n        }\n        if (from > to && from - to >= 0.5) {\n            arcSweep = 0;\n        }\n        return describeArc(\n            x,\n            y,\n            radius,\n            Math.min(0.9999, from) * 360,\n            Math.min(0.9999, to) * 360,\n            arcSweep\n        );\n    };\n\n    var create = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // start at 0\n        props.spin = false;\n        props.progress = 0;\n        props.opacity = 0;\n\n        // svg\n        var svg = createElement('svg');\n        root.ref.path = createElement('path', {\n            'stroke-width': 2,\n            'stroke-linecap': 'round',\n        });\n\n        svg.appendChild(root.ref.path);\n\n        root.ref.svg = svg;\n\n        root.appendChild(svg);\n    };\n\n    var write = function write(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n        if (props.opacity === 0) {\n            return;\n        }\n\n        if (props.align) {\n            root.element.dataset.align = props.align;\n        }\n\n        // get width of stroke\n        var ringStrokeWidth = parseInt(attr(root.ref.path, 'stroke-width'), 10);\n\n        // calculate size of ring\n        var size = root.rect.element.width * 0.5;\n\n        // ring state\n        var ringFrom = 0;\n        var ringTo = 0;\n\n        // now in busy mode\n        if (props.spin) {\n            ringFrom = 0;\n            ringTo = 0.5;\n        } else {\n            ringFrom = 0;\n            ringTo = props.progress;\n        }\n\n        // get arc path\n        var coordinates = percentageArc(size, size, size - ringStrokeWidth, ringFrom, ringTo);\n\n        // update progress bar\n        attr(root.ref.path, 'd', coordinates);\n\n        // hide while contains 0 value\n        attr(root.ref.path, 'stroke-opacity', props.spin || props.progress > 0 ? 1 : 0);\n    };\n\n    var progressIndicator = createView({\n        tag: 'div',\n        name: 'progress-indicator',\n        ignoreRectUpdate: true,\n        ignoreRect: true,\n        create: create,\n        write: write,\n        mixins: {\n            apis: ['progress', 'spin', 'align'],\n            styles: ['opacity'],\n            animations: {\n                opacity: { type: 'tween', duration: 500 },\n                progress: {\n                    type: 'spring',\n                    stiffness: 0.95,\n                    damping: 0.65,\n                    mass: 10,\n                },\n            },\n        },\n    });\n\n    var create$1 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        root.element.innerHTML = (props.icon || '') + ('<span>' + props.label + '</span>');\n\n        props.isDisabled = false;\n    };\n\n    var write$1 = function write(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n        var isDisabled = props.isDisabled;\n        var shouldDisable = root.query('GET_DISABLED') || props.opacity === 0;\n\n        if (shouldDisable && !isDisabled) {\n            props.isDisabled = true;\n            attr(root.element, 'disabled', 'disabled');\n        } else if (!shouldDisable && isDisabled) {\n            props.isDisabled = false;\n            root.element.removeAttribute('disabled');\n        }\n    };\n\n    var fileActionButton = createView({\n        tag: 'button',\n        attributes: {\n            type: 'button',\n        },\n\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        name: 'file-action-button',\n        mixins: {\n            apis: ['label'],\n            styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n            animations: {\n                scaleX: 'spring',\n                scaleY: 'spring',\n                translateX: 'spring',\n                translateY: 'spring',\n                opacity: { type: 'tween', duration: 250 },\n            },\n\n            listeners: true,\n        },\n\n        create: create$1,\n        write: write$1,\n    });\n\n    var toNaturalFileSize = function toNaturalFileSize(bytes) {\n        var decimalSeparator =\n            arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '.';\n        var base = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;\n        var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n        var _options$labelBytes = options.labelBytes,\n            labelBytes = _options$labelBytes === void 0 ? 'bytes' : _options$labelBytes,\n            _options$labelKilobyt = options.labelKilobytes,\n            labelKilobytes = _options$labelKilobyt === void 0 ? 'KB' : _options$labelKilobyt,\n            _options$labelMegabyt = options.labelMegabytes,\n            labelMegabytes = _options$labelMegabyt === void 0 ? 'MB' : _options$labelMegabyt,\n            _options$labelGigabyt = options.labelGigabytes,\n            labelGigabytes = _options$labelGigabyt === void 0 ? 'GB' : _options$labelGigabyt;\n\n        // no negative byte sizes\n        bytes = Math.round(Math.abs(bytes));\n\n        var KB = base;\n        var MB = base * base;\n        var GB = base * base * base;\n\n        // just bytes\n        if (bytes < KB) {\n            return bytes + ' ' + labelBytes;\n        }\n\n        // kilobytes\n        if (bytes < MB) {\n            return Math.floor(bytes / KB) + ' ' + labelKilobytes;\n        }\n\n        // megabytes\n        if (bytes < GB) {\n            return removeDecimalsWhenZero(bytes / MB, 1, decimalSeparator) + ' ' + labelMegabytes;\n        }\n\n        // gigabytes\n        return removeDecimalsWhenZero(bytes / GB, 2, decimalSeparator) + ' ' + labelGigabytes;\n    };\n\n    var removeDecimalsWhenZero = function removeDecimalsWhenZero(value, decimalCount, separator) {\n        return value\n            .toFixed(decimalCount)\n            .split('.')\n            .filter(function(part) {\n                return part !== '0';\n            })\n            .join(separator);\n    };\n\n    var create$2 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // filename\n        var fileName = createElement$1('span');\n        fileName.className = 'filepond--file-info-main';\n        // hide for screenreaders\n        // the file is contained in a fieldset with legend that contains the filename\n        // no need to read it twice\n        attr(fileName, 'aria-hidden', 'true');\n        root.appendChild(fileName);\n        root.ref.fileName = fileName;\n\n        // filesize\n        var fileSize = createElement$1('span');\n        fileSize.className = 'filepond--file-info-sub';\n        root.appendChild(fileSize);\n        root.ref.fileSize = fileSize;\n\n        // set initial values\n        text(fileSize, root.query('GET_LABEL_FILE_WAITING_FOR_SIZE'));\n        text(fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n    };\n\n    var updateFile = function updateFile(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n        text(\n            root.ref.fileSize,\n            toNaturalFileSize(\n                root.query('GET_ITEM_SIZE', props.id),\n                '.',\n                root.query('GET_FILE_SIZE_BASE'),\n                root.query('GET_FILE_SIZE_LABELS', root.query)\n            )\n        );\n\n        text(root.ref.fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n    };\n\n    var updateFileSizeOnError = function updateFileSizeOnError(_ref3) {\n        var root = _ref3.root,\n            props = _ref3.props;\n        // if size is available don't fallback to unknown size message\n        if (isInt(root.query('GET_ITEM_SIZE', props.id))) {\n            updateFile({ root: root, props: props });\n            return;\n        }\n\n        text(root.ref.fileSize, root.query('GET_LABEL_FILE_SIZE_NOT_AVAILABLE'));\n    };\n\n    var fileInfo = createView({\n        name: 'file-info',\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        write: createRoute({\n            DID_LOAD_ITEM: updateFile,\n            DID_UPDATE_ITEM_META: updateFile,\n            DID_THROW_ITEM_LOAD_ERROR: updateFileSizeOnError,\n            DID_THROW_ITEM_INVALID: updateFileSizeOnError,\n        }),\n\n        didCreateView: function didCreateView(root) {\n            applyFilters('CREATE_VIEW', Object.assign({}, root, { view: root }));\n        },\n        create: create$2,\n        mixins: {\n            styles: ['translateX', 'translateY'],\n            animations: {\n                translateX: 'spring',\n                translateY: 'spring',\n            },\n        },\n    });\n\n    var toPercentage = function toPercentage(value) {\n        return Math.round(value * 100);\n    };\n\n    var create$3 = function create(_ref) {\n        var root = _ref.root;\n\n        // main status\n        var main = createElement$1('span');\n        main.className = 'filepond--file-status-main';\n        root.appendChild(main);\n        root.ref.main = main;\n\n        // sub status\n        var sub = createElement$1('span');\n        sub.className = 'filepond--file-status-sub';\n        root.appendChild(sub);\n        root.ref.sub = sub;\n\n        didSetItemLoadProgress({ root: root, action: { progress: null } });\n    };\n\n    var didSetItemLoadProgress = function didSetItemLoadProgress(_ref2) {\n        var root = _ref2.root,\n            action = _ref2.action;\n        var title =\n            action.progress === null\n                ? root.query('GET_LABEL_FILE_LOADING')\n                : root.query('GET_LABEL_FILE_LOADING') + ' ' + toPercentage(action.progress) + '%';\n\n        text(root.ref.main, title);\n        text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n    };\n\n    var didSetItemProcessProgress = function didSetItemProcessProgress(_ref3) {\n        var root = _ref3.root,\n            action = _ref3.action;\n        var title =\n            action.progress === null\n                ? root.query('GET_LABEL_FILE_PROCESSING')\n                : root.query('GET_LABEL_FILE_PROCESSING') +\n                  ' ' +\n                  toPercentage(action.progress) +\n                  '%';\n\n        text(root.ref.main, title);\n        text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n    };\n\n    var didRequestItemProcessing = function didRequestItemProcessing(_ref4) {\n        var root = _ref4.root;\n        text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING'));\n        text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n    };\n\n    var didAbortItemProcessing = function didAbortItemProcessing(_ref5) {\n        var root = _ref5.root;\n        text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_ABORTED'));\n        text(root.ref.sub, root.query('GET_LABEL_TAP_TO_RETRY'));\n    };\n\n    var didCompleteItemProcessing = function didCompleteItemProcessing(_ref6) {\n        var root = _ref6.root;\n        text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_COMPLETE'));\n        text(root.ref.sub, root.query('GET_LABEL_TAP_TO_UNDO'));\n    };\n\n    var clear = function clear(_ref7) {\n        var root = _ref7.root;\n        text(root.ref.main, '');\n        text(root.ref.sub, '');\n    };\n\n    var error = function error(_ref8) {\n        var root = _ref8.root,\n            action = _ref8.action;\n        text(root.ref.main, action.status.main);\n        text(root.ref.sub, action.status.sub);\n    };\n\n    var fileStatus = createView({\n        name: 'file-status',\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        write: createRoute({\n            DID_LOAD_ITEM: clear,\n            DID_REVERT_ITEM_PROCESSING: clear,\n            DID_REQUEST_ITEM_PROCESSING: didRequestItemProcessing,\n            DID_ABORT_ITEM_PROCESSING: didAbortItemProcessing,\n            DID_COMPLETE_ITEM_PROCESSING: didCompleteItemProcessing,\n            DID_UPDATE_ITEM_PROCESS_PROGRESS: didSetItemProcessProgress,\n            DID_UPDATE_ITEM_LOAD_PROGRESS: didSetItemLoadProgress,\n            DID_THROW_ITEM_LOAD_ERROR: error,\n            DID_THROW_ITEM_INVALID: error,\n            DID_THROW_ITEM_PROCESSING_ERROR: error,\n            DID_THROW_ITEM_PROCESSING_REVERT_ERROR: error,\n            DID_THROW_ITEM_REMOVE_ERROR: error,\n        }),\n\n        didCreateView: function didCreateView(root) {\n            applyFilters('CREATE_VIEW', Object.assign({}, root, { view: root }));\n        },\n        create: create$3,\n        mixins: {\n            styles: ['translateX', 'translateY', 'opacity'],\n            animations: {\n                opacity: { type: 'tween', duration: 250 },\n                translateX: 'spring',\n                translateY: 'spring',\n            },\n        },\n    });\n\n    /**\n     * Button definitions for the file view\n     */\n\n    var Buttons = {\n        AbortItemLoad: {\n            label: 'GET_LABEL_BUTTON_ABORT_ITEM_LOAD',\n            action: 'ABORT_ITEM_LOAD',\n            className: 'filepond--action-abort-item-load',\n            align: 'LOAD_INDICATOR_POSITION', // right\n        },\n        RetryItemLoad: {\n            label: 'GET_LABEL_BUTTON_RETRY_ITEM_LOAD',\n            action: 'RETRY_ITEM_LOAD',\n            icon: 'GET_ICON_RETRY',\n            className: 'filepond--action-retry-item-load',\n            align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n        },\n        RemoveItem: {\n            label: 'GET_LABEL_BUTTON_REMOVE_ITEM',\n            action: 'REQUEST_REMOVE_ITEM',\n            icon: 'GET_ICON_REMOVE',\n            className: 'filepond--action-remove-item',\n            align: 'BUTTON_REMOVE_ITEM_POSITION', // left\n        },\n        ProcessItem: {\n            label: 'GET_LABEL_BUTTON_PROCESS_ITEM',\n            action: 'REQUEST_ITEM_PROCESSING',\n            icon: 'GET_ICON_PROCESS',\n            className: 'filepond--action-process-item',\n            align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n        },\n        AbortItemProcessing: {\n            label: 'GET_LABEL_BUTTON_ABORT_ITEM_PROCESSING',\n            action: 'ABORT_ITEM_PROCESSING',\n            className: 'filepond--action-abort-item-processing',\n            align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n        },\n        RetryItemProcessing: {\n            label: 'GET_LABEL_BUTTON_RETRY_ITEM_PROCESSING',\n            action: 'RETRY_ITEM_PROCESSING',\n            icon: 'GET_ICON_RETRY',\n            className: 'filepond--action-retry-item-processing',\n            align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n        },\n        RevertItemProcessing: {\n            label: 'GET_LABEL_BUTTON_UNDO_ITEM_PROCESSING',\n            action: 'REQUEST_REVERT_ITEM_PROCESSING',\n            icon: 'GET_ICON_UNDO',\n            className: 'filepond--action-revert-item-processing',\n            align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n        },\n    };\n\n    // make a list of buttons, we can then remove buttons from this list if they're disabled\n    var ButtonKeys = [];\n    forin(Buttons, function(key) {\n        ButtonKeys.push(key);\n    });\n\n    var calculateFileInfoOffset = function calculateFileInfoOffset(root) {\n        if (getRemoveIndicatorAligment(root) === 'right') return 0;\n        var buttonRect = root.ref.buttonRemoveItem.rect.element;\n        return buttonRect.hidden ? null : buttonRect.width + buttonRect.left;\n    };\n\n    var calculateButtonWidth = function calculateButtonWidth(root) {\n        var buttonRect = root.ref.buttonAbortItemLoad.rect.element;\n        return buttonRect.width;\n    };\n\n    // Force on full pixels so text stays crips\n    var calculateFileVerticalCenterOffset = function calculateFileVerticalCenterOffset(root) {\n        return Math.floor(root.ref.buttonRemoveItem.rect.element.height / 4);\n    };\n    var calculateFileHorizontalCenterOffset = function calculateFileHorizontalCenterOffset(root) {\n        return Math.floor(root.ref.buttonRemoveItem.rect.element.left / 2);\n    };\n\n    var getLoadIndicatorAlignment = function getLoadIndicatorAlignment(root) {\n        return root.query('GET_STYLE_LOAD_INDICATOR_POSITION');\n    };\n    var getProcessIndicatorAlignment = function getProcessIndicatorAlignment(root) {\n        return root.query('GET_STYLE_PROGRESS_INDICATOR_POSITION');\n    };\n    var getRemoveIndicatorAligment = function getRemoveIndicatorAligment(root) {\n        return root.query('GET_STYLE_BUTTON_REMOVE_ITEM_POSITION');\n    };\n\n    var DefaultStyle = {\n        buttonAbortItemLoad: { opacity: 0 },\n        buttonRetryItemLoad: { opacity: 0 },\n        buttonRemoveItem: { opacity: 0 },\n        buttonProcessItem: { opacity: 0 },\n        buttonAbortItemProcessing: { opacity: 0 },\n        buttonRetryItemProcessing: { opacity: 0 },\n        buttonRevertItemProcessing: { opacity: 0 },\n        loadProgressIndicator: { opacity: 0, align: getLoadIndicatorAlignment },\n        processProgressIndicator: { opacity: 0, align: getProcessIndicatorAlignment },\n        processingCompleteIndicator: { opacity: 0, scaleX: 0.75, scaleY: 0.75 },\n        info: { translateX: 0, translateY: 0, opacity: 0 },\n        status: { translateX: 0, translateY: 0, opacity: 0 },\n    };\n\n    var IdleStyle = {\n        buttonRemoveItem: { opacity: 1 },\n        buttonProcessItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { translateX: calculateFileInfoOffset },\n    };\n\n    var ProcessingStyle = {\n        buttonAbortItemProcessing: { opacity: 1 },\n        processProgressIndicator: { opacity: 1 },\n        status: { opacity: 1 },\n    };\n\n    var StyleMap = {\n        DID_THROW_ITEM_INVALID: {\n            buttonRemoveItem: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n            status: { translateX: calculateFileInfoOffset, opacity: 1 },\n        },\n\n        DID_START_ITEM_LOAD: {\n            buttonAbortItemLoad: { opacity: 1 },\n            loadProgressIndicator: { opacity: 1 },\n            status: { opacity: 1 },\n        },\n\n        DID_THROW_ITEM_LOAD_ERROR: {\n            buttonRetryItemLoad: { opacity: 1 },\n            buttonRemoveItem: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n            status: { opacity: 1 },\n        },\n\n        DID_START_ITEM_REMOVE: {\n            processProgressIndicator: { opacity: 1, align: getRemoveIndicatorAligment },\n            info: { translateX: calculateFileInfoOffset },\n            status: { opacity: 0 },\n        },\n\n        DID_THROW_ITEM_REMOVE_ERROR: {\n            processProgressIndicator: { opacity: 0, align: getRemoveIndicatorAligment },\n            buttonRemoveItem: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n            status: { opacity: 1, translateX: calculateFileInfoOffset },\n        },\n\n        DID_LOAD_ITEM: IdleStyle,\n        DID_LOAD_LOCAL_ITEM: {\n            buttonRemoveItem: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n            status: { translateX: calculateFileInfoOffset },\n        },\n\n        DID_START_ITEM_PROCESSING: ProcessingStyle,\n        DID_REQUEST_ITEM_PROCESSING: ProcessingStyle,\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: ProcessingStyle,\n        DID_COMPLETE_ITEM_PROCESSING: {\n            buttonRevertItemProcessing: { opacity: 1 },\n            info: { opacity: 1 },\n            status: { opacity: 1 },\n        },\n\n        DID_THROW_ITEM_PROCESSING_ERROR: {\n            buttonRemoveItem: { opacity: 1 },\n            buttonRetryItemProcessing: { opacity: 1 },\n            status: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n        },\n\n        DID_THROW_ITEM_PROCESSING_REVERT_ERROR: {\n            buttonRevertItemProcessing: { opacity: 1 },\n            status: { opacity: 1 },\n            info: { opacity: 1 },\n        },\n\n        DID_ABORT_ITEM_PROCESSING: {\n            buttonRemoveItem: { opacity: 1 },\n            buttonProcessItem: { opacity: 1 },\n            info: { translateX: calculateFileInfoOffset },\n            status: { opacity: 1 },\n        },\n\n        DID_REVERT_ITEM_PROCESSING: IdleStyle,\n    };\n\n    // complete indicator view\n    var processingCompleteIndicatorView = createView({\n        create: function create(_ref) {\n            var root = _ref.root;\n            root.element.innerHTML = root.query('GET_ICON_DONE');\n        },\n        name: 'processing-complete-indicator',\n        ignoreRect: true,\n        mixins: {\n            styles: ['scaleX', 'scaleY', 'opacity'],\n            animations: {\n                scaleX: 'spring',\n                scaleY: 'spring',\n                opacity: { type: 'tween', duration: 250 },\n            },\n        },\n    });\n\n    /**\n     * Creates the file view\n     */\n    var create$4 = function create(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n        // copy Buttons object\n        var LocalButtons = Object.keys(Buttons).reduce(function(prev, curr) {\n            prev[curr] = Object.assign({}, Buttons[curr]);\n            return prev;\n        }, {});\n        var id = props.id;\n\n        // allow reverting upload\n        var allowRevert = root.query('GET_ALLOW_REVERT');\n\n        // allow remove file\n        var allowRemove = root.query('GET_ALLOW_REMOVE');\n\n        // allow processing upload\n        var allowProcess = root.query('GET_ALLOW_PROCESS');\n\n        // is instant uploading, need this to determine the icon of the undo button\n        var instantUpload = root.query('GET_INSTANT_UPLOAD');\n\n        // is async set up\n        var isAsync = root.query('IS_ASYNC');\n\n        // should align remove item buttons\n        var alignRemoveItemButton = root.query('GET_STYLE_BUTTON_REMOVE_ITEM_ALIGN');\n\n        // enabled buttons array\n        var buttonFilter;\n        if (isAsync) {\n            if (allowProcess && !allowRevert) {\n                // only remove revert button\n                buttonFilter = function buttonFilter(key) {\n                    return !/RevertItemProcessing/.test(key);\n                };\n            } else if (!allowProcess && allowRevert) {\n                // only remove process button\n                buttonFilter = function buttonFilter(key) {\n                    return !/ProcessItem|RetryItemProcessing|AbortItemProcessing/.test(key);\n                };\n            } else if (!allowProcess && !allowRevert) {\n                // remove all process buttons\n                buttonFilter = function buttonFilter(key) {\n                    return !/Process/.test(key);\n                };\n            }\n        } else {\n            // no process controls available\n            buttonFilter = function buttonFilter(key) {\n                return !/Process/.test(key);\n            };\n        }\n\n        var enabledButtons = buttonFilter ? ButtonKeys.filter(buttonFilter) : ButtonKeys.concat();\n\n        // update icon and label for revert button when instant uploading\n        if (instantUpload && allowRevert) {\n            LocalButtons['RevertItemProcessing'].label = 'GET_LABEL_BUTTON_REMOVE_ITEM';\n            LocalButtons['RevertItemProcessing'].icon = 'GET_ICON_REMOVE';\n        }\n\n        // remove last button (revert) if not allowed\n        if (isAsync && !allowRevert) {\n            var map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n            map.info.translateX = calculateFileHorizontalCenterOffset;\n            map.info.translateY = calculateFileVerticalCenterOffset;\n            map.status.translateY = calculateFileVerticalCenterOffset;\n            map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n        }\n\n        // should align center\n        if (isAsync && !allowProcess) {\n            [\n                'DID_START_ITEM_PROCESSING',\n                'DID_REQUEST_ITEM_PROCESSING',\n                'DID_UPDATE_ITEM_PROCESS_PROGRESS',\n                'DID_THROW_ITEM_PROCESSING_ERROR',\n            ].forEach(function(key) {\n                StyleMap[key].status.translateY = calculateFileVerticalCenterOffset;\n            });\n            StyleMap['DID_THROW_ITEM_PROCESSING_ERROR'].status.translateX = calculateButtonWidth;\n        }\n\n        // move remove button to right\n        if (alignRemoveItemButton && allowRevert) {\n            LocalButtons['RevertItemProcessing'].align = 'BUTTON_REMOVE_ITEM_POSITION';\n            var _map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n            _map.info.translateX = calculateFileInfoOffset;\n            _map.status.translateY = calculateFileVerticalCenterOffset;\n            _map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n        }\n\n        // show/hide RemoveItem button\n        if (!allowRemove) {\n            LocalButtons['RemoveItem'].disabled = true;\n        }\n\n        // create the button views\n        forin(LocalButtons, function(key, definition) {\n            // create button\n            var buttonView = root.createChildView(fileActionButton, {\n                label: root.query(definition.label),\n                icon: root.query(definition.icon),\n                opacity: 0,\n            });\n\n            // should be appended?\n            if (enabledButtons.includes(key)) {\n                root.appendChildView(buttonView);\n            }\n\n            // toggle\n            if (definition.disabled) {\n                buttonView.element.setAttribute('disabled', 'disabled');\n                buttonView.element.setAttribute('hidden', 'hidden');\n            }\n\n            // add position attribute\n            buttonView.element.dataset.align = root.query('GET_STYLE_' + definition.align);\n\n            // add class\n            buttonView.element.classList.add(definition.className);\n\n            // handle interactions\n            buttonView.on('click', function(e) {\n                e.stopPropagation();\n                if (definition.disabled) return;\n                root.dispatch(definition.action, { query: id });\n            });\n\n            // set reference\n            root.ref['button' + key] = buttonView;\n        });\n\n        // checkmark\n        root.ref.processingCompleteIndicator = root.appendChildView(\n            root.createChildView(processingCompleteIndicatorView)\n        );\n\n        root.ref.processingCompleteIndicator.element.dataset.align = root.query(\n            'GET_STYLE_BUTTON_PROCESS_ITEM_POSITION'\n        );\n\n        // create file info view\n        root.ref.info = root.appendChildView(root.createChildView(fileInfo, { id: id }));\n\n        // create file status view\n        root.ref.status = root.appendChildView(root.createChildView(fileStatus, { id: id }));\n\n        // add progress indicators\n        var loadIndicatorView = root.appendChildView(\n            root.createChildView(progressIndicator, {\n                opacity: 0,\n                align: root.query('GET_STYLE_LOAD_INDICATOR_POSITION'),\n            })\n        );\n\n        loadIndicatorView.element.classList.add('filepond--load-indicator');\n        root.ref.loadProgressIndicator = loadIndicatorView;\n\n        var progressIndicatorView = root.appendChildView(\n            root.createChildView(progressIndicator, {\n                opacity: 0,\n                align: root.query('GET_STYLE_PROGRESS_INDICATOR_POSITION'),\n            })\n        );\n\n        progressIndicatorView.element.classList.add('filepond--process-indicator');\n        root.ref.processProgressIndicator = progressIndicatorView;\n\n        // current active styles\n        root.ref.activeStyles = [];\n    };\n\n    var write$2 = function write(_ref3) {\n        var root = _ref3.root,\n            actions = _ref3.actions,\n            props = _ref3.props;\n        // route actions\n        route({ root: root, actions: actions, props: props });\n\n        // select last state change action\n        var action = actions\n            .concat()\n            .filter(function(action) {\n                return /^DID_/.test(action.type);\n            })\n            .reverse()\n            .find(function(action) {\n                return StyleMap[action.type];\n            });\n\n        // a new action happened, let's get the matching styles\n        if (action) {\n            // define new active styles\n            root.ref.activeStyles = [];\n\n            var stylesToApply = StyleMap[action.type];\n            forin(DefaultStyle, function(name, defaultStyles) {\n                // get reference to control\n                var control = root.ref[name];\n\n                // loop over all styles for this control\n                forin(defaultStyles, function(key, defaultValue) {\n                    var value =\n                        stylesToApply[name] && typeof stylesToApply[name][key] !== 'undefined'\n                            ? stylesToApply[name][key]\n                            : defaultValue;\n                    root.ref.activeStyles.push({ control: control, key: key, value: value });\n                });\n            });\n        }\n\n        // apply active styles to element\n        root.ref.activeStyles.forEach(function(_ref4) {\n            var control = _ref4.control,\n                key = _ref4.key,\n                value = _ref4.value;\n            control[key] = typeof value === 'function' ? value(root) : value;\n        });\n    };\n\n    var route = createRoute({\n        DID_SET_LABEL_BUTTON_ABORT_ITEM_PROCESSING: function DID_SET_LABEL_BUTTON_ABORT_ITEM_PROCESSING(\n            _ref5\n        ) {\n            var root = _ref5.root,\n                action = _ref5.action;\n            root.ref.buttonAbortItemProcessing.label = action.value;\n        },\n        DID_SET_LABEL_BUTTON_ABORT_ITEM_LOAD: function DID_SET_LABEL_BUTTON_ABORT_ITEM_LOAD(_ref6) {\n            var root = _ref6.root,\n                action = _ref6.action;\n            root.ref.buttonAbortItemLoad.label = action.value;\n        },\n        DID_SET_LABEL_BUTTON_ABORT_ITEM_REMOVAL: function DID_SET_LABEL_BUTTON_ABORT_ITEM_REMOVAL(\n            _ref7\n        ) {\n            var root = _ref7.root,\n                action = _ref7.action;\n            root.ref.buttonAbortItemRemoval.label = action.value;\n        },\n        DID_REQUEST_ITEM_PROCESSING: function DID_REQUEST_ITEM_PROCESSING(_ref8) {\n            var root = _ref8.root;\n            root.ref.processProgressIndicator.spin = true;\n            root.ref.processProgressIndicator.progress = 0;\n        },\n        DID_START_ITEM_LOAD: function DID_START_ITEM_LOAD(_ref9) {\n            var root = _ref9.root;\n            root.ref.loadProgressIndicator.spin = true;\n            root.ref.loadProgressIndicator.progress = 0;\n        },\n        DID_START_ITEM_REMOVE: function DID_START_ITEM_REMOVE(_ref10) {\n            var root = _ref10.root;\n            root.ref.processProgressIndicator.spin = true;\n            root.ref.processProgressIndicator.progress = 0;\n        },\n        DID_UPDATE_ITEM_LOAD_PROGRESS: function DID_UPDATE_ITEM_LOAD_PROGRESS(_ref11) {\n            var root = _ref11.root,\n                action = _ref11.action;\n            root.ref.loadProgressIndicator.spin = false;\n            root.ref.loadProgressIndicator.progress = action.progress;\n        },\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: function DID_UPDATE_ITEM_PROCESS_PROGRESS(_ref12) {\n            var root = _ref12.root,\n                action = _ref12.action;\n            root.ref.processProgressIndicator.spin = false;\n            root.ref.processProgressIndicator.progress = action.progress;\n        },\n    });\n\n    var file = createView({\n        create: create$4,\n        write: write$2,\n        didCreateView: function didCreateView(root) {\n            applyFilters('CREATE_VIEW', Object.assign({}, root, { view: root }));\n        },\n        name: 'file',\n    });\n\n    /**\n     * Creates the file view\n     */\n    var create$5 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n\n        // filename\n        root.ref.fileName = createElement$1('legend');\n        root.appendChild(root.ref.fileName);\n\n        // file appended\n        root.ref.file = root.appendChildView(root.createChildView(file, { id: props.id }));\n\n        // data has moved to data.js\n        root.ref.data = false;\n    };\n\n    /**\n     * Data storage\n     */\n    var didLoadItem = function didLoadItem(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n        // updates the legend of the fieldset so screenreaders can better group buttons\n        text(root.ref.fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n    };\n\n    var fileWrapper = createView({\n        create: create$5,\n        ignoreRect: true,\n        write: createRoute({\n            DID_LOAD_ITEM: didLoadItem,\n        }),\n\n        didCreateView: function didCreateView(root) {\n            applyFilters('CREATE_VIEW', Object.assign({}, root, { view: root }));\n        },\n        tag: 'fieldset',\n        name: 'file-wrapper',\n    });\n\n    var PANEL_SPRING_PROPS = { type: 'spring', damping: 0.6, mass: 7 };\n\n    var create$6 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        [\n            {\n                name: 'top',\n            },\n\n            {\n                name: 'center',\n                props: {\n                    translateY: null,\n                    scaleY: null,\n                },\n\n                mixins: {\n                    animations: {\n                        scaleY: PANEL_SPRING_PROPS,\n                    },\n\n                    styles: ['translateY', 'scaleY'],\n                },\n            },\n\n            {\n                name: 'bottom',\n                props: {\n                    translateY: null,\n                },\n\n                mixins: {\n                    animations: {\n                        translateY: PANEL_SPRING_PROPS,\n                    },\n\n                    styles: ['translateY'],\n                },\n            },\n        ].forEach(function(section) {\n            createSection(root, section, props.name);\n        });\n\n        root.element.classList.add('filepond--' + props.name);\n\n        root.ref.scalable = null;\n    };\n\n    var createSection = function createSection(root, section, className) {\n        var viewConstructor = createView({\n            name: 'panel-' + section.name + ' filepond--' + className,\n            mixins: section.mixins,\n            ignoreRectUpdate: true,\n        });\n\n        var view = root.createChildView(viewConstructor, section.props);\n\n        root.ref[section.name] = root.appendChildView(view);\n    };\n\n    var write$3 = function write(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props;\n\n        // update scalable state\n        if (root.ref.scalable === null || props.scalable !== root.ref.scalable) {\n            root.ref.scalable = isBoolean(props.scalable) ? props.scalable : true;\n            root.element.dataset.scalable = root.ref.scalable;\n        }\n\n        // no height, can't set\n        if (!props.height) return;\n\n        // get child rects\n        var topRect = root.ref.top.rect.element;\n        var bottomRect = root.ref.bottom.rect.element;\n\n        // make sure height never is smaller than bottom and top seciton heights combined (will probably never happen, but who knows)\n        var height = Math.max(topRect.height + bottomRect.height, props.height);\n\n        // offset center part\n        root.ref.center.translateY = topRect.height;\n\n        // scale center part\n        // use math ceil to prevent transparent lines because of rounding errors\n        root.ref.center.scaleY = (height - topRect.height - bottomRect.height) / 100;\n\n        // offset bottom part\n        root.ref.bottom.translateY = height - bottomRect.height;\n    };\n\n    var panel = createView({\n        name: 'panel',\n        read: function read(_ref3) {\n            var root = _ref3.root,\n                props = _ref3.props;\n            return (props.heightCurrent = root.ref.bottom.translateY);\n        },\n        write: write$3,\n        create: create$6,\n        ignoreRect: true,\n        mixins: {\n            apis: ['height', 'heightCurrent', 'scalable'],\n        },\n    });\n\n    var createDragHelper = function createDragHelper(items) {\n        var itemIds = items.map(function(item) {\n            return item.id;\n        });\n        var prevIndex = undefined;\n        return {\n            setIndex: function setIndex(index) {\n                prevIndex = index;\n            },\n            getIndex: function getIndex() {\n                return prevIndex;\n            },\n            getItemIndex: function getItemIndex(item) {\n                return itemIds.indexOf(item.id);\n            },\n        };\n    };\n\n    var ITEM_TRANSLATE_SPRING = {\n        type: 'spring',\n        stiffness: 0.75,\n        damping: 0.45,\n        mass: 10,\n    };\n\n    var ITEM_SCALE_SPRING = 'spring';\n\n    var StateMap = {\n        DID_START_ITEM_LOAD: 'busy',\n        DID_UPDATE_ITEM_LOAD_PROGRESS: 'loading',\n        DID_THROW_ITEM_INVALID: 'load-invalid',\n        DID_THROW_ITEM_LOAD_ERROR: 'load-error',\n        DID_LOAD_ITEM: 'idle',\n        DID_THROW_ITEM_REMOVE_ERROR: 'remove-error',\n        DID_START_ITEM_REMOVE: 'busy',\n        DID_START_ITEM_PROCESSING: 'busy processing',\n        DID_REQUEST_ITEM_PROCESSING: 'busy processing',\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: 'processing',\n        DID_COMPLETE_ITEM_PROCESSING: 'processing-complete',\n        DID_THROW_ITEM_PROCESSING_ERROR: 'processing-error',\n        DID_THROW_ITEM_PROCESSING_REVERT_ERROR: 'processing-revert-error',\n        DID_ABORT_ITEM_PROCESSING: 'cancelled',\n        DID_REVERT_ITEM_PROCESSING: 'idle',\n    };\n\n    /**\n     * Creates the file view\n     */\n    var create$7 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // select\n        root.ref.handleClick = function(e) {\n            return root.dispatch('DID_ACTIVATE_ITEM', { id: props.id });\n        };\n\n        // set id\n        root.element.id = 'filepond--item-' + props.id;\n        root.element.addEventListener('click', root.ref.handleClick);\n\n        // file view\n        root.ref.container = root.appendChildView(\n            root.createChildView(fileWrapper, { id: props.id })\n        );\n\n        // file panel\n        root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'item-panel' }));\n\n        // default start height\n        root.ref.panel.height = null;\n\n        // by default not marked for removal\n        props.markedForRemoval = false;\n\n        // if not allowed to reorder file items, exit here\n        if (!root.query('GET_ALLOW_REORDER')) return;\n\n        // set to idle so shows grab cursor\n        root.element.dataset.dragState = 'idle';\n\n        var grab = function grab(e) {\n            if (!e.isPrimary) return;\n\n            var removedActivateListener = false;\n\n            var origin = {\n                x: e.pageX,\n                y: e.pageY,\n            };\n\n            props.dragOrigin = {\n                x: root.translateX,\n                y: root.translateY,\n            };\n\n            props.dragCenter = {\n                x: e.offsetX,\n                y: e.offsetY,\n            };\n\n            var dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));\n\n            root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState: dragState });\n\n            var drag = function drag(e) {\n                if (!e.isPrimary) return;\n\n                e.stopPropagation();\n                e.preventDefault();\n\n                props.dragOffset = {\n                    x: e.pageX - origin.x,\n                    y: e.pageY - origin.y,\n                };\n\n                // if dragged stop listening to clicks, will re-add when done dragging\n                var dist =\n                    props.dragOffset.x * props.dragOffset.x +\n                    props.dragOffset.y * props.dragOffset.y;\n                if (dist > 16 && !removedActivateListener) {\n                    removedActivateListener = true;\n                    root.element.removeEventListener('click', root.ref.handleClick);\n                }\n\n                root.dispatch('DID_DRAG_ITEM', { id: props.id, dragState: dragState });\n            };\n\n            var drop = function drop(e) {\n                if (!e.isPrimary) return;\n\n                props.dragOffset = {\n                    x: e.pageX - origin.x,\n                    y: e.pageY - origin.y,\n                };\n\n                reset();\n            };\n\n            var cancel = function cancel() {\n                reset();\n            };\n\n            var reset = function reset() {\n                document.removeEventListener('pointercancel', cancel);\n                document.removeEventListener('pointermove', drag);\n                document.removeEventListener('pointerup', drop);\n\n                root.dispatch('DID_DROP_ITEM', { id: props.id, dragState: dragState });\n\n                // start listening to clicks again\n                if (removedActivateListener) {\n                    setTimeout(function() {\n                        return root.element.addEventListener('click', root.ref.handleClick);\n                    }, 0);\n                }\n            };\n\n            document.addEventListener('pointercancel', cancel);\n            document.addEventListener('pointermove', drag);\n            document.addEventListener('pointerup', drop);\n        };\n\n        root.element.addEventListener('pointerdown', grab);\n    };\n\n    var route$1 = createRoute({\n        DID_UPDATE_PANEL_HEIGHT: function DID_UPDATE_PANEL_HEIGHT(_ref2) {\n            var root = _ref2.root,\n                action = _ref2.action;\n            root.height = action.height;\n        },\n    });\n\n    var write$4 = createRoute(\n        {\n            DID_GRAB_ITEM: function DID_GRAB_ITEM(_ref3) {\n                var root = _ref3.root,\n                    props = _ref3.props;\n                props.dragOrigin = {\n                    x: root.translateX,\n                    y: root.translateY,\n                };\n            },\n            DID_DRAG_ITEM: function DID_DRAG_ITEM(_ref4) {\n                var root = _ref4.root;\n                root.element.dataset.dragState = 'drag';\n            },\n            DID_DROP_ITEM: function DID_DROP_ITEM(_ref5) {\n                var root = _ref5.root,\n                    props = _ref5.props;\n                props.dragOffset = null;\n                props.dragOrigin = null;\n                root.element.dataset.dragState = 'drop';\n            },\n        },\n\n        function(_ref6) {\n            var root = _ref6.root,\n                actions = _ref6.actions,\n                props = _ref6.props,\n                shouldOptimize = _ref6.shouldOptimize;\n            if (root.element.dataset.dragState === 'drop') {\n                if (root.scaleX <= 1) {\n                    root.element.dataset.dragState = 'idle';\n                }\n            }\n\n            // select last state change action\n            var action = actions\n                .concat()\n                .filter(function(action) {\n                    return /^DID_/.test(action.type);\n                })\n                .reverse()\n                .find(function(action) {\n                    return StateMap[action.type];\n                });\n\n            // no need to set same state twice\n            if (action && action.type !== props.currentState) {\n                // set current state\n                props.currentState = action.type;\n\n                // set state\n                root.element.dataset.filepondItemState = StateMap[props.currentState] || '';\n            }\n\n            // route actions\n            var aspectRatio =\n                root.query('GET_ITEM_PANEL_ASPECT_RATIO') || root.query('GET_PANEL_ASPECT_RATIO');\n            if (!aspectRatio) {\n                route$1({ root: root, actions: actions, props: props });\n                if (!root.height && root.ref.container.rect.element.height > 0) {\n                    root.height = root.ref.container.rect.element.height;\n                }\n            } else if (!shouldOptimize) {\n                root.height = root.rect.element.width * aspectRatio;\n            }\n\n            // sync panel height with item height\n            if (shouldOptimize) {\n                root.ref.panel.height = null;\n            }\n\n            root.ref.panel.height = root.height;\n        }\n    );\n\n    var item = createView({\n        create: create$7,\n        write: write$4,\n        destroy: function destroy(_ref7) {\n            var root = _ref7.root,\n                props = _ref7.props;\n            root.element.removeEventListener('click', root.ref.handleClick);\n            root.dispatch('RELEASE_ITEM', { query: props.id });\n        },\n        tag: 'li',\n        name: 'item',\n        mixins: {\n            apis: [\n                'id',\n                'interactionMethod',\n                'markedForRemoval',\n                'spawnDate',\n                'dragCenter',\n                'dragOrigin',\n                'dragOffset',\n            ],\n\n            styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity', 'height'],\n            animations: {\n                scaleX: ITEM_SCALE_SPRING,\n                scaleY: ITEM_SCALE_SPRING,\n                translateX: ITEM_TRANSLATE_SPRING,\n                translateY: ITEM_TRANSLATE_SPRING,\n                opacity: { type: 'tween', duration: 150 },\n            },\n        },\n    });\n\n    var getItemsPerRow = function(horizontalSpace, itemWidth) {\n        // add one pixel leeway, when using percentages for item width total items can be 1.99 per row\n\n        return Math.max(1, Math.floor((horizontalSpace + 1) / itemWidth));\n    };\n\n    var getItemIndexByPosition = function getItemIndexByPosition(view, children, positionInView) {\n        if (!positionInView) return;\n\n        var horizontalSpace = view.rect.element.width;\n        // const children = view.childViews;\n        var l = children.length;\n        var last = null;\n\n        // -1, don't move items to accomodate (either add to top or bottom)\n        if (l === 0 || positionInView.top < children[0].rect.element.top) return -1;\n\n        // let's get the item width\n        var item = children[0];\n        var itemRect = item.rect.element;\n        var itemHorizontalMargin = itemRect.marginLeft + itemRect.marginRight;\n        var itemWidth = itemRect.width + itemHorizontalMargin;\n        var itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n        // stack\n        if (itemsPerRow === 1) {\n            for (var index = 0; index < l; index++) {\n                var child = children[index];\n                var childMid = child.rect.outer.top + child.rect.element.height * 0.5;\n                if (positionInView.top < childMid) {\n                    return index;\n                }\n            }\n            return l;\n        }\n\n        // grid\n        var itemVerticalMargin = itemRect.marginTop + itemRect.marginBottom;\n        var itemHeight = itemRect.height + itemVerticalMargin;\n        for (var _index = 0; _index < l; _index++) {\n            var indexX = _index % itemsPerRow;\n            var indexY = Math.floor(_index / itemsPerRow);\n\n            var offsetX = indexX * itemWidth;\n            var offsetY = indexY * itemHeight;\n\n            var itemTop = offsetY - itemRect.marginTop;\n            var itemRight = offsetX + itemWidth;\n            var itemBottom = offsetY + itemHeight + itemRect.marginBottom;\n\n            if (positionInView.top < itemBottom && positionInView.top > itemTop) {\n                if (positionInView.left < itemRight) {\n                    return _index;\n                } else if (_index !== l - 1) {\n                    last = _index;\n                } else {\n                    last = null;\n                }\n            }\n        }\n\n        if (last !== null) {\n            return last;\n        }\n\n        return l;\n    };\n\n    var dropAreaDimensions = {\n        height: 0,\n        width: 0,\n        get getHeight() {\n            return this.height;\n        },\n        set setHeight(val) {\n            if (this.height === 0 || val === 0) this.height = val;\n        },\n        get getWidth() {\n            return this.width;\n        },\n        set setWidth(val) {\n            if (this.width === 0 || val === 0) this.width = val;\n        },\n        setDimensions: function setDimensions(height, width) {\n            if (this.height === 0 || height === 0) this.height = height;\n            if (this.width === 0 || width === 0) this.width = width;\n        },\n    };\n\n    var create$8 = function create(_ref) {\n        var root = _ref.root;\n        // need to set role to list as otherwise it won't be read as a list by VoiceOver\n        attr(root.element, 'role', 'list');\n\n        root.ref.lastItemSpanwDate = Date.now();\n    };\n\n    /**\n     * Inserts a new item\n     * @param root\n     * @param action\n     */\n    var addItemView = function addItemView(_ref2) {\n        var root = _ref2.root,\n            action = _ref2.action;\n        var id = action.id,\n            index = action.index,\n            interactionMethod = action.interactionMethod;\n\n        root.ref.addIndex = index;\n\n        var now = Date.now();\n        var spawnDate = now;\n        var opacity = 1;\n\n        if (interactionMethod !== InteractionMethod.NONE) {\n            opacity = 0;\n            var cooldown = root.query('GET_ITEM_INSERT_INTERVAL');\n            var dist = now - root.ref.lastItemSpanwDate;\n            spawnDate = dist < cooldown ? now + (cooldown - dist) : now;\n        }\n\n        root.ref.lastItemSpanwDate = spawnDate;\n\n        root.appendChildView(\n            root.createChildView(\n                // view type\n                item,\n\n                // props\n                {\n                    spawnDate: spawnDate,\n                    id: id,\n                    opacity: opacity,\n                    interactionMethod: interactionMethod,\n                }\n            ),\n\n            index\n        );\n    };\n\n    var moveItem = function moveItem(item, x, y) {\n        var vx = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n        var vy = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;\n        // set to null to remove animation while dragging\n        if (item.dragOffset) {\n            item.translateX = null;\n            item.translateY = null;\n            item.translateX = item.dragOrigin.x + item.dragOffset.x;\n            item.translateY = item.dragOrigin.y + item.dragOffset.y;\n            item.scaleX = 1.025;\n            item.scaleY = 1.025;\n        } else {\n            item.translateX = x;\n            item.translateY = y;\n\n            if (Date.now() > item.spawnDate) {\n                // reveal element\n                if (item.opacity === 0) {\n                    introItemView(item, x, y, vx, vy);\n                }\n\n                // make sure is default scale every frame\n                item.scaleX = 1;\n                item.scaleY = 1;\n                item.opacity = 1;\n            }\n        }\n    };\n\n    var introItemView = function introItemView(item, x, y, vx, vy) {\n        if (item.interactionMethod === InteractionMethod.NONE) {\n            item.translateX = null;\n            item.translateX = x;\n            item.translateY = null;\n            item.translateY = y;\n        } else if (item.interactionMethod === InteractionMethod.DROP) {\n            item.translateX = null;\n            item.translateX = x - vx * 20;\n\n            item.translateY = null;\n            item.translateY = y - vy * 10;\n\n            item.scaleX = 0.8;\n            item.scaleY = 0.8;\n        } else if (item.interactionMethod === InteractionMethod.BROWSE) {\n            item.translateY = null;\n            item.translateY = y - 30;\n        } else if (item.interactionMethod === InteractionMethod.API) {\n            item.translateX = null;\n            item.translateX = x - 30;\n            item.translateY = null;\n        }\n    };\n\n    /**\n     * Removes an existing item\n     * @param root\n     * @param action\n     */\n    var removeItemView = function removeItemView(_ref3) {\n        var root = _ref3.root,\n            action = _ref3.action;\n        var id = action.id;\n\n        // get the view matching the given id\n        var view = root.childViews.find(function(child) {\n            return child.id === id;\n        });\n\n        // if no view found, exit\n        if (!view) {\n            return;\n        }\n\n        // animate view out of view\n        view.scaleX = 0.9;\n        view.scaleY = 0.9;\n        view.opacity = 0;\n\n        // mark for removal\n        view.markedForRemoval = true;\n    };\n\n    var getItemHeight = function getItemHeight(child) {\n        return (\n            child.rect.element.height +\n            child.rect.element.marginBottom +\n            child.rect.element.marginTop\n        );\n    };\n    var getItemWidth = function getItemWidth(child) {\n        return (\n            child.rect.element.width +\n            child.rect.element.marginLeft * 0.5 +\n            child.rect.element.marginRight * 0.5\n        );\n    };\n\n    var dragItem = function dragItem(_ref4) {\n        var root = _ref4.root,\n            action = _ref4.action;\n        var id = action.id,\n            dragState = action.dragState;\n\n        // reference to item\n        var item = root.query('GET_ITEM', { id: id });\n\n        // get the view matching the given id\n        var view = root.childViews.find(function(child) {\n            return child.id === id;\n        });\n\n        var numItems = root.childViews.length;\n        var oldIndex = dragState.getItemIndex(item);\n\n        // if no view found, exit\n        if (!view) return;\n\n        var dragPosition = {\n            x: view.dragOrigin.x + view.dragOffset.x + view.dragCenter.x,\n            y: view.dragOrigin.y + view.dragOffset.y + view.dragCenter.y,\n        };\n\n        // get drag area dimensions\n        var dragHeight = getItemHeight(view);\n        var dragWidth = getItemWidth(view);\n\n        // get rows and columns (There will always be at least one row and one column if a file is present)\n        var cols = Math.floor(root.rect.outer.width / dragWidth);\n        if (cols > numItems) cols = numItems;\n\n        // rows are used to find when we have left the preview area bounding box\n        var rows = Math.floor(numItems / cols + 1);\n\n        dropAreaDimensions.setHeight = dragHeight * rows;\n        dropAreaDimensions.setWidth = dragWidth * cols;\n\n        // get new index of dragged item\n        var location = {\n            y: Math.floor(dragPosition.y / dragHeight),\n            x: Math.floor(dragPosition.x / dragWidth),\n            getGridIndex: function getGridIndex() {\n                if (\n                    dragPosition.y > dropAreaDimensions.getHeight ||\n                    dragPosition.y < 0 ||\n                    dragPosition.x > dropAreaDimensions.getWidth ||\n                    dragPosition.x < 0\n                )\n                    return oldIndex;\n                return this.y * cols + this.x;\n            },\n            getColIndex: function getColIndex() {\n                var items = root.query('GET_ACTIVE_ITEMS');\n                var visibleChildren = root.childViews.filter(function(child) {\n                    return child.rect.element.height;\n                });\n                var children = items.map(function(item) {\n                    return visibleChildren.find(function(childView) {\n                        return childView.id === item.id;\n                    });\n                });\n\n                var currentIndex = children.findIndex(function(child) {\n                    return child === view;\n                });\n                var dragHeight = getItemHeight(view);\n                var l = children.length;\n                var idx = l;\n                var childHeight = 0;\n                var childBottom = 0;\n                var childTop = 0;\n                for (var i = 0; i < l; i++) {\n                    childHeight = getItemHeight(children[i]);\n                    childTop = childBottom;\n                    childBottom = childTop + childHeight;\n                    if (dragPosition.y < childBottom) {\n                        if (currentIndex > i) {\n                            if (dragPosition.y < childTop + dragHeight) {\n                                idx = i;\n                                break;\n                            }\n                            continue;\n                        }\n                        idx = i;\n                        break;\n                    }\n                }\n                return idx;\n            },\n        };\n\n        // get new index\n        var index = cols > 1 ? location.getGridIndex() : location.getColIndex();\n        root.dispatch('MOVE_ITEM', { query: view, index: index });\n\n        // if the index of the item changed, dispatch reorder action\n        var currentIndex = dragState.getIndex();\n\n        if (currentIndex === undefined || currentIndex !== index) {\n            dragState.setIndex(index);\n\n            if (currentIndex === undefined) return;\n\n            root.dispatch('DID_REORDER_ITEMS', {\n                items: root.query('GET_ACTIVE_ITEMS'),\n                origin: oldIndex,\n                target: index,\n            });\n        }\n    };\n\n    /**\n     * Setup action routes\n     */\n    var route$2 = createRoute({\n        DID_ADD_ITEM: addItemView,\n        DID_REMOVE_ITEM: removeItemView,\n        DID_DRAG_ITEM: dragItem,\n    });\n\n    /**\n     * Write to view\n     * @param root\n     * @param actions\n     * @param props\n     */\n    var write$5 = function write(_ref5) {\n        var root = _ref5.root,\n            props = _ref5.props,\n            actions = _ref5.actions,\n            shouldOptimize = _ref5.shouldOptimize;\n        // route actions\n        route$2({ root: root, props: props, actions: actions });\n        var dragCoordinates = props.dragCoordinates;\n\n        // available space on horizontal axis\n        var horizontalSpace = root.rect.element.width;\n\n        // only draw children that have dimensions\n        var visibleChildren = root.childViews.filter(function(child) {\n            return child.rect.element.height;\n        });\n\n        // sort based on current active items\n        var children = root\n            .query('GET_ACTIVE_ITEMS')\n            .map(function(item) {\n                return visibleChildren.find(function(child) {\n                    return child.id === item.id;\n                });\n            })\n            .filter(function(item) {\n                return item;\n            });\n\n        // get index\n        var dragIndex = dragCoordinates\n            ? getItemIndexByPosition(root, children, dragCoordinates)\n            : null;\n\n        // add index is used to reserve the dropped/added item index till the actual item is rendered\n        var addIndex = root.ref.addIndex || null;\n\n        // add index no longer needed till possibly next draw\n        root.ref.addIndex = null;\n\n        var dragIndexOffset = 0;\n        var removeIndexOffset = 0;\n        var addIndexOffset = 0;\n\n        if (children.length === 0) return;\n\n        var childRect = children[0].rect.element;\n        var itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n        var itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n        var itemWidth = childRect.width + itemHorizontalMargin;\n        var itemHeight = childRect.height + itemVerticalMargin;\n        var itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n        // stack\n        if (itemsPerRow === 1) {\n            var offsetY = 0;\n            var dragOffset = 0;\n\n            children.forEach(function(child, index) {\n                if (dragIndex) {\n                    var dist = index - dragIndex;\n                    if (dist === -2) {\n                        dragOffset = -itemVerticalMargin * 0.25;\n                    } else if (dist === -1) {\n                        dragOffset = -itemVerticalMargin * 0.75;\n                    } else if (dist === 0) {\n                        dragOffset = itemVerticalMargin * 0.75;\n                    } else if (dist === 1) {\n                        dragOffset = itemVerticalMargin * 0.25;\n                    } else {\n                        dragOffset = 0;\n                    }\n                }\n\n                if (shouldOptimize) {\n                    child.translateX = null;\n                    child.translateY = null;\n                }\n\n                if (!child.markedForRemoval) {\n                    moveItem(child, 0, offsetY + dragOffset);\n                }\n\n                var itemHeight = child.rect.element.height + itemVerticalMargin;\n\n                var visualHeight = itemHeight * (child.markedForRemoval ? child.opacity : 1);\n\n                offsetY += visualHeight;\n            });\n        }\n        // grid\n        else {\n            var prevX = 0;\n            var prevY = 0;\n\n            children.forEach(function(child, index) {\n                if (index === dragIndex) {\n                    dragIndexOffset = 1;\n                }\n\n                if (index === addIndex) {\n                    addIndexOffset += 1;\n                }\n\n                if (child.markedForRemoval && child.opacity < 0.5) {\n                    removeIndexOffset -= 1;\n                }\n\n                var visualIndex = index + addIndexOffset + dragIndexOffset + removeIndexOffset;\n\n                var indexX = visualIndex % itemsPerRow;\n                var indexY = Math.floor(visualIndex / itemsPerRow);\n\n                var offsetX = indexX * itemWidth;\n                var offsetY = indexY * itemHeight;\n\n                var vectorX = Math.sign(offsetX - prevX);\n                var vectorY = Math.sign(offsetY - prevY);\n\n                prevX = offsetX;\n                prevY = offsetY;\n\n                if (child.markedForRemoval) return;\n\n                if (shouldOptimize) {\n                    child.translateX = null;\n                    child.translateY = null;\n                }\n\n                moveItem(child, offsetX, offsetY, vectorX, vectorY);\n            });\n        }\n    };\n\n    /**\n     * Filters actions that are meant specifically for a certain child of the list\n     * @param child\n     * @param actions\n     */\n    var filterSetItemActions = function filterSetItemActions(child, actions) {\n        return actions.filter(function(action) {\n            // if action has an id, filter out actions that don't have this child id\n            if (action.data && action.data.id) {\n                return child.id === action.data.id;\n            }\n\n            // allow all other actions\n            return true;\n        });\n    };\n\n    var list = createView({\n        create: create$8,\n        write: write$5,\n        tag: 'ul',\n        name: 'list',\n        didWriteView: function didWriteView(_ref6) {\n            var root = _ref6.root;\n            root.childViews\n                .filter(function(view) {\n                    return view.markedForRemoval && view.opacity === 0 && view.resting;\n                })\n                .forEach(function(view) {\n                    view._destroy();\n                    root.removeChildView(view);\n                });\n        },\n        filterFrameActionsForChild: filterSetItemActions,\n        mixins: {\n            apis: ['dragCoordinates'],\n        },\n    });\n\n    var create$9 = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        root.ref.list = root.appendChildView(root.createChildView(list));\n        props.dragCoordinates = null;\n        props.overflowing = false;\n    };\n\n    var storeDragCoordinates = function storeDragCoordinates(_ref2) {\n        var root = _ref2.root,\n            props = _ref2.props,\n            action = _ref2.action;\n        if (!root.query('GET_ITEM_INSERT_LOCATION_FREEDOM')) return;\n        props.dragCoordinates = {\n            left: action.position.scopeLeft - root.ref.list.rect.element.left,\n            top:\n                action.position.scopeTop -\n                (root.rect.outer.top + root.rect.element.marginTop + root.rect.element.scrollTop),\n        };\n    };\n\n    var clearDragCoordinates = function clearDragCoordinates(_ref3) {\n        var props = _ref3.props;\n        props.dragCoordinates = null;\n    };\n\n    var route$3 = createRoute({\n        DID_DRAG: storeDragCoordinates,\n        DID_END_DRAG: clearDragCoordinates,\n    });\n\n    var write$6 = function write(_ref4) {\n        var root = _ref4.root,\n            props = _ref4.props,\n            actions = _ref4.actions;\n\n        // route actions\n        route$3({ root: root, props: props, actions: actions });\n\n        // current drag position\n        root.ref.list.dragCoordinates = props.dragCoordinates;\n\n        // if currently overflowing but no longer received overflow\n        if (props.overflowing && !props.overflow) {\n            props.overflowing = false;\n\n            // reset overflow state\n            root.element.dataset.state = '';\n            root.height = null;\n        }\n\n        // if is not overflowing currently but does receive overflow value\n        if (props.overflow) {\n            var newHeight = Math.round(props.overflow);\n            if (newHeight !== root.height) {\n                props.overflowing = true;\n                root.element.dataset.state = 'overflow';\n                root.height = newHeight;\n            }\n        }\n    };\n\n    var listScroller = createView({\n        create: create$9,\n        write: write$6,\n        name: 'list-scroller',\n        mixins: {\n            apis: ['overflow', 'dragCoordinates'],\n            styles: ['height', 'translateY'],\n            animations: {\n                translateY: 'spring',\n            },\n        },\n    });\n\n    var attrToggle = function attrToggle(element, name, state) {\n        var enabledValue = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';\n        if (state) {\n            attr(element, name, enabledValue);\n        } else {\n            element.removeAttribute(name);\n        }\n    };\n\n    var resetFileInput = function resetFileInput(input) {\n        // no value, no need to reset\n        if (!input || input.value === '') {\n            return;\n        }\n\n        try {\n            // for modern browsers\n            input.value = '';\n        } catch (err) {}\n\n        // for IE10\n        if (input.value) {\n            // quickly append input to temp form and reset form\n            var form = createElement$1('form');\n            var parentNode = input.parentNode;\n            var ref = input.nextSibling;\n            form.appendChild(input);\n            form.reset();\n\n            // re-inject input where it originally was\n            if (ref) {\n                parentNode.insertBefore(input, ref);\n            } else {\n                parentNode.appendChild(input);\n            }\n        }\n    };\n\n    var create$a = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // set id so can be referenced from outside labels\n        root.element.id = 'filepond--browser-' + props.id;\n\n        // set name of element (is removed when a value is set)\n        attr(root.element, 'name', root.query('GET_NAME'));\n\n        // we have to link this element to the status element\n        attr(root.element, 'aria-controls', 'filepond--assistant-' + props.id);\n\n        // set label, we use labelled by as otherwise the screenreader does not read the \"browse\" text in the label (as it has tabindex: 0)\n        attr(root.element, 'aria-labelledby', 'filepond--drop-label-' + props.id);\n\n        // set configurable props\n        setAcceptedFileTypes({\n            root: root,\n            action: { value: root.query('GET_ACCEPTED_FILE_TYPES') },\n        });\n        toggleAllowMultiple({ root: root, action: { value: root.query('GET_ALLOW_MULTIPLE') } });\n        toggleDirectoryFilter({\n            root: root,\n            action: { value: root.query('GET_ALLOW_DIRECTORIES_ONLY') },\n        });\n        toggleDisabled({ root: root });\n        toggleRequired({ root: root, action: { value: root.query('GET_REQUIRED') } });\n        setCaptureMethod({ root: root, action: { value: root.query('GET_CAPTURE_METHOD') } });\n\n        // handle changes to the input field\n        root.ref.handleChange = function(e) {\n            if (!root.element.value) {\n                return;\n            }\n\n            // extract files and move value of webkitRelativePath path to _relativePath\n            var files = Array.from(root.element.files).map(function(file) {\n                file._relativePath = file.webkitRelativePath;\n                return file;\n            });\n\n            // we add a little delay so the OS file select window can move out of the way before we add our file\n            setTimeout(function() {\n                // load files\n                props.onload(files);\n\n                // reset input, it's just for exposing a method to drop files, should not retain any state\n                resetFileInput(root.element);\n            }, 250);\n        };\n\n        root.element.addEventListener('change', root.ref.handleChange);\n    };\n\n    var setAcceptedFileTypes = function setAcceptedFileTypes(_ref2) {\n        var root = _ref2.root,\n            action = _ref2.action;\n        if (!root.query('GET_ALLOW_SYNC_ACCEPT_ATTRIBUTE')) return;\n        attrToggle(\n            root.element,\n            'accept',\n            !!action.value,\n            action.value ? action.value.join(',') : ''\n        );\n    };\n\n    var toggleAllowMultiple = function toggleAllowMultiple(_ref3) {\n        var root = _ref3.root,\n            action = _ref3.action;\n        attrToggle(root.element, 'multiple', action.value);\n    };\n\n    var toggleDirectoryFilter = function toggleDirectoryFilter(_ref4) {\n        var root = _ref4.root,\n            action = _ref4.action;\n        attrToggle(root.element, 'webkitdirectory', action.value);\n    };\n\n    var toggleDisabled = function toggleDisabled(_ref5) {\n        var root = _ref5.root;\n        var isDisabled = root.query('GET_DISABLED');\n        var doesAllowBrowse = root.query('GET_ALLOW_BROWSE');\n        var disableField = isDisabled || !doesAllowBrowse;\n        attrToggle(root.element, 'disabled', disableField);\n    };\n\n    var toggleRequired = function toggleRequired(_ref6) {\n        var root = _ref6.root,\n            action = _ref6.action;\n        // want to remove required, always possible\n        if (!action.value) {\n            attrToggle(root.element, 'required', false);\n        }\n        // if want to make required, only possible when zero items\n        else if (root.query('GET_TOTAL_ITEMS') === 0) {\n            attrToggle(root.element, 'required', true);\n        }\n    };\n\n    var setCaptureMethod = function setCaptureMethod(_ref7) {\n        var root = _ref7.root,\n            action = _ref7.action;\n        attrToggle(\n            root.element,\n            'capture',\n            !!action.value,\n            action.value === true ? '' : action.value\n        );\n    };\n\n    var updateRequiredStatus = function updateRequiredStatus(_ref8) {\n        var root = _ref8.root;\n        var element = root.element;\n        // always remove the required attribute when more than zero items\n        if (root.query('GET_TOTAL_ITEMS') > 0) {\n            attrToggle(element, 'required', false);\n            attrToggle(element, 'name', false);\n\n            // still has items\n            var activeItems = root.query('GET_ACTIVE_ITEMS');\n            var hasInvalidField = false;\n            for (var i = 0; i < activeItems.length; i++) {\n                if (activeItems[i].status === ItemStatus.LOAD_ERROR) {\n                    hasInvalidField = true;\n                }\n            }\n            // set validity status\n            root.element.setCustomValidity(\n                hasInvalidField ? root.query('GET_LABEL_INVALID_FIELD') : ''\n            );\n        } else {\n            // add name attribute\n            attrToggle(element, 'name', true, root.query('GET_NAME'));\n\n            // remove any validation messages\n            var shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n            if (shouldCheckValidity) {\n                element.setCustomValidity('');\n            }\n\n            // we only add required if the field has been deemed required\n            if (root.query('GET_REQUIRED')) {\n                attrToggle(element, 'required', true);\n            }\n        }\n    };\n\n    var updateFieldValidityStatus = function updateFieldValidityStatus(_ref9) {\n        var root = _ref9.root;\n        var shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n        if (!shouldCheckValidity) return;\n        root.element.setCustomValidity(root.query('GET_LABEL_INVALID_FIELD'));\n    };\n\n    var browser = createView({\n        tag: 'input',\n        name: 'browser',\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        attributes: {\n            type: 'file',\n        },\n\n        create: create$a,\n        destroy: function destroy(_ref10) {\n            var root = _ref10.root;\n            root.element.removeEventListener('change', root.ref.handleChange);\n        },\n        write: createRoute({\n            DID_LOAD_ITEM: updateRequiredStatus,\n            DID_REMOVE_ITEM: updateRequiredStatus,\n            DID_THROW_ITEM_INVALID: updateFieldValidityStatus,\n\n            DID_SET_DISABLED: toggleDisabled,\n            DID_SET_ALLOW_BROWSE: toggleDisabled,\n            DID_SET_ALLOW_DIRECTORIES_ONLY: toggleDirectoryFilter,\n            DID_SET_ALLOW_MULTIPLE: toggleAllowMultiple,\n            DID_SET_ACCEPTED_FILE_TYPES: setAcceptedFileTypes,\n            DID_SET_CAPTURE_METHOD: setCaptureMethod,\n            DID_SET_REQUIRED: toggleRequired,\n        }),\n    });\n\n    var Key = {\n        ENTER: 13,\n        SPACE: 32,\n    };\n\n    var create$b = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // create the label and link it to the file browser\n        var label = createElement$1('label');\n        attr(label, 'for', 'filepond--browser-' + props.id);\n\n        // use for labeling file input (aria-labelledby on file input)\n        attr(label, 'id', 'filepond--drop-label-' + props.id);\n\n        // handle keys\n        root.ref.handleKeyDown = function(e) {\n            var isActivationKey = e.keyCode === Key.ENTER || e.keyCode === Key.SPACE;\n            if (!isActivationKey) return;\n            // stops from triggering the element a second time\n            e.preventDefault();\n\n            // click link (will then in turn activate file input)\n            root.ref.label.click();\n        };\n\n        root.ref.handleClick = function(e) {\n            var isLabelClick = e.target === label || label.contains(e.target);\n\n            // don't want to click twice\n            if (isLabelClick) return;\n\n            // click link (will then in turn activate file input)\n            root.ref.label.click();\n        };\n\n        // attach events\n        label.addEventListener('keydown', root.ref.handleKeyDown);\n        root.element.addEventListener('click', root.ref.handleClick);\n\n        // update\n        updateLabelValue(label, props.caption);\n\n        // add!\n        root.appendChild(label);\n        root.ref.label = label;\n    };\n\n    var updateLabelValue = function updateLabelValue(label, value) {\n        label.innerHTML = value;\n        var clickable = label.querySelector('.filepond--label-action');\n        if (clickable) {\n            attr(clickable, 'tabindex', '0');\n        }\n        return value;\n    };\n\n    var dropLabel = createView({\n        name: 'drop-label',\n        ignoreRect: true,\n        create: create$b,\n        destroy: function destroy(_ref2) {\n            var root = _ref2.root;\n            root.ref.label.addEventListener('keydown', root.ref.handleKeyDown);\n            root.element.removeEventListener('click', root.ref.handleClick);\n        },\n        write: createRoute({\n            DID_SET_LABEL_IDLE: function DID_SET_LABEL_IDLE(_ref3) {\n                var root = _ref3.root,\n                    action = _ref3.action;\n                updateLabelValue(root.ref.label, action.value);\n            },\n        }),\n\n        mixins: {\n            styles: ['opacity', 'translateX', 'translateY'],\n            animations: {\n                opacity: { type: 'tween', duration: 150 },\n                translateX: 'spring',\n                translateY: 'spring',\n            },\n        },\n    });\n\n    var blob = createView({\n        name: 'drip-blob',\n        ignoreRect: true,\n        mixins: {\n            styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n            animations: {\n                scaleX: 'spring',\n                scaleY: 'spring',\n                translateX: 'spring',\n                translateY: 'spring',\n                opacity: { type: 'tween', duration: 250 },\n            },\n        },\n    });\n\n    var addBlob = function addBlob(_ref) {\n        var root = _ref.root;\n        var centerX = root.rect.element.width * 0.5;\n        var centerY = root.rect.element.height * 0.5;\n\n        root.ref.blob = root.appendChildView(\n            root.createChildView(blob, {\n                opacity: 0,\n                scaleX: 2.5,\n                scaleY: 2.5,\n                translateX: centerX,\n                translateY: centerY,\n            })\n        );\n    };\n\n    var moveBlob = function moveBlob(_ref2) {\n        var root = _ref2.root,\n            action = _ref2.action;\n        if (!root.ref.blob) {\n            addBlob({ root: root });\n            return;\n        }\n\n        root.ref.blob.translateX = action.position.scopeLeft;\n        root.ref.blob.translateY = action.position.scopeTop;\n        root.ref.blob.scaleX = 1;\n        root.ref.blob.scaleY = 1;\n        root.ref.blob.opacity = 1;\n    };\n\n    var hideBlob = function hideBlob(_ref3) {\n        var root = _ref3.root;\n        if (!root.ref.blob) {\n            return;\n        }\n        root.ref.blob.opacity = 0;\n    };\n\n    var explodeBlob = function explodeBlob(_ref4) {\n        var root = _ref4.root;\n        if (!root.ref.blob) {\n            return;\n        }\n        root.ref.blob.scaleX = 2.5;\n        root.ref.blob.scaleY = 2.5;\n        root.ref.blob.opacity = 0;\n    };\n\n    var write$7 = function write(_ref5) {\n        var root = _ref5.root,\n            props = _ref5.props,\n            actions = _ref5.actions;\n        route$4({ root: root, props: props, actions: actions });\n        var blob = root.ref.blob;\n\n        if (actions.length === 0 && blob && blob.opacity === 0) {\n            root.removeChildView(blob);\n            root.ref.blob = null;\n        }\n    };\n\n    var route$4 = createRoute({\n        DID_DRAG: moveBlob,\n        DID_DROP: explodeBlob,\n        DID_END_DRAG: hideBlob,\n    });\n\n    var drip = createView({\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        name: 'drip',\n        write: write$7,\n    });\n\n    var setInputFiles = function setInputFiles(element, files) {\n        try {\n            // Create a DataTransfer instance and add a newly created file\n            var dataTransfer = new DataTransfer();\n            files.forEach(function(file) {\n                if (file instanceof File) {\n                    dataTransfer.items.add(file);\n                } else {\n                    dataTransfer.items.add(\n                        new File([file], file.name, {\n                            type: file.type,\n                        })\n                    );\n                }\n            });\n\n            // Assign the DataTransfer files list to the file input\n            element.files = dataTransfer.files;\n        } catch (err) {\n            return false;\n        }\n        return true;\n    };\n\n    var create$c = function create(_ref) {\n        var root = _ref.root;\n        root.ref.fields = {};\n        var legend = document.createElement('legend');\n        legend.textContent = 'Files';\n        root.element.appendChild(legend);\n    };\n\n    var getField = function getField(root, id) {\n        return root.ref.fields[id];\n    };\n\n    var syncFieldPositionsWithItems = function syncFieldPositionsWithItems(root) {\n        root.query('GET_ACTIVE_ITEMS').forEach(function(item) {\n            if (!root.ref.fields[item.id]) return;\n            root.element.appendChild(root.ref.fields[item.id]);\n        });\n    };\n\n    var didReorderItems = function didReorderItems(_ref2) {\n        var root = _ref2.root;\n        return syncFieldPositionsWithItems(root);\n    };\n\n    var didAddItem = function didAddItem(_ref3) {\n        var root = _ref3.root,\n            action = _ref3.action;\n        var fileItem = root.query('GET_ITEM', action.id);\n        var isLocalFile = fileItem.origin === FileOrigin.LOCAL;\n        var shouldUseFileInput = !isLocalFile && root.query('SHOULD_UPDATE_FILE_INPUT');\n        var dataContainer = createElement$1('input');\n        dataContainer.type = shouldUseFileInput ? 'file' : 'hidden';\n        dataContainer.name = root.query('GET_NAME');\n        root.ref.fields[action.id] = dataContainer;\n        syncFieldPositionsWithItems(root);\n    };\n\n    var didLoadItem$1 = function didLoadItem(_ref4) {\n        var root = _ref4.root,\n            action = _ref4.action;\n        var field = getField(root, action.id);\n        if (!field) return;\n\n        // store server ref in hidden input\n        if (action.serverFileReference !== null) field.value = action.serverFileReference;\n\n        // store file item in file input\n        if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n\n        var fileItem = root.query('GET_ITEM', action.id);\n        setInputFiles(field, [fileItem.file]);\n    };\n\n    var didPrepareOutput = function didPrepareOutput(_ref5) {\n        var root = _ref5.root,\n            action = _ref5.action;\n        // this timeout pushes the handler after 'load'\n        if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n        setTimeout(function() {\n            var field = getField(root, action.id);\n            if (!field) return;\n            setInputFiles(field, [action.file]);\n        }, 0);\n    };\n\n    var didSetDisabled = function didSetDisabled(_ref6) {\n        var root = _ref6.root;\n        root.element.disabled = root.query('GET_DISABLED');\n    };\n\n    var didRemoveItem = function didRemoveItem(_ref7) {\n        var root = _ref7.root,\n            action = _ref7.action;\n        var field = getField(root, action.id);\n        if (!field) return;\n        if (field.parentNode) field.parentNode.removeChild(field);\n        delete root.ref.fields[action.id];\n    };\n\n    // only runs for server files. will refuse to update the value if the field\n    // is a file field\n    var didDefineValue = function didDefineValue(_ref8) {\n        var root = _ref8.root,\n            action = _ref8.action;\n        var field = getField(root, action.id);\n        if (!field) return;\n        if (action.value === null) {\n            // clear field value\n            field.removeAttribute('value');\n        } else {\n            // set field value\n            if (field.type != 'file') {\n                field.value = action.value;\n            }\n        }\n        syncFieldPositionsWithItems(root);\n    };\n\n    var write$8 = createRoute({\n        DID_SET_DISABLED: didSetDisabled,\n        DID_ADD_ITEM: didAddItem,\n        DID_LOAD_ITEM: didLoadItem$1,\n        DID_REMOVE_ITEM: didRemoveItem,\n        DID_DEFINE_VALUE: didDefineValue,\n        DID_PREPARE_OUTPUT: didPrepareOutput,\n        DID_REORDER_ITEMS: didReorderItems,\n        DID_SORT_ITEMS: didReorderItems,\n    });\n\n    var data = createView({\n        tag: 'fieldset',\n        name: 'data',\n        create: create$c,\n        write: write$8,\n        ignoreRect: true,\n    });\n\n    var getRootNode = function getRootNode(element) {\n        return 'getRootNode' in element ? element.getRootNode() : document;\n    };\n\n    var images = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff'];\n    var text$1 = ['css', 'csv', 'html', 'txt'];\n    var map = {\n        zip: 'zip|compressed',\n        epub: 'application/epub+zip',\n    };\n\n    var guesstimateMimeType = function guesstimateMimeType() {\n        var extension = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n        extension = extension.toLowerCase();\n        if (images.includes(extension)) {\n            return (\n                'image/' +\n                (extension === 'jpg' ? 'jpeg' : extension === 'svg' ? 'svg+xml' : extension)\n            );\n        }\n        if (text$1.includes(extension)) {\n            return 'text/' + extension;\n        }\n\n        return map[extension] || '';\n    };\n\n    var requestDataTransferItems = function requestDataTransferItems(dataTransfer) {\n        return new Promise(function(resolve, reject) {\n            // try to get links from transfer, if found we'll exit immediately (unless a file is in the dataTransfer as well, this is because Firefox could represent the file as a URL and a file object at the same time)\n            var links = getLinks(dataTransfer);\n            if (links.length && !hasFiles(dataTransfer)) {\n                return resolve(links);\n            }\n            // try to get files from the transfer\n            getFiles(dataTransfer).then(resolve);\n        });\n    };\n\n    /**\n     * Test if datatransfer has files\n     */\n    var hasFiles = function hasFiles(dataTransfer) {\n        if (dataTransfer.files) return dataTransfer.files.length > 0;\n        return false;\n    };\n\n    /**\n     * Extracts files from a DataTransfer object\n     */\n    var getFiles = function getFiles(dataTransfer) {\n        return new Promise(function(resolve, reject) {\n            // get the transfer items as promises\n            var promisedFiles = (dataTransfer.items ? Array.from(dataTransfer.items) : [])\n                // only keep file system items (files and directories)\n                .filter(function(item) {\n                    return isFileSystemItem(item);\n                })\n\n                // map each item to promise\n                .map(function(item) {\n                    return getFilesFromItem(item);\n                });\n\n            // if is empty, see if we can extract some info from the files property as a fallback\n            if (!promisedFiles.length) {\n                // TODO: test for directories (should not be allowed)\n                // Use FileReader, problem is that the files property gets lost in the process\n                resolve(dataTransfer.files ? Array.from(dataTransfer.files) : []);\n                return;\n            }\n\n            // done!\n            Promise.all(promisedFiles)\n                .then(function(returnedFileGroups) {\n                    // flatten groups\n                    var files = [];\n                    returnedFileGroups.forEach(function(group) {\n                        files.push.apply(files, group);\n                    });\n\n                    // done (filter out empty files)!\n                    resolve(\n                        files\n                            .filter(function(file) {\n                                return file;\n                            })\n                            .map(function(file) {\n                                if (!file._relativePath)\n                                    file._relativePath = file.webkitRelativePath;\n                                return file;\n                            })\n                    );\n                })\n                .catch(console.error);\n        });\n    };\n\n    var isFileSystemItem = function isFileSystemItem(item) {\n        if (isEntry(item)) {\n            var entry = getAsEntry(item);\n            if (entry) {\n                return entry.isFile || entry.isDirectory;\n            }\n        }\n        return item.kind === 'file';\n    };\n\n    var getFilesFromItem = function getFilesFromItem(item) {\n        return new Promise(function(resolve, reject) {\n            if (isDirectoryEntry(item)) {\n                getFilesInDirectory(getAsEntry(item))\n                    .then(resolve)\n                    .catch(reject);\n                return;\n            }\n\n            resolve([item.getAsFile()]);\n        });\n    };\n\n    var getFilesInDirectory = function getFilesInDirectory(entry) {\n        return new Promise(function(resolve, reject) {\n            var files = [];\n\n            // the total entries to read\n            var dirCounter = 0;\n            var fileCounter = 0;\n\n            var resolveIfDone = function resolveIfDone() {\n                if (fileCounter === 0 && dirCounter === 0) {\n                    resolve(files);\n                }\n            };\n\n            // the recursive function\n            var readEntries = function readEntries(dirEntry) {\n                dirCounter++;\n\n                var directoryReader = dirEntry.createReader();\n\n                // directories are returned in batches, we need to process all batches before we're done\n                var readBatch = function readBatch() {\n                    directoryReader.readEntries(function(entries) {\n                        if (entries.length === 0) {\n                            dirCounter--;\n                            resolveIfDone();\n                            return;\n                        }\n\n                        entries.forEach(function(entry) {\n                            // recursively read more directories\n                            if (entry.isDirectory) {\n                                readEntries(entry);\n                            } else {\n                                // read as file\n                                fileCounter++;\n\n                                entry.file(function(file) {\n                                    var correctedFile = correctMissingFileType(file);\n                                    if (entry.fullPath)\n                                        correctedFile._relativePath = entry.fullPath;\n                                    files.push(correctedFile);\n                                    fileCounter--;\n                                    resolveIfDone();\n                                });\n                            }\n                        });\n\n                        // try to get next batch of files\n                        readBatch();\n                    }, reject);\n                };\n\n                // read first batch of files\n                readBatch();\n            };\n\n            // go!\n            readEntries(entry);\n        });\n    };\n\n    var correctMissingFileType = function correctMissingFileType(file) {\n        if (file.type.length) return file;\n        var date = file.lastModifiedDate;\n        var name = file.name;\n        var type = guesstimateMimeType(getExtensionFromFilename(file.name));\n        if (!type.length) return file;\n        file = file.slice(0, file.size, type);\n        file.name = name;\n        file.lastModifiedDate = date;\n        return file;\n    };\n\n    var isDirectoryEntry = function isDirectoryEntry(item) {\n        return isEntry(item) && (getAsEntry(item) || {}).isDirectory;\n    };\n\n    var isEntry = function isEntry(item) {\n        return 'webkitGetAsEntry' in item;\n    };\n\n    var getAsEntry = function getAsEntry(item) {\n        return item.webkitGetAsEntry();\n    };\n\n    /**\n     * Extracts links from a DataTransfer object\n     */\n    var getLinks = function getLinks(dataTransfer) {\n        var links = [];\n        try {\n            // look in meta data property\n            links = getLinksFromTransferMetaData(dataTransfer);\n            if (links.length) {\n                return links;\n            }\n            links = getLinksFromTransferURLData(dataTransfer);\n        } catch (e) {\n            // nope nope nope (probably IE trouble)\n        }\n        return links;\n    };\n\n    var getLinksFromTransferURLData = function getLinksFromTransferURLData(dataTransfer) {\n        var data = dataTransfer.getData('url');\n        if (typeof data === 'string' && data.length) {\n            return [data];\n        }\n        return [];\n    };\n\n    var getLinksFromTransferMetaData = function getLinksFromTransferMetaData(dataTransfer) {\n        var data = dataTransfer.getData('text/html');\n        if (typeof data === 'string' && data.length) {\n            var matches = data.match(/src\\s*=\\s*\"(.+?)\"/);\n            if (matches) {\n                return [matches[1]];\n            }\n        }\n        return [];\n    };\n\n    var dragNDropObservers = [];\n\n    var eventPosition = function eventPosition(e) {\n        return {\n            pageLeft: e.pageX,\n            pageTop: e.pageY,\n            scopeLeft: e.offsetX || e.layerX,\n            scopeTop: e.offsetY || e.layerY,\n        };\n    };\n\n    var createDragNDropClient = function createDragNDropClient(\n        element,\n        scopeToObserve,\n        filterElement\n    ) {\n        var observer = getDragNDropObserver(scopeToObserve);\n\n        var client = {\n            element: element,\n            filterElement: filterElement,\n            state: null,\n            ondrop: function ondrop() {},\n            onenter: function onenter() {},\n            ondrag: function ondrag() {},\n            onexit: function onexit() {},\n            onload: function onload() {},\n            allowdrop: function allowdrop() {},\n        };\n\n        client.destroy = observer.addListener(client);\n\n        return client;\n    };\n\n    var getDragNDropObserver = function getDragNDropObserver(element) {\n        // see if already exists, if so, return\n        var observer = dragNDropObservers.find(function(item) {\n            return item.element === element;\n        });\n        if (observer) {\n            return observer;\n        }\n\n        // create new observer, does not yet exist for this element\n        var newObserver = createDragNDropObserver(element);\n        dragNDropObservers.push(newObserver);\n        return newObserver;\n    };\n\n    var createDragNDropObserver = function createDragNDropObserver(element) {\n        var clients = [];\n\n        var routes = {\n            dragenter: dragenter,\n            dragover: dragover,\n            dragleave: dragleave,\n            drop: drop,\n        };\n\n        var handlers = {};\n\n        forin(routes, function(event, createHandler) {\n            handlers[event] = createHandler(element, clients);\n            element.addEventListener(event, handlers[event], false);\n        });\n\n        var observer = {\n            element: element,\n            addListener: function addListener(client) {\n                // add as client\n                clients.push(client);\n\n                // return removeListener function\n                return function() {\n                    // remove client\n                    clients.splice(clients.indexOf(client), 1);\n\n                    // if no more clients, clean up observer\n                    if (clients.length === 0) {\n                        dragNDropObservers.splice(dragNDropObservers.indexOf(observer), 1);\n\n                        forin(routes, function(event) {\n                            element.removeEventListener(event, handlers[event], false);\n                        });\n                    }\n                };\n            },\n        };\n\n        return observer;\n    };\n\n    var elementFromPoint = function elementFromPoint(root, point) {\n        if (!('elementFromPoint' in root)) {\n            root = document;\n        }\n        return root.elementFromPoint(point.x, point.y);\n    };\n\n    var isEventTarget = function isEventTarget(e, target) {\n        // get root\n        var root = getRootNode(target);\n\n        // get element at position\n        // if root is not actual shadow DOM and does not have elementFromPoint method, use the one on document\n        var elementAtPosition = elementFromPoint(root, {\n            x: e.pageX - window.pageXOffset,\n            y: e.pageY - window.pageYOffset,\n        });\n\n        // test if target is the element or if one of its children is\n        return elementAtPosition === target || target.contains(elementAtPosition);\n    };\n\n    var initialTarget = null;\n\n    var setDropEffect = function setDropEffect(dataTransfer, effect) {\n        // is in try catch as IE11 will throw error if not\n        try {\n            dataTransfer.dropEffect = effect;\n        } catch (e) {}\n    };\n\n    var dragenter = function dragenter(root, clients) {\n        return function(e) {\n            e.preventDefault();\n\n            initialTarget = e.target;\n\n            clients.forEach(function(client) {\n                var element = client.element,\n                    onenter = client.onenter;\n\n                if (isEventTarget(e, element)) {\n                    client.state = 'enter';\n\n                    // fire enter event\n                    onenter(eventPosition(e));\n                }\n            });\n        };\n    };\n\n    var dragover = function dragover(root, clients) {\n        return function(e) {\n            e.preventDefault();\n\n            var dataTransfer = e.dataTransfer;\n\n            requestDataTransferItems(dataTransfer).then(function(items) {\n                var overDropTarget = false;\n\n                clients.some(function(client) {\n                    var filterElement = client.filterElement,\n                        element = client.element,\n                        onenter = client.onenter,\n                        onexit = client.onexit,\n                        ondrag = client.ondrag,\n                        allowdrop = client.allowdrop;\n\n                    // by default we can drop\n                    setDropEffect(dataTransfer, 'copy');\n\n                    // allow transfer of these items\n                    var allowsTransfer = allowdrop(items);\n\n                    // only used when can be dropped on page\n                    if (!allowsTransfer) {\n                        setDropEffect(dataTransfer, 'none');\n                        return;\n                    }\n\n                    // targetting this client\n                    if (isEventTarget(e, element)) {\n                        overDropTarget = true;\n\n                        // had no previous state, means we are entering this client\n                        if (client.state === null) {\n                            client.state = 'enter';\n                            onenter(eventPosition(e));\n                            return;\n                        }\n\n                        // now over element (no matter if it allows the drop or not)\n                        client.state = 'over';\n\n                        // needs to allow transfer\n                        if (filterElement && !allowsTransfer) {\n                            setDropEffect(dataTransfer, 'none');\n                            return;\n                        }\n\n                        // dragging\n                        ondrag(eventPosition(e));\n                    } else {\n                        // should be over an element to drop\n                        if (filterElement && !overDropTarget) {\n                            setDropEffect(dataTransfer, 'none');\n                        }\n\n                        // might have just left this client?\n                        if (client.state) {\n                            client.state = null;\n                            onexit(eventPosition(e));\n                        }\n                    }\n                });\n            });\n        };\n    };\n\n    var drop = function drop(root, clients) {\n        return function(e) {\n            e.preventDefault();\n\n            var dataTransfer = e.dataTransfer;\n\n            requestDataTransferItems(dataTransfer).then(function(items) {\n                clients.forEach(function(client) {\n                    var filterElement = client.filterElement,\n                        element = client.element,\n                        ondrop = client.ondrop,\n                        onexit = client.onexit,\n                        allowdrop = client.allowdrop;\n\n                    client.state = null;\n\n                    // if we're filtering on element we need to be over the element to drop\n                    if (filterElement && !isEventTarget(e, element)) return;\n\n                    // no transfer for this client\n                    if (!allowdrop(items)) return onexit(eventPosition(e));\n\n                    // we can drop these items on this client\n                    ondrop(eventPosition(e), items);\n                });\n            });\n        };\n    };\n\n    var dragleave = function dragleave(root, clients) {\n        return function(e) {\n            if (initialTarget !== e.target) {\n                return;\n            }\n\n            clients.forEach(function(client) {\n                var onexit = client.onexit;\n\n                client.state = null;\n\n                onexit(eventPosition(e));\n            });\n        };\n    };\n\n    var createHopper = function createHopper(scope, validateItems, options) {\n        // is now hopper scope\n        scope.classList.add('filepond--hopper');\n\n        // shortcuts\n        var catchesDropsOnPage = options.catchesDropsOnPage,\n            requiresDropOnElement = options.requiresDropOnElement,\n            _options$filterItems = options.filterItems,\n            filterItems =\n                _options$filterItems === void 0\n                    ? function(items) {\n                          return items;\n                      }\n                    : _options$filterItems;\n\n        // create a dnd client\n        var client = createDragNDropClient(\n            scope,\n            catchesDropsOnPage ? document.documentElement : scope,\n            requiresDropOnElement\n        );\n\n        // current client state\n        var lastState = '';\n        var currentState = '';\n\n        // determines if a file may be dropped\n        client.allowdrop = function(items) {\n            // TODO: if we can, throw error to indicate the items cannot by dropped\n\n            return validateItems(filterItems(items));\n        };\n\n        client.ondrop = function(position, items) {\n            var filteredItems = filterItems(items);\n\n            if (!validateItems(filteredItems)) {\n                api.ondragend(position);\n                return;\n            }\n\n            currentState = 'drag-drop';\n\n            api.onload(filteredItems, position);\n        };\n\n        client.ondrag = function(position) {\n            api.ondrag(position);\n        };\n\n        client.onenter = function(position) {\n            currentState = 'drag-over';\n\n            api.ondragstart(position);\n        };\n\n        client.onexit = function(position) {\n            currentState = 'drag-exit';\n\n            api.ondragend(position);\n        };\n\n        var api = {\n            updateHopperState: function updateHopperState() {\n                if (lastState !== currentState) {\n                    scope.dataset.hopperState = currentState;\n                    lastState = currentState;\n                }\n            },\n            onload: function onload() {},\n            ondragstart: function ondragstart() {},\n            ondrag: function ondrag() {},\n            ondragend: function ondragend() {},\n            destroy: function destroy() {\n                // destroy client\n                client.destroy();\n            },\n        };\n\n        return api;\n    };\n\n    var listening = false;\n    var listeners$1 = [];\n\n    var handlePaste = function handlePaste(e) {\n        // if is pasting in input or textarea and the target is outside of a filepond scope, ignore\n        var activeEl = document.activeElement;\n        var isActiveElementEditable =\n            activeEl &&\n            (/textarea|input/i.test(activeEl.nodeName) ||\n                activeEl.getAttribute('contenteditable') === 'true' ||\n                activeEl.getAttribute('contenteditable') === '');\n\n        if (isActiveElementEditable) {\n            // test textarea or input is contained in filepond root\n            var inScope = false;\n            var element = activeEl;\n            while (element !== document.body) {\n                if (element.classList.contains('filepond--root')) {\n                    inScope = true;\n                    break;\n                }\n                element = element.parentNode;\n            }\n\n            if (!inScope) return;\n        }\n\n        requestDataTransferItems(e.clipboardData).then(function(files) {\n            // no files received\n            if (!files.length) {\n                return;\n            }\n\n            // notify listeners of received files\n            listeners$1.forEach(function(listener) {\n                return listener(files);\n            });\n        });\n    };\n\n    var listen = function listen(cb) {\n        // can't add twice\n        if (listeners$1.includes(cb)) {\n            return;\n        }\n\n        // add initial listener\n        listeners$1.push(cb);\n\n        // setup paste listener for entire page\n        if (listening) {\n            return;\n        }\n\n        listening = true;\n        document.addEventListener('paste', handlePaste);\n    };\n\n    var unlisten = function unlisten(listener) {\n        arrayRemove(listeners$1, listeners$1.indexOf(listener));\n\n        // clean up\n        if (listeners$1.length === 0) {\n            document.removeEventListener('paste', handlePaste);\n            listening = false;\n        }\n    };\n\n    var createPaster = function createPaster() {\n        var cb = function cb(files) {\n            api.onload(files);\n        };\n\n        var api = {\n            destroy: function destroy() {\n                unlisten(cb);\n            },\n            onload: function onload() {},\n        };\n\n        listen(cb);\n\n        return api;\n    };\n\n    /**\n     * Creates the file view\n     */\n    var create$d = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        root.element.id = 'filepond--assistant-' + props.id;\n        attr(root.element, 'role', 'alert');\n        attr(root.element, 'aria-live', 'polite');\n        attr(root.element, 'aria-relevant', 'additions');\n    };\n\n    var addFilesNotificationTimeout = null;\n    var notificationClearTimeout = null;\n\n    var filenames = [];\n\n    var assist = function assist(root, message) {\n        root.element.textContent = message;\n    };\n\n    var clear$1 = function clear(root) {\n        root.element.textContent = '';\n    };\n\n    var listModified = function listModified(root, filename, label) {\n        var total = root.query('GET_TOTAL_ITEMS');\n        assist(\n            root,\n            label +\n                ' ' +\n                filename +\n                ', ' +\n                total +\n                ' ' +\n                (total === 1\n                    ? root.query('GET_LABEL_FILE_COUNT_SINGULAR')\n                    : root.query('GET_LABEL_FILE_COUNT_PLURAL'))\n        );\n\n        // clear group after set amount of time so the status is not read twice\n        clearTimeout(notificationClearTimeout);\n        notificationClearTimeout = setTimeout(function() {\n            clear$1(root);\n        }, 1500);\n    };\n\n    var isUsingFilePond = function isUsingFilePond(root) {\n        return root.element.parentNode.contains(document.activeElement);\n    };\n\n    var itemAdded = function itemAdded(_ref2) {\n        var root = _ref2.root,\n            action = _ref2.action;\n        if (!isUsingFilePond(root)) {\n            return;\n        }\n\n        root.element.textContent = '';\n        var item = root.query('GET_ITEM', action.id);\n        filenames.push(item.filename);\n\n        clearTimeout(addFilesNotificationTimeout);\n        addFilesNotificationTimeout = setTimeout(function() {\n            listModified(root, filenames.join(', '), root.query('GET_LABEL_FILE_ADDED'));\n            filenames.length = 0;\n        }, 750);\n    };\n\n    var itemRemoved = function itemRemoved(_ref3) {\n        var root = _ref3.root,\n            action = _ref3.action;\n        if (!isUsingFilePond(root)) {\n            return;\n        }\n\n        var item = action.item;\n        listModified(root, item.filename, root.query('GET_LABEL_FILE_REMOVED'));\n    };\n\n    var itemProcessed = function itemProcessed(_ref4) {\n        var root = _ref4.root,\n            action = _ref4.action;\n        // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n        var item = root.query('GET_ITEM', action.id);\n        var filename = item.filename;\n        var label = root.query('GET_LABEL_FILE_PROCESSING_COMPLETE');\n\n        assist(root, filename + ' ' + label);\n    };\n\n    var itemProcessedUndo = function itemProcessedUndo(_ref5) {\n        var root = _ref5.root,\n            action = _ref5.action;\n        var item = root.query('GET_ITEM', action.id);\n        var filename = item.filename;\n        var label = root.query('GET_LABEL_FILE_PROCESSING_ABORTED');\n\n        assist(root, filename + ' ' + label);\n    };\n\n    var itemError = function itemError(_ref6) {\n        var root = _ref6.root,\n            action = _ref6.action;\n        var item = root.query('GET_ITEM', action.id);\n        var filename = item.filename;\n\n        // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n        assist(root, action.status.main + ' ' + filename + ' ' + action.status.sub);\n    };\n\n    var assistant = createView({\n        create: create$d,\n        ignoreRect: true,\n        ignoreRectUpdate: true,\n        write: createRoute({\n            DID_LOAD_ITEM: itemAdded,\n            DID_REMOVE_ITEM: itemRemoved,\n            DID_COMPLETE_ITEM_PROCESSING: itemProcessed,\n\n            DID_ABORT_ITEM_PROCESSING: itemProcessedUndo,\n            DID_REVERT_ITEM_PROCESSING: itemProcessedUndo,\n\n            DID_THROW_ITEM_REMOVE_ERROR: itemError,\n            DID_THROW_ITEM_LOAD_ERROR: itemError,\n            DID_THROW_ITEM_INVALID: itemError,\n            DID_THROW_ITEM_PROCESSING_ERROR: itemError,\n        }),\n\n        tag: 'span',\n        name: 'assistant',\n    });\n\n    var toCamels = function toCamels(string) {\n        var separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '-';\n        return string.replace(new RegExp(separator + '.', 'g'), function(sub) {\n            return sub.charAt(1).toUpperCase();\n        });\n    };\n\n    var debounce = function debounce(func) {\n        var interval = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 16;\n        var immidiateOnly =\n            arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n        var last = Date.now();\n        var timeout = null;\n\n        return function() {\n            for (\n                var _len = arguments.length, args = new Array(_len), _key = 0;\n                _key < _len;\n                _key++\n            ) {\n                args[_key] = arguments[_key];\n            }\n            clearTimeout(timeout);\n\n            var dist = Date.now() - last;\n\n            var fn = function fn() {\n                last = Date.now();\n                func.apply(void 0, args);\n            };\n\n            if (dist < interval) {\n                // we need to delay by the difference between interval and dist\n                // for example: if distance is 10 ms and interval is 16 ms,\n                // we need to wait an additional 6ms before calling the function)\n                if (!immidiateOnly) {\n                    timeout = setTimeout(fn, interval - dist);\n                }\n            } else {\n                // go!\n                fn();\n            }\n        };\n    };\n\n    var MAX_FILES_LIMIT = 1000000;\n\n    var prevent = function prevent(e) {\n        return e.preventDefault();\n    };\n\n    var create$e = function create(_ref) {\n        var root = _ref.root,\n            props = _ref.props;\n        // Add id\n        var id = root.query('GET_ID');\n        if (id) {\n            root.element.id = id;\n        }\n\n        // Add className\n        var className = root.query('GET_CLASS_NAME');\n        if (className) {\n            className\n                .split(' ')\n                .filter(function(name) {\n                    return name.length;\n                })\n                .forEach(function(name) {\n                    root.element.classList.add(name);\n                });\n        }\n\n        // Field label\n        root.ref.label = root.appendChildView(\n            root.createChildView(\n                dropLabel,\n                Object.assign({}, props, {\n                    translateY: null,\n                    caption: root.query('GET_LABEL_IDLE'),\n                })\n            )\n        );\n\n        // List of items\n        root.ref.list = root.appendChildView(\n            root.createChildView(listScroller, { translateY: null })\n        );\n\n        // Background panel\n        root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'panel-root' }));\n\n        // Assistant notifies assistive tech when content changes\n        root.ref.assistant = root.appendChildView(\n            root.createChildView(assistant, Object.assign({}, props))\n        );\n\n        // Data\n        root.ref.data = root.appendChildView(root.createChildView(data, Object.assign({}, props)));\n\n        // Measure (tests if fixed height was set)\n        // DOCTYPE needs to be set for this to work\n        root.ref.measure = createElement$1('div');\n        root.ref.measure.style.height = '100%';\n        root.element.appendChild(root.ref.measure);\n\n        // information on the root height or fixed height status\n        root.ref.bounds = null;\n\n        // apply initial style properties\n        root.query('GET_STYLES')\n            .filter(function(style) {\n                return !isEmpty(style.value);\n            })\n            .map(function(_ref2) {\n                var name = _ref2.name,\n                    value = _ref2.value;\n                root.element.dataset[name] = value;\n            });\n\n        // determine if width changed\n        root.ref.widthPrevious = null;\n        root.ref.widthUpdated = debounce(function() {\n            root.ref.updateHistory = [];\n            root.dispatch('DID_RESIZE_ROOT');\n        }, 250);\n\n        // history of updates\n        root.ref.previousAspectRatio = null;\n        root.ref.updateHistory = [];\n\n        // prevent scrolling and zooming on iOS (only if supports pointer events, for then we can enable reorder)\n        var canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;\n        var hasPointerEvents = 'PointerEvent' in window;\n        if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {\n            root.element.addEventListener('touchmove', prevent, { passive: false });\n            root.element.addEventListener('gesturestart', prevent);\n        }\n\n        // add credits\n        var credits = root.query('GET_CREDITS');\n        var hasCredits = credits.length === 2;\n        if (hasCredits) {\n            var frag = document.createElement('a');\n            frag.className = 'filepond--credits';\n            frag.href = credits[0];\n            frag.tabIndex = -1;\n            frag.target = '_blank';\n            frag.rel = 'noopener noreferrer nofollow';\n            frag.textContent = credits[1];\n            root.element.appendChild(frag);\n            root.ref.credits = frag;\n        }\n    };\n\n    var write$9 = function write(_ref3) {\n        var root = _ref3.root,\n            props = _ref3.props,\n            actions = _ref3.actions;\n        // route actions\n        route$5({ root: root, props: props, actions: actions });\n\n        // apply style properties\n        actions\n            .filter(function(action) {\n                return /^DID_SET_STYLE_/.test(action.type);\n            })\n            .filter(function(action) {\n                return !isEmpty(action.data.value);\n            })\n            .map(function(_ref4) {\n                var type = _ref4.type,\n                    data = _ref4.data;\n                var name = toCamels(type.substring(8).toLowerCase(), '_');\n                root.element.dataset[name] = data.value;\n                root.invalidateLayout();\n            });\n\n        if (root.rect.element.hidden) return;\n\n        if (root.rect.element.width !== root.ref.widthPrevious) {\n            root.ref.widthPrevious = root.rect.element.width;\n            root.ref.widthUpdated();\n        }\n\n        // get box bounds, we do this only once\n        var bounds = root.ref.bounds;\n        if (!bounds) {\n            bounds = root.ref.bounds = calculateRootBoundingBoxHeight(root);\n\n            // destroy measure element\n            root.element.removeChild(root.ref.measure);\n            root.ref.measure = null;\n        }\n\n        // get quick references to various high level parts of the upload tool\n        var _root$ref = root.ref,\n            hopper = _root$ref.hopper,\n            label = _root$ref.label,\n            list = _root$ref.list,\n            panel = _root$ref.panel;\n\n        // sets correct state to hopper scope\n        if (hopper) {\n            hopper.updateHopperState();\n        }\n\n        // bool to indicate if we're full or not\n        var aspectRatio = root.query('GET_PANEL_ASPECT_RATIO');\n        var isMultiItem = root.query('GET_ALLOW_MULTIPLE');\n        var totalItems = root.query('GET_TOTAL_ITEMS');\n        var maxItems = isMultiItem ? root.query('GET_MAX_FILES') || MAX_FILES_LIMIT : 1;\n        var atMaxCapacity = totalItems === maxItems;\n\n        // action used to add item\n        var addAction = actions.find(function(action) {\n            return action.type === 'DID_ADD_ITEM';\n        });\n\n        // if reached max capacity and we've just reached it\n        if (atMaxCapacity && addAction) {\n            // get interaction type\n            var interactionMethod = addAction.data.interactionMethod;\n\n            // hide label\n            label.opacity = 0;\n\n            if (isMultiItem) {\n                label.translateY = -40;\n            } else {\n                if (interactionMethod === InteractionMethod.API) {\n                    label.translateX = 40;\n                } else if (interactionMethod === InteractionMethod.BROWSE) {\n                    label.translateY = 40;\n                } else {\n                    label.translateY = 30;\n                }\n            }\n        } else if (!atMaxCapacity) {\n            label.opacity = 1;\n            label.translateX = 0;\n            label.translateY = 0;\n        }\n\n        var listItemMargin = calculateListItemMargin(root);\n\n        var listHeight = calculateListHeight(root);\n\n        var labelHeight = label.rect.element.height;\n        var currentLabelHeight = !isMultiItem || atMaxCapacity ? 0 : labelHeight;\n\n        var listMarginTop = atMaxCapacity ? list.rect.element.marginTop : 0;\n        var listMarginBottom = totalItems === 0 ? 0 : list.rect.element.marginBottom;\n\n        var visualHeight =\n            currentLabelHeight + listMarginTop + listHeight.visual + listMarginBottom;\n        var boundsHeight =\n            currentLabelHeight + listMarginTop + listHeight.bounds + listMarginBottom;\n\n        // link list to label bottom position\n        list.translateY =\n            Math.max(0, currentLabelHeight - list.rect.element.marginTop) - listItemMargin.top;\n\n        if (aspectRatio) {\n            // fixed aspect ratio\n\n            // calculate height based on width\n            var width = root.rect.element.width;\n            var height = width * aspectRatio;\n\n            // clear history if aspect ratio has changed\n            if (aspectRatio !== root.ref.previousAspectRatio) {\n                root.ref.previousAspectRatio = aspectRatio;\n                root.ref.updateHistory = [];\n            }\n\n            // remember this width\n            var history = root.ref.updateHistory;\n            history.push(width);\n\n            var MAX_BOUNCES = 2;\n            if (history.length > MAX_BOUNCES * 2) {\n                var l = history.length;\n                var bottom = l - 10;\n                var bounces = 0;\n                for (var i = l; i >= bottom; i--) {\n                    if (history[i] === history[i - 2]) {\n                        bounces++;\n                    }\n\n                    if (bounces >= MAX_BOUNCES) {\n                        // dont adjust height\n                        return;\n                    }\n                }\n            }\n\n            // fix height of panel so it adheres to aspect ratio\n            panel.scalable = false;\n            panel.height = height;\n\n            // available height for list\n            var listAvailableHeight =\n                // the height of the panel minus the label height\n                height -\n                currentLabelHeight -\n                // the room we leave open between the end of the list and the panel bottom\n                (listMarginBottom - listItemMargin.bottom) -\n                // if we're full we need to leave some room between the top of the panel and the list\n                (atMaxCapacity ? listMarginTop : 0);\n\n            if (listHeight.visual > listAvailableHeight) {\n                list.overflow = listAvailableHeight;\n            } else {\n                list.overflow = null;\n            }\n\n            // set container bounds (so pushes siblings downwards)\n            root.height = height;\n        } else if (bounds.fixedHeight) {\n            // fixed height\n\n            // fix height of panel\n            panel.scalable = false;\n\n            // available height for list\n            var _listAvailableHeight =\n                // the height of the panel minus the label height\n                bounds.fixedHeight -\n                currentLabelHeight -\n                // the room we leave open between the end of the list and the panel bottom\n                (listMarginBottom - listItemMargin.bottom) -\n                // if we're full we need to leave some room between the top of the panel and the list\n                (atMaxCapacity ? listMarginTop : 0);\n\n            // set list height\n            if (listHeight.visual > _listAvailableHeight) {\n                list.overflow = _listAvailableHeight;\n            } else {\n                list.overflow = null;\n            }\n\n            // no need to set container bounds as these are handles by CSS fixed height\n        } else if (bounds.cappedHeight) {\n            // max-height\n\n            // not a fixed height panel\n            var isCappedHeight = visualHeight >= bounds.cappedHeight;\n            var panelHeight = Math.min(bounds.cappedHeight, visualHeight);\n            panel.scalable = true;\n            panel.height = isCappedHeight\n                ? panelHeight\n                : panelHeight - listItemMargin.top - listItemMargin.bottom;\n\n            // available height for list\n            var _listAvailableHeight2 =\n                // the height of the panel minus the label height\n                panelHeight -\n                currentLabelHeight -\n                // the room we leave open between the end of the list and the panel bottom\n                (listMarginBottom - listItemMargin.bottom) -\n                // if we're full we need to leave some room between the top of the panel and the list\n                (atMaxCapacity ? listMarginTop : 0);\n\n            // set list height (if is overflowing)\n            if (visualHeight > bounds.cappedHeight && listHeight.visual > _listAvailableHeight2) {\n                list.overflow = _listAvailableHeight2;\n            } else {\n                list.overflow = null;\n            }\n\n            // set container bounds (so pushes siblings downwards)\n            root.height = Math.min(\n                bounds.cappedHeight,\n                boundsHeight - listItemMargin.top - listItemMargin.bottom\n            );\n        } else {\n            // flexible height\n\n            // not a fixed height panel\n            var itemMargin = totalItems > 0 ? listItemMargin.top + listItemMargin.bottom : 0;\n            panel.scalable = true;\n            panel.height = Math.max(labelHeight, visualHeight - itemMargin);\n\n            // set container bounds (so pushes siblings downwards)\n            root.height = Math.max(labelHeight, boundsHeight - itemMargin);\n        }\n\n        // move credits to bottom\n        if (root.ref.credits && panel.heightCurrent)\n            root.ref.credits.style.transform = 'translateY(' + panel.heightCurrent + 'px)';\n    };\n\n    var calculateListItemMargin = function calculateListItemMargin(root) {\n        var item = root.ref.list.childViews[0].childViews[0];\n        return item\n            ? {\n                  top: item.rect.element.marginTop,\n                  bottom: item.rect.element.marginBottom,\n              }\n            : {\n                  top: 0,\n                  bottom: 0,\n              };\n    };\n\n    var calculateListHeight = function calculateListHeight(root) {\n        var visual = 0;\n        var bounds = 0;\n\n        // get file list reference\n        var scrollList = root.ref.list;\n        var itemList = scrollList.childViews[0];\n        var visibleChildren = itemList.childViews.filter(function(child) {\n            return child.rect.element.height;\n        });\n        var children = root\n            .query('GET_ACTIVE_ITEMS')\n            .map(function(item) {\n                return visibleChildren.find(function(child) {\n                    return child.id === item.id;\n                });\n            })\n            .filter(function(item) {\n                return item;\n            });\n\n        // no children, done!\n        if (children.length === 0) return { visual: visual, bounds: bounds };\n\n        var horizontalSpace = itemList.rect.element.width;\n        var dragIndex = getItemIndexByPosition(itemList, children, scrollList.dragCoordinates);\n\n        var childRect = children[0].rect.element;\n\n        var itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n        var itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n\n        var itemWidth = childRect.width + itemHorizontalMargin;\n        var itemHeight = childRect.height + itemVerticalMargin;\n\n        var newItem = typeof dragIndex !== 'undefined' && dragIndex >= 0 ? 1 : 0;\n        var removedItem = children.find(function(child) {\n            return child.markedForRemoval && child.opacity < 0.45;\n        })\n            ? -1\n            : 0;\n        var verticalItemCount = children.length + newItem + removedItem;\n        var itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n        // stack\n        if (itemsPerRow === 1) {\n            children.forEach(function(item) {\n                var height = item.rect.element.height + itemVerticalMargin;\n                bounds += height;\n                visual += height * item.opacity;\n            });\n        }\n        // grid\n        else {\n            bounds = Math.ceil(verticalItemCount / itemsPerRow) * itemHeight;\n            visual = bounds;\n        }\n\n        return { visual: visual, bounds: bounds };\n    };\n\n    var calculateRootBoundingBoxHeight = function calculateRootBoundingBoxHeight(root) {\n        var height = root.ref.measureHeight || null;\n        var cappedHeight = parseInt(root.style.maxHeight, 10) || null;\n        var fixedHeight = height === 0 ? null : height;\n\n        return {\n            cappedHeight: cappedHeight,\n            fixedHeight: fixedHeight,\n        };\n    };\n\n    var exceedsMaxFiles = function exceedsMaxFiles(root, items) {\n        var allowReplace = root.query('GET_ALLOW_REPLACE');\n        var allowMultiple = root.query('GET_ALLOW_MULTIPLE');\n        var totalItems = root.query('GET_TOTAL_ITEMS');\n        var maxItems = root.query('GET_MAX_FILES');\n\n        // total amount of items being dragged\n        var totalBrowseItems = items.length;\n\n        // if does not allow multiple items and dragging more than one item\n        if (!allowMultiple && totalBrowseItems > 1) {\n            root.dispatch('DID_THROW_MAX_FILES', {\n                source: items,\n                error: createResponse('warning', 0, 'Max files'),\n            });\n\n            return true;\n        }\n\n        // limit max items to one if not allowed to drop multiple items\n        maxItems = allowMultiple ? maxItems : 1;\n\n        if (!allowMultiple && allowReplace) {\n            // There is only one item, so there is room to replace or add an item\n            return false;\n        }\n\n        // no more room?\n        var hasMaxItems = isInt(maxItems);\n        if (hasMaxItems && totalItems + totalBrowseItems > maxItems) {\n            root.dispatch('DID_THROW_MAX_FILES', {\n                source: items,\n                error: createResponse('warning', 0, 'Max files'),\n            });\n\n            return true;\n        }\n\n        return false;\n    };\n\n    var getDragIndex = function getDragIndex(list, children, position) {\n        var itemList = list.childViews[0];\n        return getItemIndexByPosition(itemList, children, {\n            left: position.scopeLeft - itemList.rect.element.left,\n            top:\n                position.scopeTop -\n                (list.rect.outer.top + list.rect.element.marginTop + list.rect.element.scrollTop),\n        });\n    };\n\n    /**\n     * Enable or disable file drop functionality\n     */\n    var toggleDrop = function toggleDrop(root) {\n        var isAllowed = root.query('GET_ALLOW_DROP');\n        var isDisabled = root.query('GET_DISABLED');\n        var enabled = isAllowed && !isDisabled;\n        if (enabled && !root.ref.hopper) {\n            var hopper = createHopper(\n                root.element,\n                function(items) {\n                    // allow quick validation of dropped items\n                    var beforeDropFile =\n                        root.query('GET_BEFORE_DROP_FILE') ||\n                        function() {\n                            return true;\n                        };\n\n                    // all items should be validated by all filters as valid\n                    var dropValidation = root.query('GET_DROP_VALIDATION');\n                    return dropValidation\n                        ? items.every(function(item) {\n                              return (\n                                  applyFilters('ALLOW_HOPPER_ITEM', item, {\n                                      query: root.query,\n                                  }).every(function(result) {\n                                      return result === true;\n                                  }) && beforeDropFile(item)\n                              );\n                          })\n                        : true;\n                },\n                {\n                    filterItems: function filterItems(items) {\n                        var ignoredFiles = root.query('GET_IGNORED_FILES');\n                        return items.filter(function(item) {\n                            if (isFile(item)) {\n                                return !ignoredFiles.includes(item.name.toLowerCase());\n                            }\n                            return true;\n                        });\n                    },\n                    catchesDropsOnPage: root.query('GET_DROP_ON_PAGE'),\n                    requiresDropOnElement: root.query('GET_DROP_ON_ELEMENT'),\n                }\n            );\n\n            hopper.onload = function(items, position) {\n                // get item children elements and sort based on list sort\n                var list = root.ref.list.childViews[0];\n                var visibleChildren = list.childViews.filter(function(child) {\n                    return child.rect.element.height;\n                });\n                var children = root\n                    .query('GET_ACTIVE_ITEMS')\n                    .map(function(item) {\n                        return visibleChildren.find(function(child) {\n                            return child.id === item.id;\n                        });\n                    })\n                    .filter(function(item) {\n                        return item;\n                    });\n\n                applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(function(\n                    queue\n                ) {\n                    // these files don't fit so stop here\n                    if (exceedsMaxFiles(root, queue)) return false;\n\n                    // go\n                    root.dispatch('ADD_ITEMS', {\n                        items: queue,\n                        index: getDragIndex(root.ref.list, children, position),\n                        interactionMethod: InteractionMethod.DROP,\n                    });\n                });\n\n                root.dispatch('DID_DROP', { position: position });\n\n                root.dispatch('DID_END_DRAG', { position: position });\n            };\n\n            hopper.ondragstart = function(position) {\n                root.dispatch('DID_START_DRAG', { position: position });\n            };\n\n            hopper.ondrag = debounce(function(position) {\n                root.dispatch('DID_DRAG', { position: position });\n            });\n\n            hopper.ondragend = function(position) {\n                root.dispatch('DID_END_DRAG', { position: position });\n            };\n\n            root.ref.hopper = hopper;\n\n            root.ref.drip = root.appendChildView(root.createChildView(drip));\n        } else if (!enabled && root.ref.hopper) {\n            root.ref.hopper.destroy();\n            root.ref.hopper = null;\n            root.removeChildView(root.ref.drip);\n        }\n    };\n\n    /**\n     * Enable or disable browse functionality\n     */\n    var toggleBrowse = function toggleBrowse(root, props) {\n        var isAllowed = root.query('GET_ALLOW_BROWSE');\n        var isDisabled = root.query('GET_DISABLED');\n        var enabled = isAllowed && !isDisabled;\n        if (enabled && !root.ref.browser) {\n            root.ref.browser = root.appendChildView(\n                root.createChildView(\n                    browser,\n                    Object.assign({}, props, {\n                        onload: function onload(items) {\n                            applyFilterChain('ADD_ITEMS', items, {\n                                dispatch: root.dispatch,\n                            }).then(function(queue) {\n                                // these files don't fit so stop here\n                                if (exceedsMaxFiles(root, queue)) return false;\n\n                                // add items!\n                                root.dispatch('ADD_ITEMS', {\n                                    items: queue,\n                                    index: -1,\n                                    interactionMethod: InteractionMethod.BROWSE,\n                                });\n                            });\n                        },\n                    })\n                ),\n\n                0\n            );\n        } else if (!enabled && root.ref.browser) {\n            root.removeChildView(root.ref.browser);\n            root.ref.browser = null;\n        }\n    };\n\n    /**\n     * Enable or disable paste functionality\n     */\n    var togglePaste = function togglePaste(root) {\n        var isAllowed = root.query('GET_ALLOW_PASTE');\n        var isDisabled = root.query('GET_DISABLED');\n        var enabled = isAllowed && !isDisabled;\n        if (enabled && !root.ref.paster) {\n            root.ref.paster = createPaster();\n            root.ref.paster.onload = function(items) {\n                applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(function(\n                    queue\n                ) {\n                    // these files don't fit so stop here\n                    if (exceedsMaxFiles(root, queue)) return false;\n\n                    // add items!\n                    root.dispatch('ADD_ITEMS', {\n                        items: queue,\n                        index: -1,\n                        interactionMethod: InteractionMethod.PASTE,\n                    });\n                });\n            };\n        } else if (!enabled && root.ref.paster) {\n            root.ref.paster.destroy();\n            root.ref.paster = null;\n        }\n    };\n\n    /**\n     * Route actions\n     */\n    var route$5 = createRoute({\n        DID_SET_ALLOW_BROWSE: function DID_SET_ALLOW_BROWSE(_ref5) {\n            var root = _ref5.root,\n                props = _ref5.props;\n            toggleBrowse(root, props);\n        },\n        DID_SET_ALLOW_DROP: function DID_SET_ALLOW_DROP(_ref6) {\n            var root = _ref6.root;\n            toggleDrop(root);\n        },\n        DID_SET_ALLOW_PASTE: function DID_SET_ALLOW_PASTE(_ref7) {\n            var root = _ref7.root;\n            togglePaste(root);\n        },\n        DID_SET_DISABLED: function DID_SET_DISABLED(_ref8) {\n            var root = _ref8.root,\n                props = _ref8.props;\n            toggleDrop(root);\n            togglePaste(root);\n            toggleBrowse(root, props);\n            var isDisabled = root.query('GET_DISABLED');\n            if (isDisabled) {\n                root.element.dataset.disabled = 'disabled';\n            } else {\n                // delete root.element.dataset.disabled; <= this does not work on iOS 10\n                root.element.removeAttribute('data-disabled');\n            }\n        },\n    });\n\n    var root = createView({\n        name: 'root',\n        read: function read(_ref9) {\n            var root = _ref9.root;\n            if (root.ref.measure) {\n                root.ref.measureHeight = root.ref.measure.offsetHeight;\n            }\n        },\n        create: create$e,\n        write: write$9,\n        destroy: function destroy(_ref10) {\n            var root = _ref10.root;\n            if (root.ref.paster) {\n                root.ref.paster.destroy();\n            }\n            if (root.ref.hopper) {\n                root.ref.hopper.destroy();\n            }\n            root.element.removeEventListener('touchmove', prevent);\n            root.element.removeEventListener('gesturestart', prevent);\n        },\n        mixins: {\n            styles: ['height'],\n        },\n    });\n\n    // creates the app\n    var createApp = function createApp() {\n        var initialOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n        // let element\n        var originalElement = null;\n\n        // get default options\n        var defaultOptions = getOptions();\n\n        // create the data store, this will contain all our app info\n        var store = createStore(\n            // initial state (should be serializable)\n            createInitialState(defaultOptions),\n\n            // queries\n            [queries, createOptionQueries(defaultOptions)],\n\n            // action handlers\n            [actions, createOptionActions(defaultOptions)]\n        );\n\n        // set initial options\n        store.dispatch('SET_OPTIONS', { options: initialOptions });\n\n        // kick thread if visibility changes\n        var visibilityHandler = function visibilityHandler() {\n            if (document.hidden) return;\n            store.dispatch('KICK');\n        };\n        document.addEventListener('visibilitychange', visibilityHandler);\n\n        // re-render on window resize start and finish\n        var resizeDoneTimer = null;\n        var isResizing = false;\n        var isResizingHorizontally = false;\n        var initialWindowWidth = null;\n        var currentWindowWidth = null;\n        var resizeHandler = function resizeHandler() {\n            if (!isResizing) {\n                isResizing = true;\n            }\n            clearTimeout(resizeDoneTimer);\n            resizeDoneTimer = setTimeout(function() {\n                isResizing = false;\n                initialWindowWidth = null;\n                currentWindowWidth = null;\n                if (isResizingHorizontally) {\n                    isResizingHorizontally = false;\n                    store.dispatch('DID_STOP_RESIZE');\n                }\n            }, 500);\n        };\n        window.addEventListener('resize', resizeHandler);\n\n        // render initial view\n        var view = root(store, { id: getUniqueId() });\n\n        //\n        // PRIVATE API -------------------------------------------------------------------------------------\n        //\n        var isResting = false;\n        var isHidden = false;\n\n        var readWriteApi = {\n            // necessary for update loop\n\n            /**\n             * Reads from dom (never call manually)\n             * @private\n             */\n            _read: function _read() {\n                // test if we're resizing horizontally\n                // TODO: see if we can optimize this by measuring root rect\n                if (isResizing) {\n                    currentWindowWidth = window.innerWidth;\n                    if (!initialWindowWidth) {\n                        initialWindowWidth = currentWindowWidth;\n                    }\n\n                    if (!isResizingHorizontally && currentWindowWidth !== initialWindowWidth) {\n                        store.dispatch('DID_START_RESIZE');\n                        isResizingHorizontally = true;\n                    }\n                }\n\n                if (isHidden && isResting) {\n                    // test if is no longer hidden\n                    isResting = view.element.offsetParent === null;\n                }\n\n                // if resting, no need to read as numbers will still all be correct\n                if (isResting) return;\n\n                // read view data\n                view._read();\n\n                // if is hidden we need to know so we exit rest mode when revealed\n                isHidden = view.rect.element.hidden;\n            },\n\n            /**\n             * Writes to dom (never call manually)\n             * @private\n             */\n            _write: function _write(ts) {\n                // get all actions from store\n                var actions = store\n                    .processActionQueue()\n\n                    // filter out set actions (these will automatically trigger DID_SET)\n                    .filter(function(action) {\n                        return !/^SET_/.test(action.type);\n                    });\n\n                // if was idling and no actions stop here\n                if (isResting && !actions.length) return;\n\n                // some actions might trigger events\n                routeActionsToEvents(actions);\n\n                // update the view\n                isResting = view._write(ts, actions, isResizingHorizontally);\n\n                // will clean up all archived items\n                removeReleasedItems(store.query('GET_ITEMS'));\n\n                // now idling\n                if (isResting) {\n                    store.processDispatchQueue();\n                }\n            },\n        };\n\n        //\n        // EXPOSE EVENTS -------------------------------------------------------------------------------------\n        //\n        var createEvent = function createEvent(name) {\n            return function(data) {\n                // create default event\n                var event = {\n                    type: name,\n                };\n\n                // no data to add\n                if (!data) {\n                    return event;\n                }\n\n                // copy relevant props\n                if (data.hasOwnProperty('error')) {\n                    event.error = data.error ? Object.assign({}, data.error) : null;\n                }\n\n                if (data.status) {\n                    event.status = Object.assign({}, data.status);\n                }\n\n                if (data.file) {\n                    event.output = data.file;\n                }\n\n                // only source is available, else add item if possible\n                if (data.source) {\n                    event.file = data.source;\n                } else if (data.item || data.id) {\n                    var item = data.item ? data.item : store.query('GET_ITEM', data.id);\n                    event.file = item ? createItemAPI(item) : null;\n                }\n\n                // map all items in a possible items array\n                if (data.items) {\n                    event.items = data.items.map(createItemAPI);\n                }\n\n                // if this is a progress event add the progress amount\n                if (/progress/.test(name)) {\n                    event.progress = data.progress;\n                }\n\n                // copy relevant props\n                if (data.hasOwnProperty('origin') && data.hasOwnProperty('target')) {\n                    event.origin = data.origin;\n                    event.target = data.target;\n                }\n\n                return event;\n            };\n        };\n\n        var eventRoutes = {\n            DID_DESTROY: createEvent('destroy'),\n\n            DID_INIT: createEvent('init'),\n\n            DID_THROW_MAX_FILES: createEvent('warning'),\n\n            DID_INIT_ITEM: createEvent('initfile'),\n            DID_START_ITEM_LOAD: createEvent('addfilestart'),\n            DID_UPDATE_ITEM_LOAD_PROGRESS: createEvent('addfileprogress'),\n            DID_LOAD_ITEM: createEvent('addfile'),\n\n            DID_THROW_ITEM_INVALID: [createEvent('error'), createEvent('addfile')],\n\n            DID_THROW_ITEM_LOAD_ERROR: [createEvent('error'), createEvent('addfile')],\n\n            DID_THROW_ITEM_REMOVE_ERROR: [createEvent('error'), createEvent('removefile')],\n\n            DID_PREPARE_OUTPUT: createEvent('preparefile'),\n\n            DID_START_ITEM_PROCESSING: createEvent('processfilestart'),\n            DID_UPDATE_ITEM_PROCESS_PROGRESS: createEvent('processfileprogress'),\n            DID_ABORT_ITEM_PROCESSING: createEvent('processfileabort'),\n            DID_COMPLETE_ITEM_PROCESSING: createEvent('processfile'),\n            DID_COMPLETE_ITEM_PROCESSING_ALL: createEvent('processfiles'),\n            DID_REVERT_ITEM_PROCESSING: createEvent('processfilerevert'),\n\n            DID_THROW_ITEM_PROCESSING_ERROR: [createEvent('error'), createEvent('processfile')],\n\n            DID_REMOVE_ITEM: createEvent('removefile'),\n\n            DID_UPDATE_ITEMS: createEvent('updatefiles'),\n\n            DID_ACTIVATE_ITEM: createEvent('activatefile'),\n\n            DID_REORDER_ITEMS: createEvent('reorderfiles'),\n        };\n\n        var exposeEvent = function exposeEvent(event) {\n            // create event object to be dispatched\n            var detail = Object.assign({ pond: exports }, event);\n            delete detail.type;\n            view.element.dispatchEvent(\n                new CustomEvent('FilePond:' + event.type, {\n                    // event info\n                    detail: detail,\n\n                    // event behaviour\n                    bubbles: true,\n                    cancelable: true,\n                    composed: true, // triggers listeners outside of shadow root\n                })\n            );\n\n            // event object to params used for `on()` event handlers and callbacks `oninit()`\n            var params = [];\n\n            // if is possible error event, make it the first param\n            if (event.hasOwnProperty('error')) {\n                params.push(event.error);\n            }\n\n            // file is always section\n            if (event.hasOwnProperty('file')) {\n                params.push(event.file);\n            }\n\n            // append other props\n            var filtered = ['type', 'error', 'file'];\n            Object.keys(event)\n                .filter(function(key) {\n                    return !filtered.includes(key);\n                })\n                .forEach(function(key) {\n                    return params.push(event[key]);\n                });\n\n            // on(type, () => { })\n            exports.fire.apply(exports, [event.type].concat(params));\n\n            // oninit = () => {}\n            var handler = store.query('GET_ON' + event.type.toUpperCase());\n            if (handler) {\n                handler.apply(void 0, params);\n            }\n        };\n\n        var routeActionsToEvents = function routeActionsToEvents(actions) {\n            if (!actions.length) return;\n            actions\n                .filter(function(action) {\n                    return eventRoutes[action.type];\n                })\n                .forEach(function(action) {\n                    var routes = eventRoutes[action.type];\n                    (Array.isArray(routes) ? routes : [routes]).forEach(function(route) {\n                        // this isn't fantastic, but because of the stacking of settimeouts plugins can handle the did_load before the did_init\n                        if (action.type === 'DID_INIT_ITEM') {\n                            exposeEvent(route(action.data));\n                        } else {\n                            setTimeout(function() {\n                                exposeEvent(route(action.data));\n                            }, 0);\n                        }\n                    });\n                });\n        };\n\n        //\n        // PUBLIC API -------------------------------------------------------------------------------------\n        //\n        var setOptions = function setOptions(options) {\n            return store.dispatch('SET_OPTIONS', { options: options });\n        };\n\n        var getFile = function getFile(query) {\n            return store.query('GET_ACTIVE_ITEM', query);\n        };\n\n        var prepareFile = function prepareFile(query) {\n            return new Promise(function(resolve, reject) {\n                store.dispatch('REQUEST_ITEM_PREPARE', {\n                    query: query,\n                    success: function success(item) {\n                        resolve(item);\n                    },\n                    failure: function failure(error) {\n                        reject(error);\n                    },\n                });\n            });\n        };\n\n        var addFile = function addFile(source) {\n            var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n            return new Promise(function(resolve, reject) {\n                addFiles([{ source: source, options: options }], { index: options.index })\n                    .then(function(items) {\n                        return resolve(items && items[0]);\n                    })\n                    .catch(reject);\n            });\n        };\n\n        var isFilePondFile = function isFilePondFile(obj) {\n            return obj.file && obj.id;\n        };\n\n        var removeFile = function removeFile(query, options) {\n            // if only passed options\n            if (typeof query === 'object' && !isFilePondFile(query) && !options) {\n                options = query;\n                query = undefined;\n            }\n\n            // request item removal\n            store.dispatch('REMOVE_ITEM', Object.assign({}, options, { query: query }));\n\n            // see if item has been removed\n            return store.query('GET_ACTIVE_ITEM', query) === null;\n        };\n\n        var addFiles = function addFiles() {\n            for (\n                var _len = arguments.length, args = new Array(_len), _key = 0;\n                _key < _len;\n                _key++\n            ) {\n                args[_key] = arguments[_key];\n            }\n            return new Promise(function(resolve, reject) {\n                var sources = [];\n                var options = {};\n\n                // user passed a sources array\n                if (isArray(args[0])) {\n                    sources.push.apply(sources, args[0]);\n                    Object.assign(options, args[1] || {});\n                } else {\n                    // user passed sources as arguments, last one might be options object\n                    var lastArgument = args[args.length - 1];\n                    if (typeof lastArgument === 'object' && !(lastArgument instanceof Blob)) {\n                        Object.assign(options, args.pop());\n                    }\n\n                    // add rest to sources\n                    sources.push.apply(sources, args);\n                }\n\n                store.dispatch('ADD_ITEMS', {\n                    items: sources,\n                    index: options.index,\n                    interactionMethod: InteractionMethod.API,\n                    success: resolve,\n                    failure: reject,\n                });\n            });\n        };\n\n        var getFiles = function getFiles() {\n            return store.query('GET_ACTIVE_ITEMS');\n        };\n\n        var processFile = function processFile(query) {\n            return new Promise(function(resolve, reject) {\n                store.dispatch('REQUEST_ITEM_PROCESSING', {\n                    query: query,\n                    success: function success(item) {\n                        resolve(item);\n                    },\n                    failure: function failure(error) {\n                        reject(error);\n                    },\n                });\n            });\n        };\n\n        var prepareFiles = function prepareFiles() {\n            for (\n                var _len2 = arguments.length, args = new Array(_len2), _key2 = 0;\n                _key2 < _len2;\n                _key2++\n            ) {\n                args[_key2] = arguments[_key2];\n            }\n            var queries = Array.isArray(args[0]) ? args[0] : args;\n            var items = queries.length ? queries : getFiles();\n            return Promise.all(items.map(prepareFile));\n        };\n\n        var processFiles = function processFiles() {\n            for (\n                var _len3 = arguments.length, args = new Array(_len3), _key3 = 0;\n                _key3 < _len3;\n                _key3++\n            ) {\n                args[_key3] = arguments[_key3];\n            }\n            var queries = Array.isArray(args[0]) ? args[0] : args;\n            if (!queries.length) {\n                var files = getFiles().filter(function(item) {\n                    return (\n                        !(item.status === ItemStatus.IDLE && item.origin === FileOrigin.LOCAL) &&\n                        item.status !== ItemStatus.PROCESSING &&\n                        item.status !== ItemStatus.PROCESSING_COMPLETE &&\n                        item.status !== ItemStatus.PROCESSING_REVERT_ERROR\n                    );\n                });\n\n                return Promise.all(files.map(processFile));\n            }\n            return Promise.all(queries.map(processFile));\n        };\n\n        var removeFiles = function removeFiles() {\n            for (\n                var _len4 = arguments.length, args = new Array(_len4), _key4 = 0;\n                _key4 < _len4;\n                _key4++\n            ) {\n                args[_key4] = arguments[_key4];\n            }\n\n            var queries = Array.isArray(args[0]) ? args[0] : args;\n\n            var options;\n            if (typeof queries[queries.length - 1] === 'object') {\n                options = queries.pop();\n            } else if (Array.isArray(args[0])) {\n                options = args[1];\n            }\n\n            var files = getFiles();\n\n            if (!queries.length)\n                return Promise.all(\n                    files.map(function(file) {\n                        return removeFile(file, options);\n                    })\n                );\n\n            // when removing by index the indexes shift after each file removal so we need to convert indexes to ids\n            var mappedQueries = queries\n                .map(function(query) {\n                    return isNumber(query) ? (files[query] ? files[query].id : null) : query;\n                })\n                .filter(function(query) {\n                    return query;\n                });\n\n            return mappedQueries.map(function(q) {\n                return removeFile(q, options);\n            });\n        };\n\n        var exports = Object.assign(\n            {},\n\n            on(),\n            {},\n\n            readWriteApi,\n            {},\n\n            createOptionAPI(store, defaultOptions),\n            {\n                /**\n                 * Override options defined in options object\n                 * @param options\n                 */\n                setOptions: setOptions,\n\n                /**\n                 * Load the given file\n                 * @param source - the source of the file (either a File, base64 data uri or url)\n                 * @param options - object, { index: 0 }\n                 */\n                addFile: addFile,\n\n                /**\n                 * Load the given files\n                 * @param sources - the sources of the files to load\n                 * @param options - object, { index: 0 }\n                 */\n                addFiles: addFiles,\n\n                /**\n                 * Returns the file objects matching the given query\n                 * @param query { string, number, null }\n                 */\n                getFile: getFile,\n\n                /**\n                 * Upload file with given name\n                 * @param query { string, number, null  }\n                 */\n                processFile: processFile,\n\n                /**\n                 * Request prepare output for file with given name\n                 * @param query { string, number, null  }\n                 */\n                prepareFile: prepareFile,\n\n                /**\n                 * Removes a file by its name\n                 * @param query { string, number, null  }\n                 */\n                removeFile: removeFile,\n\n                /**\n                 * Moves a file to a new location in the files list\n                 */\n                moveFile: function moveFile(query, index) {\n                    return store.dispatch('MOVE_ITEM', { query: query, index: index });\n                },\n\n                /**\n                 * Returns all files (wrapped in public api)\n                 */\n                getFiles: getFiles,\n\n                /**\n                 * Starts uploading all files\n                 */\n                processFiles: processFiles,\n\n                /**\n                 * Clears all files from the files list\n                 */\n                removeFiles: removeFiles,\n\n                /**\n                 * Starts preparing output of all files\n                 */\n                prepareFiles: prepareFiles,\n\n                /**\n                 * Sort list of files\n                 */\n                sort: function sort(compare) {\n                    return store.dispatch('SORT', { compare: compare });\n                },\n\n                /**\n                 * Browse the file system for a file\n                 */\n                browse: function browse() {\n                    // needs to be trigger directly as user action needs to be traceable (is not traceable in requestAnimationFrame)\n                    var input = view.element.querySelector('input[type=file]');\n                    if (input) {\n                        input.click();\n                    }\n                },\n\n                /**\n                 * Destroys the app\n                 */\n                destroy: function destroy() {\n                    // request destruction\n                    exports.fire('destroy', view.element);\n\n                    // stop active processes (file uploads, fetches, stuff like that)\n                    // loop over items and depending on states call abort for ongoing processes\n                    store.dispatch('ABORT_ALL');\n\n                    // destroy view\n                    view._destroy();\n\n                    // stop listening to resize\n                    window.removeEventListener('resize', resizeHandler);\n\n                    // stop listening to the visiblitychange event\n                    document.removeEventListener('visibilitychange', visibilityHandler);\n\n                    // dispatch destroy\n                    store.dispatch('DID_DESTROY');\n                },\n\n                /**\n                 * Inserts the plugin before the target element\n                 */\n                insertBefore: function insertBefore$1(element) {\n                    return insertBefore(view.element, element);\n                },\n\n                /**\n                 * Inserts the plugin after the target element\n                 */\n                insertAfter: function insertAfter$1(element) {\n                    return insertAfter(view.element, element);\n                },\n\n                /**\n                 * Appends the plugin to the target element\n                 */\n                appendTo: function appendTo(element) {\n                    return element.appendChild(view.element);\n                },\n\n                /**\n                 * Replaces an element with the app\n                 */\n                replaceElement: function replaceElement(element) {\n                    // insert the app before the element\n                    insertBefore(view.element, element);\n\n                    // remove the original element\n                    element.parentNode.removeChild(element);\n\n                    // remember original element\n                    originalElement = element;\n                },\n\n                /**\n                 * Restores the original element\n                 */\n                restoreElement: function restoreElement() {\n                    if (!originalElement) {\n                        return; // no element to restore\n                    }\n\n                    // restore original element\n                    insertAfter(originalElement, view.element);\n\n                    // remove our element\n                    view.element.parentNode.removeChild(view.element);\n\n                    // remove reference\n                    originalElement = null;\n                },\n\n                /**\n                 * Returns true if the app root is attached to given element\n                 * @param element\n                 */\n                isAttachedTo: function isAttachedTo(element) {\n                    return view.element === element || originalElement === element;\n                },\n\n                /**\n                 * Returns the root element\n                 */\n                element: {\n                    get: function get() {\n                        return view.element;\n                    },\n                },\n\n                /**\n                 * Returns the current pond status\n                 */\n                status: {\n                    get: function get() {\n                        return store.query('GET_STATUS');\n                    },\n                },\n            }\n        );\n\n        // Done!\n        store.dispatch('DID_INIT');\n\n        // create actual api object\n        return createObject(exports);\n    };\n\n    var createAppObject = function createAppObject() {\n        var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n        // default options\n        var defaultOptions = {};\n        forin(getOptions(), function(key, value) {\n            defaultOptions[key] = value[0];\n        });\n\n        // set app options\n        var app = createApp(\n            Object.assign(\n                {},\n\n                defaultOptions,\n                {},\n\n                customOptions\n            )\n        );\n\n        // return the plugin instance\n        return app;\n    };\n\n    var lowerCaseFirstLetter = function lowerCaseFirstLetter(string) {\n        return string.charAt(0).toLowerCase() + string.slice(1);\n    };\n\n    var attributeNameToPropertyName = function attributeNameToPropertyName(attributeName) {\n        return toCamels(attributeName.replace(/^data-/, ''));\n    };\n\n    var mapObject = function mapObject(object, propertyMap) {\n        // remove unwanted\n        forin(propertyMap, function(selector, mapping) {\n            forin(object, function(property, value) {\n                // create regexp shortcut\n                var selectorRegExp = new RegExp(selector);\n\n                // tests if\n                var matches = selectorRegExp.test(property);\n\n                // no match, skip\n                if (!matches) {\n                    return;\n                }\n\n                // if there's a mapping, the original property is always removed\n                delete object[property];\n\n                // should only remove, we done!\n                if (mapping === false) {\n                    return;\n                }\n\n                // move value to new property\n                if (isString(mapping)) {\n                    object[mapping] = value;\n                    return;\n                }\n\n                // move to group\n                var group = mapping.group;\n                if (isObject(mapping) && !object[group]) {\n                    object[group] = {};\n                }\n\n                object[group][lowerCaseFirstLetter(property.replace(selectorRegExp, ''))] = value;\n            });\n\n            // do submapping\n            if (mapping.mapping) {\n                mapObject(object[mapping.group], mapping.mapping);\n            }\n        });\n    };\n\n    var getAttributesAsObject = function getAttributesAsObject(node) {\n        var attributeMapping =\n            arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n        // turn attributes into object\n        var attributes = [];\n        forin(node.attributes, function(index) {\n            attributes.push(node.attributes[index]);\n        });\n\n        var output = attributes\n            .filter(function(attribute) {\n                return attribute.name;\n            })\n            .reduce(function(obj, attribute) {\n                var value = attr(node, attribute.name);\n\n                obj[attributeNameToPropertyName(attribute.name)] =\n                    value === attribute.name ? true : value;\n                return obj;\n            }, {});\n\n        // do mapping of object properties\n        mapObject(output, attributeMapping);\n\n        return output;\n    };\n\n    var createAppAtElement = function createAppAtElement(element) {\n        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n        // how attributes of the input element are mapped to the options for the plugin\n        var attributeMapping = {\n            // translate to other name\n            '^class$': 'className',\n            '^multiple$': 'allowMultiple',\n            '^capture$': 'captureMethod',\n            '^webkitdirectory$': 'allowDirectoriesOnly',\n\n            // group under single property\n            '^server': {\n                group: 'server',\n                mapping: {\n                    '^process': {\n                        group: 'process',\n                    },\n\n                    '^revert': {\n                        group: 'revert',\n                    },\n\n                    '^fetch': {\n                        group: 'fetch',\n                    },\n\n                    '^restore': {\n                        group: 'restore',\n                    },\n\n                    '^load': {\n                        group: 'load',\n                    },\n                },\n            },\n\n            // don't include in object\n            '^type$': false,\n            '^files$': false,\n        };\n\n        // add additional option translators\n        applyFilters('SET_ATTRIBUTE_TO_OPTION_MAP', attributeMapping);\n\n        // create final options object by setting options object and then overriding options supplied on element\n        var mergedOptions = Object.assign({}, options);\n\n        var attributeOptions = getAttributesAsObject(\n            element.nodeName === 'FIELDSET' ? element.querySelector('input[type=file]') : element,\n            attributeMapping\n        );\n\n        // merge with options object\n        Object.keys(attributeOptions).forEach(function(key) {\n            if (isObject(attributeOptions[key])) {\n                if (!isObject(mergedOptions[key])) {\n                    mergedOptions[key] = {};\n                }\n                Object.assign(mergedOptions[key], attributeOptions[key]);\n            } else {\n                mergedOptions[key] = attributeOptions[key];\n            }\n        });\n\n        // if parent is a fieldset, get files from parent by selecting all input fields that are not file upload fields\n        // these will then be automatically set to the initial files\n        mergedOptions.files = (options.files || []).concat(\n            Array.from(element.querySelectorAll('input:not([type=file])')).map(function(input) {\n                return {\n                    source: input.value,\n                    options: {\n                        type: input.dataset.type,\n                    },\n                };\n            })\n        );\n\n        // build plugin\n        var app = createAppObject(mergedOptions);\n\n        // add already selected files\n        if (element.files) {\n            Array.from(element.files).forEach(function(file) {\n                app.addFile(file);\n            });\n        }\n\n        // replace the target element\n        app.replaceElement(element);\n\n        // expose\n        return app;\n    };\n\n    // if an element is passed, we create the instance at that element, if not, we just create an up object\n    var createApp$1 = function createApp() {\n        return isNode(arguments.length <= 0 ? undefined : arguments[0])\n            ? createAppAtElement.apply(void 0, arguments)\n            : createAppObject.apply(void 0, arguments);\n    };\n\n    var PRIVATE_METHODS = ['fire', '_read', '_write'];\n\n    var createAppAPI = function createAppAPI(app) {\n        var api = {};\n\n        copyObjectPropertiesToObject(app, api, PRIVATE_METHODS);\n\n        return api;\n    };\n\n    /**\n     * Replaces placeholders in given string with replacements\n     * @param string - \"Foo {bar}\"\"\n     * @param replacements - { \"bar\": 10 }\n     */\n    var replaceInString = function replaceInString(string, replacements) {\n        return string.replace(/(?:{([a-zA-Z]+)})/g, function(match, group) {\n            return replacements[group];\n        });\n    };\n\n    var createWorker = function createWorker(fn) {\n        var workerBlob = new Blob(['(', fn.toString(), ')()'], {\n            type: 'application/javascript',\n        });\n\n        var workerURL = URL.createObjectURL(workerBlob);\n        var worker = new Worker(workerURL);\n\n        return {\n            transfer: function transfer(message, cb) {},\n            post: function post(message, cb, transferList) {\n                var id = getUniqueId();\n\n                worker.onmessage = function(e) {\n                    if (e.data.id === id) {\n                        cb(e.data.message);\n                    }\n                };\n\n                worker.postMessage(\n                    {\n                        id: id,\n                        message: message,\n                    },\n\n                    transferList\n                );\n            },\n            terminate: function terminate() {\n                worker.terminate();\n                URL.revokeObjectURL(workerURL);\n            },\n        };\n    };\n\n    var loadImage = function loadImage(url) {\n        return new Promise(function(resolve, reject) {\n            var img = new Image();\n            img.onload = function() {\n                resolve(img);\n            };\n            img.onerror = function(e) {\n                reject(e);\n            };\n            img.src = url;\n        });\n    };\n\n    var renameFile = function renameFile(file, name) {\n        var renamedFile = file.slice(0, file.size, file.type);\n        renamedFile.lastModifiedDate = file.lastModifiedDate;\n        renamedFile.name = name;\n        return renamedFile;\n    };\n\n    var copyFile = function copyFile(file) {\n        return renameFile(file, file.name);\n    };\n\n    // already registered plugins (can't register twice)\n    var registeredPlugins = [];\n\n    // pass utils to plugin\n    var createAppPlugin = function createAppPlugin(plugin) {\n        // already registered\n        if (registeredPlugins.includes(plugin)) {\n            return;\n        }\n\n        // remember this plugin\n        registeredPlugins.push(plugin);\n\n        // setup!\n        var pluginOutline = plugin({\n            addFilter: addFilter,\n            utils: {\n                Type: Type,\n                forin: forin,\n                isString: isString,\n                isFile: isFile,\n                toNaturalFileSize: toNaturalFileSize,\n                replaceInString: replaceInString,\n                getExtensionFromFilename: getExtensionFromFilename,\n                getFilenameWithoutExtension: getFilenameWithoutExtension,\n                guesstimateMimeType: guesstimateMimeType,\n                getFileFromBlob: getFileFromBlob,\n                getFilenameFromURL: getFilenameFromURL,\n                createRoute: createRoute,\n                createWorker: createWorker,\n                createView: createView,\n                createItemAPI: createItemAPI,\n                loadImage: loadImage,\n                copyFile: copyFile,\n                renameFile: renameFile,\n                createBlob: createBlob,\n                applyFilterChain: applyFilterChain,\n                text: text,\n                getNumericAspectRatioFromString: getNumericAspectRatioFromString,\n            },\n\n            views: {\n                fileActionButton: fileActionButton,\n            },\n        });\n\n        // add plugin options to default options\n        extendDefaultOptions(pluginOutline.options);\n    };\n\n    // feature detection used by supported() method\n    var isOperaMini = function isOperaMini() {\n        return Object.prototype.toString.call(window.operamini) === '[object OperaMini]';\n    };\n    var hasPromises = function hasPromises() {\n        return 'Promise' in window;\n    };\n    var hasBlobSlice = function hasBlobSlice() {\n        return 'slice' in Blob.prototype;\n    };\n    var hasCreateObjectURL = function hasCreateObjectURL() {\n        return 'URL' in window && 'createObjectURL' in window.URL;\n    };\n    var hasVisibility = function hasVisibility() {\n        return 'visibilityState' in document;\n    };\n    var hasTiming = function hasTiming() {\n        return 'performance' in window;\n    }; // iOS 8.x\n    var hasCSSSupports = function hasCSSSupports() {\n        return 'supports' in (window.CSS || {});\n    }; // use to detect Safari 9+\n    var isIE11 = function isIE11() {\n        return /MSIE|Trident/.test(window.navigator.userAgent);\n    };\n\n    var supported = (function() {\n        // Runs immediately and then remembers result for subsequent calls\n        var isSupported =\n            // Has to be a browser\n            isBrowser() &&\n            // Can't run on Opera Mini due to lack of everything\n            !isOperaMini() &&\n            // Require these APIs to feature detect a modern browser\n            hasVisibility() &&\n            hasPromises() &&\n            hasBlobSlice() &&\n            hasCreateObjectURL() &&\n            hasTiming() &&\n            // doesn't need CSSSupports but is a good way to detect Safari 9+ (we do want to support IE11 though)\n            (hasCSSSupports() || isIE11());\n\n        return function() {\n            return isSupported;\n        };\n    })();\n\n    /**\n     * Plugin internal state (over all instances)\n     */\n    var state = {\n        // active app instances, used to redraw the apps and to find the later\n        apps: [],\n    };\n\n    // plugin name\n    var name = 'filepond';\n\n    /**\n     * Public Plugin methods\n     */\n    var fn = function fn() {};\n    exports.Status = {};\n    exports.FileStatus = {};\n    exports.FileOrigin = {};\n    exports.OptionTypes = {};\n    exports.create = fn;\n    exports.destroy = fn;\n    exports.parse = fn;\n    exports.find = fn;\n    exports.registerPlugin = fn;\n    exports.getOptions = fn;\n    exports.setOptions = fn;\n\n    // if not supported, no API\n    if (supported()) {\n        // start painter and fire load event\n        createPainter(\n            function() {\n                state.apps.forEach(function(app) {\n                    return app._read();\n                });\n            },\n            function(ts) {\n                state.apps.forEach(function(app) {\n                    return app._write(ts);\n                });\n            }\n        );\n\n        // fire loaded event so we know when FilePond is available\n        var dispatch = function dispatch() {\n            // let others know we have area ready\n            document.dispatchEvent(\n                new CustomEvent('FilePond:loaded', {\n                    detail: {\n                        supported: supported,\n                        create: exports.create,\n                        destroy: exports.destroy,\n                        parse: exports.parse,\n                        find: exports.find,\n                        registerPlugin: exports.registerPlugin,\n                        setOptions: exports.setOptions,\n                    },\n                })\n            );\n\n            // clean up event\n            document.removeEventListener('DOMContentLoaded', dispatch);\n        };\n\n        if (document.readyState !== 'loading') {\n            // move to back of execution queue, FilePond should have been exported by then\n            setTimeout(function() {\n                return dispatch();\n            }, 0);\n        } else {\n            document.addEventListener('DOMContentLoaded', dispatch);\n        }\n\n        // updates the OptionTypes object based on the current options\n        var updateOptionTypes = function updateOptionTypes() {\n            return forin(getOptions(), function(key, value) {\n                exports.OptionTypes[key] = value[1];\n            });\n        };\n\n        exports.Status = Object.assign({}, Status);\n        exports.FileOrigin = Object.assign({}, FileOrigin);\n        exports.FileStatus = Object.assign({}, ItemStatus);\n\n        exports.OptionTypes = {};\n        updateOptionTypes();\n\n        // create method, creates apps and adds them to the app array\n        exports.create = function create() {\n            var app = createApp$1.apply(void 0, arguments);\n            app.on('destroy', exports.destroy);\n            state.apps.push(app);\n            return createAppAPI(app);\n        };\n\n        // destroys apps and removes them from the app array\n        exports.destroy = function destroy(hook) {\n            // returns true if the app was destroyed successfully\n            var indexToRemove = state.apps.findIndex(function(app) {\n                return app.isAttachedTo(hook);\n            });\n            if (indexToRemove >= 0) {\n                // remove from apps\n                var app = state.apps.splice(indexToRemove, 1)[0];\n\n                // restore original dom element\n                app.restoreElement();\n\n                return true;\n            }\n\n            return false;\n        };\n\n        // parses the given context for plugins (does not include the context element itself)\n        exports.parse = function parse(context) {\n            // get all possible hooks\n            var matchedHooks = Array.from(context.querySelectorAll('.' + name));\n\n            // filter out already active hooks\n            var newHooks = matchedHooks.filter(function(newHook) {\n                return !state.apps.find(function(app) {\n                    return app.isAttachedTo(newHook);\n                });\n            });\n\n            // create new instance for each hook\n            return newHooks.map(function(hook) {\n                return exports.create(hook);\n            });\n        };\n\n        // returns an app based on the given element hook\n        exports.find = function find(hook) {\n            var app = state.apps.find(function(app) {\n                return app.isAttachedTo(hook);\n            });\n            if (!app) {\n                return null;\n            }\n            return createAppAPI(app);\n        };\n\n        // adds a plugin extension\n        exports.registerPlugin = function registerPlugin() {\n            for (\n                var _len = arguments.length, plugins = new Array(_len), _key = 0;\n                _key < _len;\n                _key++\n            ) {\n                plugins[_key] = arguments[_key];\n            }\n\n            // register plugins\n            plugins.forEach(createAppPlugin);\n\n            // update OptionTypes, each plugin might have extended the default options\n            updateOptionTypes();\n        };\n\n        exports.getOptions = function getOptions$1() {\n            var opts = {};\n            forin(getOptions(), function(key, value) {\n                opts[key] = value[0];\n            });\n            return opts;\n        };\n\n        exports.setOptions = function setOptions$1(opts) {\n            if (isObject(opts)) {\n                // update existing plugins\n                state.apps.forEach(function(app) {\n                    app.setOptions(opts);\n                });\n\n                // override defaults\n                setOptions(opts);\n            }\n\n            // return new options\n            return exports.getOptions();\n        };\n    }\n\n    exports.supported = supported;\n\n    Object.defineProperty(exports, '__esModule', { value: true });\n});\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <title>FilePond Demo</title>\n        <link href=\"./dist/filepond.css\" rel=\"stylesheet\" />\n    </head>\n    <body>\n        <input type=\"file\" />\n\n        <script>\n            // prettier-ignore\n            [\n        {supported: 'Symbol' in window, fill: 'https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser-polyfill.min.js'},\n        {supported: 'Promise' in window, fill: 'https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js'},\n        {supported: 'fetch' in window, fill: 'https://cdn.jsdelivr.net/npm/fetch-polyfill@0.8.2/fetch.min.js'},\n        {supported: 'CustomEvent' in window && 'log10' in Math && 'sign' in Math &&  'assign' in Object &&  'from' in Array &&\n                    ['find', 'findIndex', 'some', 'includes'].reduce(function(previous, prop) { return (prop in Array.prototype) ? previous : false; }, true), fill: 'https://unpkg.com/filepond-polyfill/dist/filepond-polyfill.js'}\n    ].forEach(function(p) {\n        if (p.supported) return;\n        document.write('<script src=\"' + p.fill + '\"><\\/script>');\n    });\n        </script>\n\n        <script src=\"./dist/filepond.js\"></script>\n\n        <script>\n            // Get a reference to the file input element\n            const inputElement = document.querySelector('input[type=\"file\"]');\n\n            // Create the FilePond instance\n            const pond = FilePond.create(inputElement, {\n                allowMultiple: true,\n                storeAsFile: true,\n            });\n\n            // Easy console access for testing purposes\n            window.pond = pond;\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n    bail: true,\n    verbose: true,\n    setupFiles: ['<rootDir>/jest.stubs.js'],\n    roots: ['<rootDir>/src/js']\n};"
  },
  {
    "path": "jest.stubs.js",
    "content": "const uuid = require('uuid/v4');\n\n// needed because jest doesn't have CSS on window\nif (!window.CSS) window.CSS = {};\nwindow.CSS.supports = () => true;\n\nwindow.URL.createObjectURL = blob => {\n    return `blob:${serializeURL(location.origin)}/${uuid()}`;\n};\n\nwindow.URL.revokeObjectURL = url => {};\n"
  },
  {
    "path": "locale/am-et.js",
    "content": "export default {\n    labelIdle: 'ፋይሎች ስበው እዚህ ጋር ይልቀቁት ወይም ፋይሉን <span class=\"filepond--label-action\"> ይምረጡ </span>',\n    labelInvalidField: 'መስኩ ልክ ያልሆኑ ፋይሎችን ይዟል',\n    labelFileWaitingForSize: 'የፋይሉን መጠን በመጠባበቅ ላይ',\n    labelFileSizeNotAvailable: 'የፋይሉን መጠን ሊገኝ አልቻለም',\n    labelFileLoading: 'በማንበብ ላይ',\n    labelFileLoadError: 'በማንበብ ላይ ችግር ተፈጥሯል',\n    labelFileProcessing: 'ፋይሉን በመጫን ላይ',\n    labelFileProcessingComplete: 'ፋይሉን መጫን ተጠናቅቋል',\n    labelFileProcessingAborted: 'ፋይሉን መጫን ተቋርጧል',\n    labelFileProcessingError: 'ፋይሉን በመጫን ላይ ችግር ተፈጥሯል',\n    labelFileProcessingRevertError: 'ፈይሉን በመቀልበስ ላይ ችግር ተፈጥሯል',\n    labelFileRemoveError: 'በማጥፋት ላይ ችግር ተፈጥሯል',\n    labelTapToCancel: 'ለማቋረጥ ነካ ያድርጉ',\n    labelTapToRetry: 'ደግሞ ለመሞከር ነካ ያድርጉ',\n    labelTapToUndo: 'ወደነበረበት ለመመለስ ነካ ያድርጉ',\n    labelButtonRemoveItem: 'ላጥፋ',\n    labelButtonAbortItemLoad: 'ላቋርጥ',\n    labelButtonRetryItemLoad: 'ደግሜ ልሞክር',\n    labelButtonAbortItemProcessing: 'ይቅር',\n    labelButtonUndoItemProcessing: 'ወደነበረበት ልመልስ',\n    labelButtonRetryItemProcessing: 'ደግሜ ልሞክር',\n    labelButtonProcessItem: 'ልጫን',\n    labelMaxFileSizeExceeded: 'ፋይሉ ተልቋል',\n    labelMaxFileSize: 'የፋይል መጠን ከ {filesize} መብለጥ አይፈቀድም',\n    labelMaxTotalFileSizeExceeded: 'የሚፈቀደውን ጠቅላላ የፋይል መጠን አልፈዋል',\n    labelMaxTotalFileSize: 'ጠቅላላ የፋይል መጠን ከ {filesize} መብለጥ አይፈቀድም',\n    labelFileTypeNotAllowed: 'የተሳሳተ የፋይል አይነት ነው',\n    fileValidateTypeLabelExpectedTypes: 'የፋይል አይነቱ መሆን የሚገባው {allButLastType} እና {lastType} ነው',\n    imageValidateSizeLabelFormatError: 'የምስል አይነቱ ለመጫን አይሆንም',\n    imageValidateSizeLabelImageSizeTooSmall: 'ምስሉ በጣም አንሷል',\n    imageValidateSizeLabelImageSizeTooBig: 'ምስሉ በጣም ተልቋል',\n    imageValidateSizeLabelExpectedMinSize: 'ዝቅተኛው የምስል ልኬት {minWidth} × {minHeight} ነው',\n    imageValidateSizeLabelExpectedMaxSize: 'ከፍተኛው የምስል ልኬት {maxWidth} × {maxHeight} ነው',\n    imageValidateSizeLabelImageResolutionTooLow: 'የምስሉ ጥራት በጣም ዝቅተኛ ነው',\n    imageValidateSizeLabelImageResolutionTooHigh: 'የምስሉ ጥራት በጣም ከፍተኛ ነው',\n    imageValidateSizeLabelExpectedMinResolution: 'ዝቅተኛው የምስል ጥራት {minResolution} ነው',\n    imageValidateSizeLabelExpectedMaxResolution: 'ከፍተኛው የምስል ጥራት {maxResolution} ነው'\n};\n"
  },
  {
    "path": "locale/ar-ar.js",
    "content": "export default {\n    labelIdle: 'اسحب و ادرج ملفاتك أو <span class=\"filepond--label-action\"> تصفح </span>',\n    labelInvalidField: 'الحقل يحتوي على ملفات غير صالحة',\n    labelFileWaitingForSize: 'بانتظار الحجم',\n    labelFileSizeNotAvailable: 'الحجم غير متاح',\n    labelFileLoading: 'بالإنتظار',\n    labelFileLoadError: 'حدث خطأ أثناء التحميل',\n    labelFileProcessing: 'يتم الرفع',\n    labelFileProcessingComplete: 'تم الرفع',\n    labelFileProcessingAborted: 'تم إلغاء الرفع',\n    labelFileProcessingError: 'حدث خطأ أثناء الرفع',\n    labelFileProcessingRevertError: 'حدث خطأ أثناء التراجع',\n    labelFileRemoveError: 'حدث خطأ أثناء الحذف',\n    labelTapToCancel: 'انقر للإلغاء',\n    labelTapToRetry: 'انقر لإعادة المحاولة',\n    labelTapToUndo: 'انقر للتراجع',\n    labelButtonRemoveItem: 'مسح',\n    labelButtonAbortItemLoad: 'إلغاء',\n    labelButtonRetryItemLoad: 'إعادة',\n    labelButtonAbortItemProcessing: 'إلغاء',\n    labelButtonUndoItemProcessing: 'تراجع',\n    labelButtonRetryItemProcessing: 'إعادة',\n    labelButtonProcessItem: 'رفع',\n    labelMaxFileSizeExceeded: 'الملف كبير جدا',\n    labelMaxFileSize: 'حجم الملف الأقصى: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'تم تجاوز الحد الأقصى للحجم الإجمالي',\n    labelMaxTotalFileSize: 'الحد الأقصى لحجم الملف: {filesize}',\n    labelFileTypeNotAllowed: 'ملف من نوع غير صالح',\n    fileValidateTypeLabelExpectedTypes: 'تتوقع {allButLastType} من {lastType}',\n    imageValidateSizeLabelFormatError: 'نوع الصورة غير مدعوم',\n    imageValidateSizeLabelImageSizeTooSmall: 'الصورة صغير جدا',\n    imageValidateSizeLabelImageSizeTooBig: 'الصورة كبيرة جدا',\n    imageValidateSizeLabelExpectedMinSize: 'الحد الأدنى للأبعاد هو: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'الحد الأقصى للأبعاد هو: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'الدقة ضعيفة جدا',\n    imageValidateSizeLabelImageResolutionTooHigh: 'الدقة مرتفعة جدا',\n    imageValidateSizeLabelExpectedMinResolution: 'أقل دقة: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'أقصى دقة: {maxResolution}'\n};\n"
  },
  {
    "path": "locale/az-az.js",
    "content": "export default {\n    labelIdle: 'Faylınızı Sürüşdürün & Buraxın ya da <span class=\"filepond--label-action\"> Seçin </span>',\n    labelInvalidField: 'Sahədə etibarsız fayllar var',\n    labelFileWaitingForSize: 'Ölçü hesablanır',\n    labelFileSizeNotAvailable: 'Ölçü mövcud deyil',\n    labelFileLoading: 'Yüklənir',\n    labelFileLoadError: 'Yükləmə əsnasında xəta baş verdi',\n    labelFileProcessing: 'Yüklənir',\n    labelFileProcessingComplete: 'Yükləmə tamamlandı',\n    labelFileProcessingAborted: 'Yükləmə ləğv edildi',\n    labelFileProcessingError: 'Yükəyərkən xəta baş verdi',\n    labelFileProcessingRevertError: 'Geri çəkərkən xəta baş verdi',\n    labelFileRemoveError: 'Çıxararkən xəta baş verdi',\n    labelTapToCancel: 'İmtina etmək üçün klikləyin',\n    labelTapToRetry: 'Təkrar yoxlamaq üçün klikləyin',\n    labelTapToUndo: 'Geri almaq üçün klikləyin',\n    labelButtonRemoveItem: 'Çıxar',\n    labelButtonAbortItemLoad: 'İmtina Et',\n    labelButtonRetryItemLoad: 'Təkrar yoxla',\n    labelButtonAbortItemProcessing: 'İmtina et',\n    labelButtonUndoItemProcessing: 'Geri Al',\n    labelButtonRetryItemProcessing: 'Təkrar yoxla',\n    labelButtonProcessItem: 'Yüklə',\n    labelMaxFileSizeExceeded: 'Fayl çox böyükdür',\n    labelMaxFileSize: 'Ən böyük fayl ölçüsü: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maksimum ölçü keçildi',\n    labelMaxTotalFileSize: 'Maksimum fayl ölçüsü :{filesize}',\n    labelFileTypeNotAllowed: 'Etibarsız fayl tipi',\n    fileValidateTypeLabelExpectedTypes: 'Bu {allButLastType} ya da bu fayl olması lazımdır: {lastType}',\n    imageValidateSizeLabelFormatError: 'Şəkil tipi dəstəklənmir',\n    imageValidateSizeLabelImageSizeTooSmall: 'Şəkil çox kiçik',\n    imageValidateSizeLabelImageSizeTooBig: 'Şəkil çox böyük',\n    imageValidateSizeLabelExpectedMinSize: 'Minimum ölçü {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimum ölçü {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Görüntü imkanı çox aşağı',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Görüntü imkanı çox yüksək',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimum görüntü imkanı {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximum görüntü imkanı {maxResolution}'\n};\n"
  },
  {
    "path": "locale/ca-ca.js",
    "content": "export default {\n    labelIdle: `Arrossega i deixa anar els teus fitxers o <span class=\"filepond--label-action\"> Navega </span>`,\n    labelInvalidField: `El camp conté fitxers invàlids`,\n    labelFileWaitingForSize: `Esperant mida`,\n    labelFileSizeNotAvailable: `Mida no disponible`,\n    labelFileLoading: `Carregant`,\n    labelFileLoadError: `Error durant la càrrega`,\n    labelFileProcessing: `Pujant`,\n    labelFileProcessingComplete: `Pujada completada`,\n    labelFileProcessingAborted: `Pujada cancel·lada`,\n    labelFileProcessingError: `Error durant la pujada`,\n    labelFileProcessingRevertError: `Error durant la reversió`,\n    labelFileRemoveError: `Error durant l'eliminació`,\n    labelTapToCancel: `toca per cancel·lar`,\n    labelTapToRetry: `toca per reintentar`,\n    labelTapToUndo: `toca per desfer`,\n    labelButtonRemoveItem: `Eliminar`,\n    labelButtonAbortItemLoad: `Cancel·lar`,\n    labelButtonRetryItemLoad: `Reintentar`,\n    labelButtonAbortItemProcessing: `Cancel·lar`,\n    labelButtonUndoItemProcessing: `Desfer`,\n    labelButtonRetryItemProcessing: `Reintentar`,\n    labelButtonProcessItem: `Pujar`,\n    labelMaxFileSizeExceeded: `El fitxer és massa gran`,\n    labelMaxFileSize: `La mida màxima del fitxer és {filesize}`,\n    labelMaxTotalFileSizeExceeded: `Mida màxima total excedida`,\n    labelMaxTotalFileSize: `La mida màxima total del fitxer és {filesize}`,\n    labelFileTypeNotAllowed: `Fitxer de tipus invàlid`,\n    fileValidateTypeLabelExpectedTypes: `Espera {allButLastType} o {lastType}`,\n    imageValidateSizeLabelFormatError: `Tipus d'imatge no suportada`,\n    imageValidateSizeLabelImageSizeTooSmall: `La imatge és massa petita`,\n    imageValidateSizeLabelImageSizeTooBig: `La imatge és massa gran`,\n    imageValidateSizeLabelExpectedMinSize: `La mida mínima és {minWidth} x {minHeight}`,\n    imageValidateSizeLabelExpectedMaxSize: `La mida màxima és {maxWidth} x {maxHeight}`,\n    imageValidateSizeLabelImageResolutionTooLow: `La resolució és massa baixa`,\n    imageValidateSizeLabelImageResolutionTooHigh: `La resolució és massa alta`,\n    imageValidateSizeLabelExpectedMinResolution: `La resolució mínima és {minResolution}`,\n    imageValidateSizeLabelExpectedMaxResolution: `La resolució màxima és {maxResolution}`,\n}\n"
  },
  {
    "path": "locale/cs-cz.js",
    "content": "export default {\n    labelIdle: 'Přetáhněte soubor sem (drag&drop) nebo <span class=\"filepond--label-action\"> Vyhledat </span>',\n    labelInvalidField: 'Pole obsahuje chybné soubory',\n    labelFileWaitingForSize: 'Zjišťuje se velikost',\n    labelFileSizeNotAvailable: 'Velikost není známá',\n    labelFileLoading: 'Přenáší se',\n    labelFileLoadError: 'Chyba při přenosu',\n    labelFileProcessing: 'Probíhá upload',\n    labelFileProcessingComplete: 'Upload dokončen',\n    labelFileProcessingAborted: 'Upload stornován',\n    labelFileProcessingError: 'Chyba při uploadu',\n    labelFileProcessingRevertError: 'Chyba při obnově',\n    labelFileRemoveError: 'Chyba při odstranění',\n    labelTapToCancel: 'klepněte pro storno',\n    labelTapToRetry: 'klepněte pro opakování',\n    labelTapToUndo: 'klepněte pro vrácení',\n    labelButtonRemoveItem: 'Odstranit',\n    labelButtonAbortItemLoad: 'Storno',\n    labelButtonRetryItemLoad: 'Opakovat',\n    labelButtonAbortItemProcessing: 'Zpět',\n    labelButtonUndoItemProcessing: 'Vrátit',\n    labelButtonRetryItemProcessing: 'Opakovat',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'Soubor je příliš velký',\n    labelMaxFileSize: 'Největší velikost souboru je {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Překročena maximální celková velikost souboru',\n    labelMaxTotalFileSize: 'Maximální celková velikost souboru je {filesize}',\n    labelFileTypeNotAllowed: 'Soubor je nesprávného typu',\n    fileValidateTypeLabelExpectedTypes: 'Očekává se {allButLastType} nebo {lastType}',\n    imageValidateSizeLabelFormatError: 'Obrázek tohoto typu není podporován',\n    imageValidateSizeLabelImageSizeTooSmall: 'Obrázek je příliš malý',\n    imageValidateSizeLabelImageSizeTooBig: 'Obrázek je příliš velký',\n    imageValidateSizeLabelExpectedMinSize: 'Minimální rozměr je {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximální rozměr je {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rozlišení je příliš malé',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rozlišení je příliš velké',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimální rozlišení je {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximální rozlišení je {maxResolution}'\n};\n"
  },
  {
    "path": "locale/cy-cy.js",
    "content": "export default {\n    labelIdle: 'Llusgwch a Gollyngwch eich ffeiliau neu ddefnyddiwch y  <span class=\"filepond--label-action\"> Porwr </span>',\n    labelInvalidField: 'Mae’r maes yn cynnwys ffeiliau annilys',\n    labelFileWaitingForSize: 'Disgwyl am y maint',\n    labelFileSizeNotAvailable: 'Dim maint ar gael',\n    labelFileLoading: 'Llwytho',\n    labelFileLoadError: 'Camgymeriad wrth lwytho',\n    labelFileProcessing: 'Lanlwytho',\n    labelFileProcessingComplete: 'Lanlwythiad yn gyflawn',\n    labelFileProcessingAborted: 'Lanlwythiad wedi ei ganslo',\n    labelFileProcessingError: 'Camgymeriad wrth lanlwytho',\n    labelFileProcessingRevertError: 'Camgymeriad wrth ddychwelyd',\n    labelFileRemoveError: 'Camgymeriad wrth ddileu',\n    labelTapToCancel: 'tapiwch i ganslo',\n    labelTapToRetry: 'tapiwch i roi cynnig arall arni',\n    labelTapToUndo: 'tapiwch i ddadwneud',\n    labelButtonRemoveItem: 'Dileu',\n    labelButtonAbortItemLoad: 'Atal',\n    labelButtonRetryItemLoad: 'Ceisio eto',\n    labelButtonAbortItemProcessing: 'Canslo',\n    labelButtonUndoItemProcessing: 'Dadwneud',\n    labelButtonRetryItemProcessing: 'Ceisio eto',\n    labelButtonProcessItem: 'Lanlwytho',\n    labelMaxFileSizeExceeded: 'Mae\\'r ffeil yn rhy fawr',\n    labelMaxFileSize: 'Uchafswm maint y ffeil yw {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Mwy na’r cyfanswm uchaf o ran maint',\n    labelMaxTotalFileSize: 'Uchafswm maint y ffeil yw {filesize}',\n    labelFileTypeNotAllowed: 'Math o ffeil annilys',\n    fileValidateTypeLabelExpectedTypes: 'Yn disgwyl {allButLastType} neu {lastType}',\n    imageValidateSizeLabelFormatError: 'Ni chefnogir y math o ddelwedd',\n    imageValidateSizeLabelImageSizeTooSmall: 'Mae\\'r ddelwedd yn rhy fach',\n    imageValidateSizeLabelImageSizeTooBig: 'Mae\\'r ddelwedd yn rhy fawr',\n    imageValidateSizeLabelExpectedMinSize: 'Y maint lleiaf yw {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Y maint mwyaf yw {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Mae\\'r cydraniad yn rhy isel',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Mae\\'r cydraniad yn rhy uchel',\n    imageValidateSizeLabelExpectedMinResolution: 'Y cydraniad lleiaf yw {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Y cydraniad uchaf yw {maxResolution}'\n};\n"
  },
  {
    "path": "locale/da-dk.js",
    "content": "export default {\n    labelIdle:\n        'Træk & slip filer eller <span class = \"filepond - label-action\"> Gennemse </span>',\n    labelInvalidField: 'Felt indeholder ugyldige filer',\n    labelFileWaitingForSize: 'Venter på størrelse',\n    labelFileSizeNotAvailable: 'Størrelse ikke tilgængelig',\n    labelFileLoading: 'Loader',\n    labelFileLoadError: 'Load fejlede',\n    labelFileProcessing: 'Uploader',\n    labelFileProcessingComplete: 'Upload færdig',\n    labelFileProcessingAborted: 'Upload annulleret',\n    labelFileProcessingError: 'Upload fejlede',\n    labelFileProcessingRevertError: 'Fortryd fejlede',\n    labelFileRemoveError: 'Fjern fejlede',\n    labelTapToCancel: 'tryk for at annullere',\n    labelTapToRetry: 'tryk for at prøve igen',\n    labelTapToUndo: 'tryk for at fortryde',\n    labelButtonRemoveItem: 'Fjern',\n    labelButtonAbortItemLoad: 'Annuller',\n    labelButtonRetryItemLoad: 'Forsøg igen',\n    labelButtonAbortItemProcessing: 'Annuller',\n    labelButtonUndoItemProcessing: 'Fortryd',\n    labelButtonRetryItemProcessing: 'Prøv igen',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'Filen er for stor',\n    labelMaxFileSize: 'Maksimal filstørrelse er {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maksimal totalstørrelse overskredet',\n    labelMaxTotalFileSize: 'Maksimal total filstørrelse er {filesize}',\n    labelFileTypeNotAllowed: 'Ugyldig filtype',\n    fileValidateTypeLabelExpectedTypes: 'Forventer {allButLastType} eller {lastType}',\n    imageValidateSizeLabelFormatError: 'Ugyldigt format',\n    imageValidateSizeLabelImageSizeTooSmall: 'Billedet er for lille',\n    imageValidateSizeLabelImageSizeTooBig: 'Billedet er for stort',\n    imageValidateSizeLabelExpectedMinSize: 'Minimum størrelse er {minBredde} × {minHøjde}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimal størrelse er {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'For lav opløsning',\n    imageValidateSizeLabelImageResolutionTooHigh: 'For høj opløsning',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimum opløsning er {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimal opløsning er {maxResolution}',\n};\n"
  },
  {
    "path": "locale/de-de.js",
    "content": "export default {\n    labelIdle: 'Dateien ablegen oder <span class=\"filepond--label-action\"> auswählen </span>',\n    labelInvalidField: 'Feld beinhaltet ungültige Dateien',\n    labelFileWaitingForSize: 'Dateigröße berechnen',\n    labelFileSizeNotAvailable: 'Dateigröße nicht verfügbar',\n    labelFileLoading: 'Laden',\n    labelFileLoadError: 'Fehler beim Laden',\n    labelFileProcessing: 'Upload läuft',\n    labelFileProcessingComplete: 'Upload abgeschlossen',\n    labelFileProcessingAborted: 'Upload abgebrochen',\n    labelFileProcessingError: 'Fehler beim Upload',\n    labelFileProcessingRevertError: 'Fehler beim Wiederherstellen',\n    labelFileRemoveError: 'Fehler beim Löschen',\n    labelTapToCancel: 'abbrechen',\n    labelTapToRetry: 'erneut versuchen',\n    labelTapToUndo: 'rückgängig',\n    labelButtonRemoveItem: 'Entfernen',\n    labelButtonAbortItemLoad: 'Verwerfen',\n    labelButtonRetryItemLoad: 'Erneut versuchen',\n    labelButtonAbortItemProcessing: 'Abbrechen',\n    labelButtonUndoItemProcessing: 'Rückgängig',\n    labelButtonRetryItemProcessing: 'Erneut versuchen',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'Datei ist zu groß',\n    labelMaxFileSize: 'Maximale Dateigröße: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maximale gesamte Dateigröße überschritten',\n    labelMaxTotalFileSize: 'Maximale gesamte Dateigröße: {filesize}',\n    labelFileTypeNotAllowed: 'Dateityp ungültig',\n    fileValidateTypeLabelExpectedTypes: 'Erwartet {allButLastType} oder {lastType}',\n    imageValidateSizeLabelFormatError: 'Bildtyp nicht unterstützt',\n    imageValidateSizeLabelImageSizeTooSmall: 'Bild ist zu klein',\n    imageValidateSizeLabelImageSizeTooBig: 'Bild ist zu groß',\n    imageValidateSizeLabelExpectedMinSize: 'Mindestgröße: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximale Größe: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Auflösung ist zu niedrig',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Auflösung ist zu hoch',\n    imageValidateSizeLabelExpectedMinResolution: 'Mindestauflösung: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximale Auflösung: {maxResolution}'\n  };"
  },
  {
    "path": "locale/el-el.js",
    "content": "export default {\n    labelIdle: 'Σύρετε τα αρχεία σας στο πλαίσιο ή <span class=\"filepond--label-action\"> Επιλέξτε </span>',\n    labelInvalidField: 'Το πεδίο περιέχει μη έγκυρα αρχεία',\n    labelFileWaitingForSize: 'Σε αναμονή για το μέγεθος',\n    labelFileSizeNotAvailable: 'Μέγεθος μη διαθέσιμο',\n    labelFileLoading: 'Φόρτωση σε εξέλιξη',\n    labelFileLoadError: 'Σφάλμα κατά τη φόρτωση',\n    labelFileProcessing: 'Επεξεργασία',\n    labelFileProcessingComplete: 'Η επεξεργασία ολοκληρώθηκε',\n    labelFileProcessingAborted: 'Η επεξεργασία ακυρώθηκε',\n    labelFileProcessingError: 'Σφάλμα κατά την επεξεργασία',\n    labelFileProcessingRevertError: 'Σφάλμα κατά την επαναφορά',\n    labelFileRemoveError: 'Σφάλμα κατά την διαγραφή',\n    labelTapToCancel: 'πατήστε για ακύρωση',\n    labelTapToRetry: 'πατήστε για επανάληψη',\n    labelTapToUndo: 'πατήστε για αναίρεση',\n    labelButtonRemoveItem: 'Αφαίρεση',\n    labelButtonAbortItemLoad: 'Ακύρωση',\n    labelButtonRetryItemLoad: 'Επανάληψη',\n    labelButtonAbortItemProcessing: 'Ακύρωση',\n    labelButtonUndoItemProcessing: 'Αναίρεση',\n    labelButtonRetryItemProcessing: 'Επανάληψη',\n    labelButtonProcessItem: 'Μεταφόρτωση',\n    labelMaxFileSizeExceeded: 'Το αρχείο είναι πολύ μεγάλο',\n    labelMaxFileSize: 'Το μέγιστο μέγεθος αρχείου είναι {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Υπέρβαση του μέγιστου συνολικού μεγέθους',\n    labelMaxTotalFileSize: 'Το μέγιστο συνολικό μέγεθος αρχείων είναι {filesize}',\n    labelFileTypeNotAllowed: 'Μη έγκυρος τύπος αρχείου',\n    fileValidateTypeLabelExpectedTypes: 'Τα αποδεκτά αρχεία είναι {allButLastType} ή {lastType}',\n    imageValidateSizeLabelFormatError: 'Ο τύπος της εικόνας δεν υποστηρίζεται',\n    imageValidateSizeLabelImageSizeTooSmall: 'Η εικόνα είναι πολύ μικρή',\n    imageValidateSizeLabelImageSizeTooBig: 'Η εικόνα είναι πολύ μεγάλη',\n    imageValidateSizeLabelExpectedMinSize: 'Το ελάχιστο αποδεκτό μέγεθος είναι {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Το μέγιστο αποδεκτό μέγεθος είναι {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Η ανάλυση της εικόνας είναι πολύ χαμηλή',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Η ανάλυση της εικόνας είναι πολύ υψηλή',\n    imageValidateSizeLabelExpectedMinResolution: 'Η ελάχιστη αποδεκτή ανάλυση είναι {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Η μέγιστη αποδεκτή ανάλυση είναι {maxResolution}'\n};\n"
  },
  {
    "path": "locale/en-en.js",
    "content": "export default {\n    labelIdle: 'Drag & Drop your files or <span class=\"filepond--label-action\"> Browse </span>',\n    labelInvalidField: 'Field contains invalid files',\n    labelFileWaitingForSize: 'Waiting for size',\n    labelFileSizeNotAvailable: 'Size not available',\n    labelFileLoading: 'Loading',\n    labelFileLoadError: 'Error during load',\n    labelFileProcessing: 'Uploading',\n    labelFileProcessingComplete: 'Upload complete',\n    labelFileProcessingAborted: 'Upload cancelled',\n    labelFileProcessingError: 'Error during upload',\n    labelFileProcessingRevertError: 'Error during revert',\n    labelFileRemoveError: 'Error during remove',\n    labelTapToCancel: 'tap to cancel',\n    labelTapToRetry: 'tap to retry',\n    labelTapToUndo: 'tap to undo',\n    labelButtonRemoveItem: 'Remove',\n    labelButtonAbortItemLoad: 'Abort',\n    labelButtonRetryItemLoad: 'Retry',\n    labelButtonAbortItemProcessing: 'Cancel',\n    labelButtonUndoItemProcessing: 'Undo',\n    labelButtonRetryItemProcessing: 'Retry',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'File is too large',\n    labelMaxFileSize: 'Maximum file size is {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maximum total size exceeded',\n    labelMaxTotalFileSize: 'Maximum total file size is {filesize}',\n    labelFileTypeNotAllowed: 'File of invalid type',\n    fileValidateTypeLabelExpectedTypes: 'Expects {allButLastType} or {lastType}',\n    imageValidateSizeLabelFormatError: 'Image type not supported',\n    imageValidateSizeLabelImageSizeTooSmall: 'Image is too small',\n    imageValidateSizeLabelImageSizeTooBig: 'Image is too big',\n    imageValidateSizeLabelExpectedMinSize: 'Minimum size is {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximum size is {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolution is too low',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolution is too high',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimum resolution is {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximum resolution is {maxResolution}'\n};\n"
  },
  {
    "path": "locale/es-es.js",
    "content": "export default {\n    labelIdle: 'Arrastra y suelta tus archivos o <span class = \"filepond--label-action\"> Examina <span>',\n    labelInvalidField: \"El campo contiene archivos inválidos\",\n    labelFileWaitingForSize: \"Esperando tamaño\",\n    labelFileSizeNotAvailable: \"Tamaño no disponible\",\n    labelFileLoading: \"Cargando\",\n    labelFileLoadError: \"Error durante la carga\",\n    labelFileProcessing: \"Subiendo\",\n    labelFileProcessingComplete: \"Subida completa\",\n    labelFileProcessingAborted: \"Subida cancelada\",\n    labelFileProcessingError: \"Error durante la subida\",\n    labelFileProcessingRevertError: \"Error durante la reversión\",\n    labelFileRemoveError: \"Error durante la eliminación\",\n    labelTapToCancel: \"toca para cancelar\",\n    labelTapToRetry: \"tocar para reintentar\",\n    labelTapToUndo: \"tocar para deshacer\",\n    labelButtonRemoveItem: \"Eliminar\",\n    labelButtonAbortItemLoad: \"Cancelar\",\n    labelButtonRetryItemLoad: \"Reintentar\",\n    labelButtonAbortItemProcessing: \"Cancelar\",\n    labelButtonUndoItemProcessing: \"Deshacer\",\n    labelButtonRetryItemProcessing: \"Reintentar\",\n    labelButtonProcessItem: \"Subir\",\n    labelMaxFileSizeExceeded: \"El archivo es demasiado grande\",\n    labelMaxFileSize: \"El tamaño máximo del archivo es {filesize}\",\n    labelMaxTotalFileSizeExceeded: \"Tamaño total máximo excedido\",\n    labelMaxTotalFileSize: \"El tamaño total máximo del archivo es {filesize}\",\n    labelFileTypeNotAllowed: \"Archivo de tipo inválido\",\n    fileValidateTypeLabelExpectedTypes: \"Espera {allButLastType} o {lastType}\",\n    imageValidateSizeLabelFormatError: \"Tipo de imagen no soportada\",\n    imageValidateSizeLabelImageSizeTooSmall: \"La imagen es demasiado pequeña\",\n    imageValidateSizeLabelImageSizeTooBig: \"La imagen es demasiado grande\",\n    imageValidateSizeLabelExpectedMinSize: \"El tamaño mínimo es {minWidth} x {minHeight}\",\n    imageValidateSizeLabelExpectedMaxSize: \"El tamaño máximo es {maxWidth} x {maxHeight}\",\n    imageValidateSizeLabelImageResolutionTooLow: \"La resolución es demasiado baja\",\n    imageValidateSizeLabelImageResolutionTooHigh: \"La resolución es demasiado alta\",\n    imageValidateSizeLabelExpectedMinResolution: \"La resolución mínima es {minResolution}\",\n    imageValidateSizeLabelExpectedMaxResolution: \"La resolución máxima es {maxResolution}\",\n};\n"
  },
  {
    "path": "locale/et-ee.js",
    "content": "export default {\n    labelIdle: 'Lohista oma failid siia või <span class=\"filepond--label-action\"> Sirvi </span>',\n    labelInvalidField: 'Väli sisaldab kehtetuid faile',\n    labelFileWaitingForSize: 'Ootab suurust',\n    labelFileSizeNotAvailable: 'Suurus pole saadaval',\n    labelFileLoading: 'Laadimine',\n    labelFileLoadError: 'Viga laadimisel',\n    labelFileProcessing: 'Üleslaadimine',\n    labelFileProcessingComplete: 'Üleslaadimine lõpetatud',\n    labelFileProcessingAborted: 'Üleslaadimine tühistatud',\n    labelFileProcessingError: 'Viga üleslaadimisel',\n    labelFileProcessingRevertError: 'Viga tagasivõtmisel',\n    labelFileRemoveError: 'Viga eemaldamisel',\n    labelTapToCancel: 'katkesta puudutades',\n    labelTapToRetry: 'proovi uuesti puudutades',\n    labelTapToUndo: 'võta tagasi puudutades',\n    labelButtonRemoveItem: 'Eemalda',\n    labelButtonAbortItemLoad: 'Katkesta',\n    labelButtonRetryItemLoad: 'Proovi uuesti',\n    labelButtonAbortItemProcessing: 'Tühista',\n    labelButtonUndoItemProcessing: 'Võta tagasi',\n    labelButtonRetryItemProcessing: 'Proovi uuesti',\n    labelButtonProcessItem: 'Lae üles',\n    labelMaxFileSizeExceeded: 'Fail on liiga suur',\n    labelMaxFileSize: 'Maksimaalne faili suurus on {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maksimaalne kogusuurus ületatud',\n    labelMaxTotalFileSize: 'Maksimaalne kogu faili suurus on {filesize}',\n    labelFileTypeNotAllowed: 'Keelatud failitüüp',\n    fileValidateTypeLabelExpectedTypes: 'Oodatakse {allButLastType} või {lastType}',\n    imageValidateSizeLabelFormatError: 'Pildi formaat ei ole toetatud',\n    imageValidateSizeLabelImageSizeTooSmall: 'Pilt on liiga väike',\n    imageValidateSizeLabelImageSizeTooBig: 'Pilt on liiga suur',\n    imageValidateSizeLabelExpectedMinSize: 'Minimaalne suurus on {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimaalne suurus on {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolutsioon on liiga madal',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolutsioon on liiga kõrge',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimaalne resolutsioon on {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimaalne resolutsioon on {maxResolution}'\n};\n"
  },
  {
    "path": "locale/fa_ir.js",
    "content": "export default {\n    labelIdle: 'فایل را اینجا بکشید و رها کنید، یا <span class=\"filepond--label-action\"> جستجو کنید </span>',\n    labelInvalidField: 'فیلد دارای فایل های نامعتبر است',\n    labelFileWaitingForSize: 'Waiting for size',\n    labelFileSizeNotAvailable: 'حجم فایل مجاز نیست',\n    labelFileLoading: 'درحال بارگذاری',\n    labelFileLoadError: 'خطا در زمان اجرا',\n    labelFileProcessing: 'درحال بارگذاری',\n    labelFileProcessingComplete: 'بارگذاری کامل شد',\n    labelFileProcessingAborted: 'بارگذاری لغو شد',\n    labelFileProcessingError: 'خطا در زمان بارگذاری',\n    labelFileProcessingRevertError: 'خطا در زمان حذف',\n    labelFileRemoveError: 'خطا در زمان حذف',\n    labelTapToCancel: 'برای لغو ضربه بزنید',\n    labelTapToRetry: 'برای تکرار کلیک کنید',\n    labelTapToUndo: 'برای برگشت کلیک کنید',\n    labelButtonRemoveItem: 'حذف',\n    labelButtonAbortItemLoad: 'لغو',\n    labelButtonRetryItemLoad: 'تکرار',\n    labelButtonAbortItemProcessing: 'لغو',\n    labelButtonUndoItemProcessing: 'برگشت',\n    labelButtonRetryItemProcessing: 'تکرار',\n    labelButtonProcessItem: 'بارگذاری',\n    labelMaxFileSizeExceeded: 'فایل بسیار حجیم است',\n    labelMaxFileSize: 'حداکثر مجاز فایل {filesize} است',\n    labelMaxTotalFileSizeExceeded: 'از حداکثر حجم فایل بیشتر شد',\n    labelMaxTotalFileSize: 'حداکثر حجم فایل {filesize} است',\n    labelFileTypeNotAllowed: 'نوع فایل نامعتبر است',\n    fileValidateTypeLabelExpectedTypes: 'در انتظار {allButLastType} یا {lastType}',\n    imageValidateSizeLabelFormatError: 'فرمت تصویر پشتیبانی نمی شود',\n    imageValidateSizeLabelImageSizeTooSmall: 'تصویر بسیار کوچک است',\n    imageValidateSizeLabelImageSizeTooBig: 'تصویر بسیار بزرگ است',\n    imageValidateSizeLabelExpectedMinSize: 'حداقل اندازه {minWidth} × {minHeight} است',\n    imageValidateSizeLabelExpectedMaxSize: 'حداکثر اندازه {maxWidth} × {maxHeight} است',\n    imageValidateSizeLabelImageResolutionTooLow: 'وضوح تصویر بسیار کم است',\n    imageValidateSizeLabelImageResolutionTooHigh: 'وضوع تصویر بسیار زیاد است',\n    imageValidateSizeLabelExpectedMinResolution: 'حداقل وضوح تصویر {minResolution} است',\n    imageValidateSizeLabelExpectedMaxResolution: 'حداکثر وضوح تصویر {maxResolution} است'\n};\n"
  },
  {
    "path": "locale/fi-fi.js",
    "content": "export default {\n    labelIdle: 'Vedä ja pudota tiedostoja tai <span class=\"filepond--label-action\"> Selaa </span>',\n    labelInvalidField: 'Kentässä on virheellisiä tiedostoja',\n    labelFileWaitingForSize: 'Odotetaan kokoa',\n    labelFileSizeNotAvailable: 'Kokoa ei saatavilla',\n    labelFileLoading: 'Ladataan',\n    labelFileLoadError: 'Virhe latauksessa',\n    labelFileProcessing: 'Lähetetään',\n    labelFileProcessingComplete: 'Lähetys valmis',\n    labelFileProcessingAborted: 'Lähetys peruttu',\n    labelFileProcessingError: 'Virhe lähetyksessä',\n    labelFileProcessingRevertError: 'Virhe palautuksessa',\n    labelFileRemoveError: 'Virhe poistamisessa',\n    labelTapToCancel: 'peruuta napauttamalla',\n    labelTapToRetry: 'yritä uudelleen napauttamalla',\n    labelTapToUndo: 'kumoa napauttamalla',\n    labelButtonRemoveItem: 'Poista',\n    labelButtonAbortItemLoad: 'Keskeytä',\n    labelButtonRetryItemLoad: 'Yritä uudelleen',\n    labelButtonAbortItemProcessing: 'Peruuta',\n    labelButtonUndoItemProcessing: 'Kumoa',\n    labelButtonRetryItemProcessing: 'Yritä uudelleen',\n    labelButtonProcessItem: 'Lähetä',\n    labelMaxFileSizeExceeded: 'Tiedoston koko on liian suuri',\n    labelMaxFileSize: 'Tiedoston maksimikoko on {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Tiedostojen yhdistetty maksimikoko ylitetty',\n    labelMaxTotalFileSize: 'Tiedostojen yhdistetty maksimikoko on {filesize}',\n    labelFileTypeNotAllowed: 'Tiedostotyyppiä ei sallita',\n    fileValidateTypeLabelExpectedTypes: 'Sallitaan {allButLastType} tai {lastType}',\n    imageValidateSizeLabelFormatError: 'Kuvatyyppiä ei tueta',\n    imageValidateSizeLabelImageSizeTooSmall: 'Kuva on liian pieni',\n    imageValidateSizeLabelImageSizeTooBig: 'Kuva on liian suuri',\n    imageValidateSizeLabelExpectedMinSize: 'Minimikoko on {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimikoko on {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resoluutio on liian pieni',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resoluutio on liian suuri',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimiresoluutio on {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimiresoluutio on {maxResolution}'\n};\n"
  },
  {
    "path": "locale/fr-fr.js",
    "content": "export default {\n    labelIdle: 'Faites glisser vos fichiers ou <span class = \"filepond--label-action\"> Parcourir </span>',\n    labelInvalidField: \"Le champ contient des fichiers invalides\",\n    labelFileWaitingForSize: \"En attente de taille\",\n    labelFileSizeNotAvailable: \"Taille non disponible\",\n    labelFileLoading: \"Chargement\",\n    labelFileLoadError: \"Erreur durant le chargement\",\n    labelFileProcessing: \"Traitement\",\n    labelFileProcessingComplete: \"Traitement effectué\",\n    labelFileProcessingAborted: \"Traitement interrompu\",\n    labelFileProcessingError: \"Erreur durant le traitement\",\n    labelFileProcessingRevertError: \"Erreur durant la restauration\",\n    labelFileRemoveError: \"Erreur durant la suppression\",\n    labelTapToCancel: \"appuyer pour annuler\",\n    labelTapToRetry: \"appuyer pour réessayer\",\n    labelTapToUndo: \"appuyer pour revenir en arrière\",\n    labelButtonRemoveItem: \"Retirer\",\n    labelButtonAbortItemLoad: \"Annuler\",\n    labelButtonRetryItemLoad: \"Recommencer\",\n    labelButtonAbortItemProcessing: \"Annuler\",\n    labelButtonUndoItemProcessing: \"Revenir en arrière\",\n    labelButtonRetryItemProcessing: \"Recommencer\",\n    labelButtonProcessItem: \"Transférer\",\n    labelMaxFileSizeExceeded: \"Le fichier est trop volumineux\",\n    labelMaxFileSize: \"La taille maximale de fichier est {filesize}\",\n    labelMaxTotalFileSizeExceeded: \"Taille totale maximale dépassée\",\n    labelMaxTotalFileSize: \"La taille totale maximale des fichiers est {filesize}\",\n    labelFileTypeNotAllowed: \"Fichier non valide\",\n    fileValidateTypeLabelExpectedTypes: \"Attendu {allButLastType} ou {lastType}\",\n    imageValidateSizeLabelFormatError: \"Type d'image non pris en charge\",\n    imageValidateSizeLabelImageSizeTooSmall: \"L'image est trop petite\",\n    imageValidateSizeLabelImageSizeTooBig: \"L'image est trop grande\",\n    imageValidateSizeLabelExpectedMinSize: \"La taille minimale est {minWidth} × {minHeight}\",\n    imageValidateSizeLabelExpectedMaxSize: \"La taille maximale est {maxWidth} × {maxHeight}\",\n    imageValidateSizeLabelImageResolutionTooLow: \"La résolution est trop faible\",\n    imageValidateSizeLabelImageResolutionTooHigh: \"La résolution est trop élevée\",\n    imageValidateSizeLabelExpectedMinResolution: \"La résolution minimale est {minResolution}\",\n    imageValidateSizeLabelExpectedMaxResolution: \"La résolution maximale est {maxResolution}\",\n};\n"
  },
  {
    "path": "locale/he-he.js",
    "content": "export default {\n    labelIdle: 'גרור ושחרר את הקבצים כאן או <span class=\"filepond--label-action\"> לחץ כאן לבחירה </span>',\n    labelInvalidField: 'קובץ לא חוקי',\n    labelFileWaitingForSize: 'מחשב את גודל הקבצים',\n    labelFileSizeNotAvailable: 'לא ניתן לקבוע את גודל הקבצים',\n    labelFileLoading: 'טוען...',\n    labelFileLoadError: 'שגיאה ארעה בעת טעינת הקבצים',\n    labelFileProcessing: 'מעלה את הקבצים',\n    labelFileProcessingComplete: 'העלאת הקבצים הסתיימה',\n    labelFileProcessingAborted: 'העלאת הקבצים בוטלה',\n    labelFileProcessingError: 'שגיאה ארעה בעת העלאת הקבצים',\n    labelFileProcessingRevertError: 'שגיאה ארעה בעת שחזור הקבצים',\n    labelFileRemoveError: 'שגיאה ארעה בעת הסרת הקובץ',\n    labelTapToCancel: 'הקלק לביטול',\n    labelTapToRetry: 'הקלק לנסות שנית',\n    labelTapToUndo: 'הקלק לשחזר',\n    labelButtonRemoveItem: 'הסר',\n    labelButtonAbortItemLoad: 'בטל',\n    labelButtonRetryItemLoad: 'טען שנית',\n    labelButtonAbortItemProcessing: 'בטל',\n    labelButtonUndoItemProcessing: 'שחזר',\n    labelButtonRetryItemProcessing: 'נסה שנית',\n    labelButtonProcessItem: 'העלה קובץ',\n    labelMaxFileSizeExceeded: 'הקובץ גדול מדי',\n    labelMaxFileSize: 'גודל המירבי המותר הוא: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'גודל הקבצים חורג מהכמות המותרת',\n    labelMaxTotalFileSize: 'הגודל המירבי של סך הקבצים: {filesize}',\n    labelFileTypeNotAllowed: 'קובץ מסוג זה אינו מותר',\n    fileValidateTypeLabelExpectedTypes: 'הקבצים המותרים הם {allButLastType} או {lastType}',\n    imageValidateSizeLabelFormatError: 'תמונה בפורמט זה אינה נתמכת',\n    imageValidateSizeLabelImageSizeTooSmall: 'תמונה זו קטנה מדי',\n    imageValidateSizeLabelImageSizeTooBig: 'תמונה זו גדולה מדי',\n    imageValidateSizeLabelExpectedMinSize: 'הגודל צריך להיות לפחות: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'הגודל המרבי המותר: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'הרזולוציה של תמונה זו נמוכה מדי',\n    imageValidateSizeLabelImageResolutionTooHigh: 'הרזולוציה של תמונה זו גבוהה מדי',\n    imageValidateSizeLabelExpectedMinResolution: 'הרזולוציה צריכה להיות לפחות: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'הרזולוציה המירבית המותרת היא: {maxResolution}',\n};\n"
  },
  {
    "path": "locale/hr-hr.js",
    "content": "export default {\n    labelIdle: 'Ovdje \"ispusti\" datoteku ili <span class=\"filepond--label-action\"> Pretraži </span>',\n    labelInvalidField: 'Polje sadrži neispravne datoteke',\n    labelFileWaitingForSize: 'Čekanje na veličinu datoteke',\n    labelFileSizeNotAvailable: 'Veličina datoteke nije dostupna',\n    labelFileLoading: 'Učitavanje',\n    labelFileLoadError: 'Greška tijekom učitavanja',\n    labelFileProcessing: 'Prijenos',\n    labelFileProcessingComplete: 'Prijenos završen',\n    labelFileProcessingAborted: 'Prijenos otkazan',\n    labelFileProcessingError: 'Greška tijekom prijenosa',\n    labelFileProcessingRevertError: 'Greška tijekom vraćanja',\n    labelFileRemoveError: 'Greška tijekom uklananja datoteke',\n    labelTapToCancel: 'Dodirni za prekid',\n    labelTapToRetry: 'Dodirni za ponovno',\n    labelTapToUndo: 'Dodirni za vraćanje',\n    labelButtonRemoveItem: 'Ukloni',\n    labelButtonAbortItemLoad: 'Odbaci',\n    labelButtonRetryItemLoad: 'Ponovi',\n    labelButtonAbortItemProcessing: 'Prekini',\n    labelButtonUndoItemProcessing: 'Vrati',\n    labelButtonRetryItemProcessing: 'Ponovi',\n    labelButtonProcessItem: 'Prijenos',\n    labelMaxFileSizeExceeded: 'Datoteka je prevelika',\n    labelMaxFileSize: 'Maksimalna veličina datoteke je {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maksimalna ukupna veličina datoteke prekoračena',\n    labelMaxTotalFileSize: 'Maksimalna ukupna veličina datoteke je {filesize}',\n    labelFileTypeNotAllowed: 'Tip datoteke nije podržan',\n    fileValidateTypeLabelExpectedTypes: 'Očekivan {allButLastType} ili {lastType}',\n    imageValidateSizeLabelFormatError: 'Tip slike nije podržan',\n    imageValidateSizeLabelImageSizeTooSmall: 'Slika je premala',\n    imageValidateSizeLabelImageSizeTooBig: 'Slika je prevelika',\n    imageValidateSizeLabelExpectedMinSize: 'Minimalna veličina je {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimalna veličina je {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rezolucija je preniska',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rezolucija je previsoka',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimalna rezolucija je {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimalna rezolucija je {maxResolution}'\n};"
  },
  {
    "path": "locale/hu-hu.js",
    "content": "export default {\n    labelIdle: 'Mozgasd ide a fájlt a feltöltéshez, vagy <span class=\"filepond--label-action\"> tallózás </span>',\n    labelInvalidField: 'A mező érvénytelen fájlokat tartalmaz',\n    labelFileWaitingForSize: 'Fáljméret kiszámolása',\n    labelFileSizeNotAvailable: 'A fájlméret nem elérhető',\n    labelFileLoading: 'Töltés',\n    labelFileLoadError: 'Hiba a betöltés során',\n    labelFileProcessing: 'Feltöltés',\n    labelFileProcessingComplete: 'Sikeres feltöltés',\n    labelFileProcessingAborted: 'A feltöltés megszakítva',\n    labelFileProcessingError: 'Hiba történt a feltöltés során',\n    labelFileProcessingRevertError: 'Hiba a visszaállítás során',\n    labelFileRemoveError: 'Hiba történt az eltávolítás során',\n    labelTapToCancel: 'koppints a törléshez',\n    labelTapToRetry: 'koppints az újrakezdéshez',\n    labelTapToUndo: 'koppints a visszavonáshoz',\n    labelButtonRemoveItem: 'Eltávolítás',\n    labelButtonAbortItemLoad: 'Megszakítás',\n    labelButtonRetryItemLoad: 'Újrapróbálkozás',\n    labelButtonAbortItemProcessing: 'Megszakítás',\n    labelButtonUndoItemProcessing: 'Visszavonás',\n    labelButtonRetryItemProcessing: 'Újrapróbálkozás',\n    labelButtonProcessItem: 'Feltöltés',\n    labelMaxFileSizeExceeded: 'A fájl túllépte a maximális méretet',\n    labelMaxFileSize: 'Maximális fájlméret: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Túllépte a maximális teljes méretet',\n    labelMaxTotalFileSize: 'A maximáis teljes fájlméret: {filesize}',\n    labelFileTypeNotAllowed: 'Érvénytelen típusú fájl',\n    fileValidateTypeLabelExpectedTypes: 'Engedélyezett típusok {allButLastType} vagy {lastType}',\n    imageValidateSizeLabelFormatError: 'A képtípus nem támogatott',\n    imageValidateSizeLabelImageSizeTooSmall: 'A kép túl kicsi',\n    imageValidateSizeLabelImageSizeTooBig: 'A kép túl nagy',\n    imageValidateSizeLabelExpectedMinSize: 'Minimum méret: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximum méret: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'A felbontás túl alacsony',\n    imageValidateSizeLabelImageResolutionTooHigh: 'A felbontás túl magas',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimáis felbontás: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximális felbontás: {maxResolution}'\n  };"
  },
  {
    "path": "locale/id-id.js",
    "content": "export default {\n    labelIdle: 'Seret & Jatuhkan berkas Anda atau <span class=\"filepond--label-action\">Jelajahi</span>',\n    labelInvalidField: 'Isian berisi berkas yang tidak valid',\n    labelFileWaitingForSize: 'Menunggu ukuran berkas',\n    labelFileSizeNotAvailable: 'Ukuran berkas tidak tersedia',\n    labelFileLoading: 'Memuat',\n    labelFileLoadError: 'Kesalahan saat memuat',\n    labelFileProcessing: 'Mengunggah',\n    labelFileProcessingComplete: 'Pengunggahan selesai',\n    labelFileProcessingAborted: 'Pengunggahan dibatalkan',\n    labelFileProcessingError: 'Kesalahan saat pengunggahan',\n    labelFileProcessingRevertError: 'Kesalahan saat pemulihan',\n    labelFileRemoveError: 'Kesalahan saat penghapusan',\n    labelTapToCancel: 'ketuk untuk membatalkan',\n    labelTapToRetry: 'ketuk untuk mencoba lagi',\n    labelTapToUndo: 'ketuk untuk mengurungkan',\n    labelButtonRemoveItem: 'Hapus',\n    labelButtonAbortItemLoad: 'Batalkan',\n    labelButtonRetryItemLoad: 'Coba Kembali',\n    labelButtonAbortItemProcessing: 'Batalkan',\n    labelButtonUndoItemProcessing: 'Urungkan',\n    labelButtonRetryItemProcessing: 'Coba Kembali',\n    labelButtonProcessItem: 'Unggah',\n    labelMaxFileSizeExceeded: 'Berkas terlalu besar',\n    labelMaxFileSize: 'Ukuran berkas maksimum adalah {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Jumlah berkas maksimum terlampaui',\n    labelMaxTotalFileSize: 'Jumlah berkas maksimum adalah {filesize}',\n    labelFileTypeNotAllowed: 'Jenis berkas tidak valid',\n    fileValidateTypeLabelExpectedTypes: 'Mengharapkan {allButLastType} atau {lastType}',\n    imageValidateSizeLabelFormatError: 'Jenis citra tidak didukung',\n    imageValidateSizeLabelImageSizeTooSmall: 'Citra terlalu kecil',\n    imageValidateSizeLabelImageSizeTooBig: 'Citra terlalu besar',\n    imageValidateSizeLabelExpectedMinSize: 'Ukuran minimum adalah {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Ukuran maksimum adalah {minWidth} × {minHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolusi terlalu rendah',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolusi terlalu tinggi',\n    imageValidateSizeLabelExpectedMinResolution: 'Resolusi minimum adalah {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Resolusi maksimum adalah {maxResolution}'\n  };\n"
  },
  {
    "path": "locale/it-it.js",
    "content": "export default {\n    labelIdle: 'Trascina e rilascia i tuoi file oppure <span class=\"filepond--label-action\"> Sfoglia <span>',\n    labelInvalidField: \"Il campo contiene dei file non validi\",\n    labelFileWaitingForSize: \"In attesa della dimensione\",\n    labelFileSizeNotAvailable: \"Dimensione non disponibile\",\n    labelFileLoading: \"Caricamento\",\n    labelFileLoadError: \"Errore durante il caricamento\",\n    labelFileProcessing: \"Caricamento\",\n    labelFileProcessingComplete: \"Caricamento completato\",\n    labelFileProcessingAborted: \"Caricamento cancellato\",\n    labelFileProcessingError: \"Errore durante il caricamento\",\n    labelFileProcessingRevertError: \"Errore durante il ripristino\",\n    labelFileRemoveError: \"Errore durante l'eliminazione\",\n    labelTapToCancel: \"tocca per cancellare\",\n    labelTapToRetry: \"tocca per riprovare\",\n    labelTapToUndo: \"tocca per ripristinare\",\n    labelButtonRemoveItem: \"Elimina\",\n    labelButtonAbortItemLoad: \"Cancella\",\n    labelButtonRetryItemLoad: \"Ritenta\",\n    labelButtonAbortItemProcessing: \"Cancella\",\n    labelButtonUndoItemProcessing: \"Indietro\",\n    labelButtonRetryItemProcessing: \"Ritenta\",\n    labelButtonProcessItem: \"Carica\",\n    labelMaxFileSizeExceeded: \"La dimensione del file è eccessiva\",\n    labelMaxFileSize: \"La dimensione massima del file è {filesize}\",\n    labelMaxTotalFileSizeExceeded: \"Dimensione totale massima superata\",\n    labelMaxTotalFileSize: \"La dimensione massima totale dei file è {filesize}\",\n    labelFileTypeNotAllowed: \"File non supportato\",\n    fileValidateTypeLabelExpectedTypes: \"Aspetta {allButLastType} o {lastType}\",\n    imageValidateSizeLabelFormatError: \"Tipo di immagine non supportata\",\n    imageValidateSizeLabelImageSizeTooSmall: \"L'immagine è troppo piccola\",\n    imageValidateSizeLabelImageSizeTooBig: \"L'immagine è troppo grande\",\n    imageValidateSizeLabelExpectedMinSize: \"La dimensione minima è {minWidth} × {minHeight}\",\n    imageValidateSizeLabelExpectedMaxSize: \"La dimensione massima è {maxWidth} × {maxHeight}\",\n    imageValidateSizeLabelImageResolutionTooLow: \"La risoluzione è troppo bassa\",\n    imageValidateSizeLabelImageResolutionTooHigh: \"La risoluzione è troppo alta\",\n    imageValidateSizeLabelExpectedMinResolution: \"La risoluzione minima è {minResolution}\",\n    imageValidateSizeLabelExpectedMaxResolution: \"La risoluzione massima è {maxResolution}\",\n};\n"
  },
  {
    "path": "locale/ja-ja.js",
    "content": "export default {\n    labelIdle: 'ファイルをドラッグ&ドロップ又は<span class=\"filepond--label-action\">ファイル選択</span>',\n    labelInvalidField: \"アップロードできないファイルが含まれています\",\n    labelFileWaitingForSize: \"ファイルサイズを待っています\",\n    labelFileSizeNotAvailable: \"ファイルサイズがみつかりません\",\n    labelFileLoading: \"読込中...\",\n    labelFileLoadError: \"読込中にエラーが発生\",\n    labelFileProcessing: \"読込中...\",\n    labelFileProcessingComplete: \"アップロード完了\",                                                                                          \n    labelFileProcessingAborted: \"アップロードがキャンセルされました\",                                                                           \n    labelFileProcessingError: \"アップロード中にエラーが発生\",                                                                                 \n    labelFileProcessingRevertError: \"ロールバック中にエラーが発生\",                                                                           \n    labelFileRemoveError: \"削除中にエラーが発生\",                                                                                             \n    labelTapToCancel: \"クリックしてキャンセル\",                                                                                               \n    labelTapToRetry: \"クリックしてもう一度お試し下さい\",                                                                                      \n    labelTapToUndo: \"元に戻すにはタップします\",                                                                                               \n    labelButtonRemoveItem: \"削除\",                                                                                                            \n    labelButtonAbortItemLoad: \"中断\",                                                                                                         \n    labelButtonRetryItemLoad: \"もう一度実行\",                                                                                                 \n    labelButtonAbortItemProcessing: \"キャンセル\",                                                                                             \n    labelButtonUndoItemProcessing: \"元に戻す\",                                                                                                \n    labelButtonRetryItemProcessing: \"もう一度実行\",                                                                                           \n    labelButtonProcessItem: \"アップロード\",                                                                                                   \n    labelMaxFileSizeExceeded: \"ファイルサイズが大きすぎます\",                                                                                 \n    labelMaxFileSize: \"最大ファイルサイズは {filesize} です\",                                                                                 \n    labelMaxTotalFileSizeExceeded: \"最大合計サイズを超えました\",                                                                              \n    labelMaxTotalFileSize: \"最大合計ファイルサイズは {filesize} です\",                                                                        \n    labelFileTypeNotAllowed: \"無効なファイルです\",                                                                                            \n    fileValidateTypeLabelExpectedTypes: \"サポートしているファイルは {allButLastType} 又は {lastType} です\",                                   \n    imageValidateSizeLabelFormatError: \"サポートしていない画像です\",                                                                          \n    imageValidateSizeLabelImageSizeTooSmall: \"画像が小さすぎます\",                                                                            \n    imageValidateSizeLabelImageSizeTooBig: \"画像が大きすぎます\",                                                                              \n    imageValidateSizeLabelExpectedMinSize: \"画像の最小サイズは{minWidth}×{minHeight}です\",                                                   \n    imageValidateSizeLabelExpectedMaxSize: \"画像の最大サイズは{maxWidth} × {maxHeight}です\",                                                 \n    imageValidateSizeLabelImageResolutionTooLow: \"画像の解像度が低すぎます\",                                                                  \n    imageValidateSizeLabelImageResolutionTooHigh: \"画像の解像度が高すぎます\",                                                                 \n    imageValidateSizeLabelExpectedMinResolution: \"画像の最小解像度は{minResolution}です\",                                                     \n    imageValidateSizeLabelExpectedMaxResolution: \"画像の最大解像度は{maxResolution}です\",                                                     \n};\n"
  },
  {
    "path": "locale/km-km.js",
    "content": "export default {\n    labelIdle: 'ទាញ&ដាក់ហ្វាល់ឯកសាររបស់អ្នក ឬ <span class=\"filepond--label-action\"> ស្វែងរក </span>',\n    labelInvalidField: 'ចន្លោះមានឯកសារមិនត្រឹមត្រូវ',\n    labelFileWaitingForSize: 'កំពុងរង់ចាំទំហំ',\n    labelFileSizeNotAvailable: 'ទំហំមិនអាចប្រើបាន',\n    labelFileLoading: 'កំពុងដំណើរការ',\n    labelFileLoadError: 'មានបញ្ហាកំឡុងពេលដំណើរការ',\n    labelFileProcessing: 'កំពុងផ្ទុកឡើង',\n    labelFileProcessingComplete: 'ការផ្ទុកឡើងពេញលេញ',\n    labelFileProcessingAborted: 'ការបង្ហោះត្រូវបានបោះបង់',\n    labelFileProcessingError: 'មានបញ្ហាកំឡុងពេលកំពុងផ្ទុកឡើង',\n    labelFileProcessingRevertError: 'មានបញ្ហាកំឡុងពេលត្រឡប់',\n    labelFileRemoveError: 'មានបញ្ហាកំឡុងពេលដកចេញ',\n    labelTapToCancel: 'ចុចដើម្បីបោះបង់',\n    labelTapToRetry: 'ចុចដើម្បីព្យាយាមម្តងទៀត',\n    labelTapToUndo: 'ចុចដើម្បីមិនធ្វើវិញ',\n    labelButtonRemoveItem: 'យកចេញ',\n    labelButtonAbortItemLoad: 'បោះបង់',\n    labelButtonRetryItemLoad: 'ព្យាយាមម្តងទៀត',\n    labelButtonAbortItemProcessing: 'បោះបង់',\n    labelButtonUndoItemProcessing: 'មិនធ្វើវិញ',\n    labelButtonRetryItemProcessing: 'ព្យាយាមម្តងទៀត',\n    labelButtonProcessItem: 'ផ្ទុកឡើង',\n    labelMaxFileSizeExceeded: 'ឯកសារធំពេក',\n    labelMaxFileSize: 'ទំហំឯកសារអតិបរមាគឺ {filesize}',\n    labelMaxTotalFileSizeExceeded: 'លើសទំហំសរុបអតិបរមា',\n    labelMaxTotalFileSize: 'ទំហំឯកសារសរុបអតិបរមាគឺ {filesize}',\n    labelFileTypeNotAllowed: 'ប្រភេទឯកសារមិនត្រឹមត្រូវ',\n    fileValidateTypeLabelExpectedTypes: 'រំពឹងថា {allButLastType} ឬ {lastType}',\n    imageValidateSizeLabelFormatError: 'ប្រភេទរូបភាពមិនត្រឹមត្រូវ',\n    imageValidateSizeLabelImageSizeTooSmall: 'រូបភាពតូចពេក',\n    imageValidateSizeLabelImageSizeTooBig: 'រូបភាពធំពេក',\n    imageValidateSizeLabelExpectedMinSize: 'ទំហំអប្បបរមាគឺ {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'ទំហំអតិបរមាគឺ {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'គុណភាពបង្ហាញទាបពេក',\n    imageValidateSizeLabelImageResolutionTooHigh: 'គុណភាពបង្ហាញខ្ពស់ពេក',\n    imageValidateSizeLabelExpectedMinResolution: 'គុណភាពបង្ហាញអប្បបរមាគឺ {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'គុណភាពបង្ហាញអតិបរមាគឺ {maxResolution}'\n};\n"
  },
  {
    "path": "locale/ko-kr.js",
    "content": "export default {\n    labelIdle: '파일을 드래그 하거나 <span class=\"filepond--label-action\"> 찾아보기 </span>',\n    labelInvalidField: '필드에 유효하지 않은 파일이 있습니다.',\n    labelFileWaitingForSize: '용량 확인중',\n    labelFileSizeNotAvailable: '사용할 수 없는 용량',\n    labelFileLoading: '불러오는 중',\n    labelFileLoadError: '파일 불러오기 실패',\n    labelFileProcessing: '업로드 중',\n    labelFileProcessingComplete: '업로드 성공',\n    labelFileProcessingAborted: '업로드 취소됨',\n    labelFileProcessingError: '파일 업로드 실패',\n    labelFileProcessingRevertError: '되돌리기 실패',\n    labelFileRemoveError: '제거 실패',\n    labelTapToCancel: '탭하여 취소',\n    labelTapToRetry: '탭하여 재시작',\n    labelTapToUndo: '탭하여 실행 취소',\n    labelButtonRemoveItem: '제거',\n    labelButtonAbortItemLoad: '중단',\n    labelButtonRetryItemLoad: '재시작',\n    labelButtonAbortItemProcessing: '취소',\n    labelButtonUndoItemProcessing: '실행 취소',\n    labelButtonRetryItemProcessing: '재시작',\n    labelButtonProcessItem: '업로드',\n    labelMaxFileSizeExceeded: '파일이 너무 큽니다.',\n    labelMaxFileSize: '최대 파일 용량은 {filesize} 입니다.',\n    labelMaxTotalFileSizeExceeded: '최대 전체 파일 용량 초과하였습니다.',\n    labelMaxTotalFileSize: '최대 전체 파일 용량은 {filesize} 입니다.',\n    labelFileTypeNotAllowed: '잘못된 형식의 파일',\n    fileValidateTypeLabelExpectedTypes: '{allButLastType} 또는 {lastType}',\n    imageValidateSizeLabelFormatError: '지원되지 않는 이미지 유형',\n    imageValidateSizeLabelImageSizeTooSmall: '이미지가 너무 작습니다.',\n    imageValidateSizeLabelImageSizeTooBig: '이미지가 너무 큽니다.',\n    imageValidateSizeLabelExpectedMinSize: '이미지 최소 크기는 {minWidth} × {minHeight} 입니다',\n    imageValidateSizeLabelExpectedMaxSize: '이미지 최대 크기는 {maxWidth} × {maxHeight} 입니다',\n    imageValidateSizeLabelImageResolutionTooLow: '해상도가 너무 낮습니다.',\n    imageValidateSizeLabelImageResolutionTooHigh: '해상도가 너무 높습니다.',\n    imageValidateSizeLabelExpectedMinResolution: '최소 해상도는 {minResolution} 입니다.',\n    imageValidateSizeLabelExpectedMaxResolution: '최대 해상도는 {maxResolution} 입니다.'\n};\n"
  },
  {
    "path": "locale/ku-ckb.js",
    "content": "export default {\n    labelIdle: 'پەڕگەکان فڕێ بدە ئێرە بۆ بارکردن یان <span class=\"filepond--label-action\"> هەڵبژێرە </span>',\n    labelInvalidField: 'پەڕگەی نادروستی تێدایە',\n    labelFileWaitingForSize: 'چاوەڕوانیی قەبارە',\n    labelFileSizeNotAvailable: 'قەبارە بەردەست نیە',\n    labelFileLoading: 'بارکردن',\n    labelFileLoadError: 'هەڵە لەماوەی بارکردن',\n    labelFileProcessing: 'بارکردن',\n    labelFileProcessingComplete: 'بارکردن تەواو بوو',\n    labelFileProcessingAborted: 'بارکردن هەڵوەشایەوە',\n    labelFileProcessingError: 'هەڵە لەکاتی بارکردندا',\n    labelFileProcessingRevertError: 'هەڵە لە کاتی گەڕانەوە',\n    labelFileRemoveError: 'هەڵە لە کاتی سڕینەوە',\n    labelTapToCancel: 'بۆ هەڵوەشاندنەوە Tab دابگرە',\n    labelTapToRetry: 'tap دابگرە بۆ دووبارەکردنەوە',\n    labelTapToUndo: 'tap دابگرە بۆ گەڕاندنەوە',\n    labelButtonRemoveItem: 'سڕینەوە',\n    labelButtonAbortItemLoad: 'هەڵوەشاندنەوە',\n    labelButtonRetryItemLoad: 'هەوڵدانەوە',\n    labelButtonAbortItemProcessing: 'پەشیمانبوونەوە',\n    labelButtonUndoItemProcessing: 'گەڕاندنەوە',\n    labelButtonRetryItemProcessing: 'هەوڵدانەوە',\n    labelButtonProcessItem: 'بارکردن',\n    labelMaxFileSizeExceeded: 'پەڕگە زۆر گەورەیە',\n    labelMaxFileSize: 'زۆرترین قەبارە {filesize}',\n    labelMaxTotalFileSizeExceeded: 'زۆرترین قەبارەی کۆی گشتی تێپەڕێندرا',\n    labelMaxTotalFileSize: 'زۆرترین قەبارەی کۆی پەڕگە {filesize}',\n    labelFileTypeNotAllowed: 'جۆری پەڕگەکە نادروستە',\n    fileValidateTypeLabelExpectedTypes: 'جگە لە {allButLastType} یان {lastType}',\n    imageValidateSizeLabelFormatError: 'جۆری وێنە پاڵپشتیی نەکراوە',\n    imageValidateSizeLabelImageSizeTooSmall: 'وێنەکە زۆر بچووکە',\n    imageValidateSizeLabelImageSizeTooBig: 'وێنەکە زۆر گەورەیە',\n    imageValidateSizeLabelExpectedMinSize: 'کەمترین قەبارە {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'زۆرترین قەبارە {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'وردبینییەکەی زۆر کەمە',\n    imageValidateSizeLabelImageResolutionTooHigh: 'وردبینییەکەی زۆر بەرزە',\n    imageValidateSizeLabelExpectedMinResolution: 'کەمترین وردبینیی {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'زۆرترین وردبینی {maxResolution}'\n};\n"
  },
  {
    "path": "locale/kur-ckb.js",
    "content": "export default {\n    labelIdle:\n      'فایلەکانت ڕابکێشە یان <span class=\"filepond--label-action\"> دیاری بکە </span>',\n    labelInvalidField: \"هەڵبژاردنەکان فایلی نادروستی تێدایە\",\n    labelFileWaitingForSize: \"چاوەڕوانکردنی قەبارە\",\n    labelFileSizeNotAvailable: \"قەبارە بەردەست نییە\",\n    labelFileLoading: \"چاوەڕوان بە\",\n    labelFileLoadError: \"هەڵەیەک ڕوویدا لە کاتی خوێندنەوە\",\n    labelFileProcessing: \"بارکردن\",\n    labelFileProcessingComplete: \"بارکردن سەرکەوتو بوو\",\n    labelFileProcessingAborted: \"بارکردن پاشگەزکرایەوە\",\n    labelFileProcessingError: \"هەڵەیەک ڕوویدا لەکاتی بارکردن\",\n    labelFileProcessingRevertError: \"هەڵەیەک ڕوویدا لەکاتی گەڕاندنەوە\",\n    labelFileRemoveError: \"هەڵەیەک ڕوویدا لەکاتی سڕینەوە\",\n    labelTapToCancel: \"کلیک بۆ پاشگەزبوونەوە\",\n    labelTapToRetry: \"کلیک بۆ دووبارەکردنەوە\",\n    labelTapToUndo: \"کلیک بۆ گەڕاندنەوە\",\n    labelButtonRemoveItem: \"سڕینەوە\",\n    labelButtonAbortItemLoad: \"لەباربردن\",\n    labelButtonRetryItemLoad: \"دووبارەکردنەوە\",\n    labelButtonAbortItemProcessing: \"پاشگەزکردنەوە\",\n    labelButtonUndoItemProcessing: \"گەڕاندنەوە\",\n    labelButtonRetryItemProcessing: \"دووبارەکردنەوە\",\n    labelButtonProcessItem: \"بارکردن\",\n    labelMaxFileSizeExceeded: \"قەبارەی فایلەکە زۆرە\",\n    labelMaxFileSize: \"قەبارەی فایل پێویستە لە {filesize} کەمتر بێت\",\n    labelMaxTotalFileSizeExceeded: \"قەبارەی فایل زۆر زیاترە لە قەبارەی دیاریکراو\",\n    labelMaxTotalFileSize:\n      \"کۆی گشتی قەبارەی فایل پێویستە لە {filesize} کەمتر بێت\",\n    labelFileTypeNotAllowed: \"جۆری فایل نادروستە\",\n    fileValidateTypeLabelExpectedTypes:\n      \"چاوەڕوانی {allButLastType} یان {lastType} کرا\",\n    imageValidateSizeLabelFormatError: \"جۆری وێنە نادروستە\",\n    imageValidateSizeLabelImageSizeTooSmall: \"وێنە زۆر بچووکە\",\n    imageValidateSizeLabelImageSizeTooBig: \"وێنە زۆر گەورەیە\",\n    imageValidateSizeLabelExpectedMinSize:\n      \"کەمترین پانی و بەرزی پێویستە {minWidth} × {minHeight} بیت\",\n    imageValidateSizeLabelExpectedMaxSize:\n      \"زۆرترین پانی و بەرزی پێویستە {maxWidth} × {maxHeight} بێت\",\n    imageValidateSizeLabelImageResolutionTooLow: \"چوارچێوەکە زۆر کەمە\",\n    imageValidateSizeLabelImageResolutionTooHigh: \"چوارچێوەکە زۆر بەرزە\",\n    imageValidateSizeLabelExpectedMinResolution:\n      \"کەمترین چوارچێوە پێویستە {minResolution} بێت\",\n    imageValidateSizeLabelExpectedMaxResolution:\n      \"بەرزترین چوارچێوە پێویستە {maxResolution} بێت\",\n};\n"
  },
  {
    "path": "locale/lt-lt.js",
    "content": "export default {\n    labelIdle: 'Įdėkite failus čia arba <span class=\"filepond--label-action\"> Ieškokite </span>',\n    labelInvalidField: 'Laukelis talpina netinkamus failus',\n    labelFileWaitingForSize: 'Laukiama dydžio',\n    labelFileSizeNotAvailable: 'Dydis nežinomas',\n    labelFileLoading: 'Kraunama',\n    labelFileLoadError: 'Klaida įkeliant',\n    labelFileProcessing: 'Įkeliama',\n    labelFileProcessingComplete: 'Įkėlimas sėkmingas',\n    labelFileProcessingAborted: 'Įkėlimas atšauktas',\n    labelFileProcessingError: 'Įkeliant įvyko klaida',\n    labelFileProcessingRevertError: 'Atšaukiant įvyko klaida',\n    labelFileRemoveError: 'Ištrinant įvyko klaida',\n    labelTapToCancel: 'Palieskite norėdami atšaukti',\n    labelTapToRetry: 'Palieskite norėdami pakartoti',\n    labelTapToUndo: 'Palieskite norėdami atšaukti',\n    labelButtonRemoveItem: 'Ištrinti',\n    labelButtonAbortItemLoad: 'Sustabdyti',\n    labelButtonRetryItemLoad: 'Pakartoti',\n    labelButtonAbortItemProcessing: 'Atšaukti',\n    labelButtonUndoItemProcessing: 'Atšaukti',\n    labelButtonRetryItemProcessing: 'Pakartoti',\n    labelButtonProcessItem: 'Įkelti',\n    labelMaxFileSizeExceeded: 'Failas per didelis',\n    labelMaxFileSize: 'Maksimalus failo dydis yra {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Viršijote maksimalų leistiną dydį',\n    labelMaxTotalFileSize: 'Maksimalus leistinas dydis yra {filesize}',\n    labelFileTypeNotAllowed: 'Netinkamas failas',\n    fileValidateTypeLabelExpectedTypes: 'Tikisi {allButLastType} arba {lastType}',\n    imageValidateSizeLabelFormatError: 'Nuotraukos formatas nepalaikomas',\n    imageValidateSizeLabelImageSizeTooSmall: 'Nuotrauka per maža',\n    imageValidateSizeLabelImageSizeTooBig: 'Nuotrauka per didelė',\n    imageValidateSizeLabelExpectedMinSize: 'Minimalus dydis yra {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimalus dydis yra {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rezoliucija per maža',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rezoliucija per didelė',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimali rezoliucija yra {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimali rezoliucija yra {maxResolution}'\n};\n"
  },
  {
    "path": "locale/lus-lus.js",
    "content": "export default {\n    labelIdle: 'I file hnûklût rawh, emaw <span class=\"filepond--label-action\"> Zawnna </span>',\n    labelInvalidField: 'Hemi hian files diklo a kengtel',\n    labelFileWaitingForSize: 'A lenzawng a nghâk mek',\n    labelFileSizeNotAvailable: 'A lenzawng a awmlo',\n    labelFileLoading: 'Loading',\n    labelFileLoadError: 'Load laiin dik lo a awm',\n    labelFileProcessing: 'Uploading',\n    labelFileProcessingComplete: 'Upload a zo',\n    labelFileProcessingAborted: 'Upload sût a ni',\n    labelFileProcessingError: 'Upload laiin dik lo a awm',\n    labelFileProcessingRevertError: 'Dahkîr laiin dik lo a awm',\n    labelFileRemoveError: 'Paih laiin dik lo a awm',\n    labelTapToCancel: 'Sût turin hmet rawh',\n    labelTapToRetry: 'Tinawn turin hmet rawh',\n    labelTapToUndo: 'Tilet turin hmet rawh',\n    labelButtonRemoveItem: 'Paihna',\n    labelButtonAbortItemLoad: 'Tihtlawlhna',\n    labelButtonRetryItemLoad: 'Tihnawnna',\n    labelButtonAbortItemProcessing: 'Sûtna',\n    labelButtonUndoItemProcessing: 'Tihletna',\n    labelButtonRetryItemProcessing: 'Tihnawnna',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'File a lian lutuk',\n    labelMaxFileSize: 'File lenzawng tam ber chu {filesize} ani',\n    labelMaxTotalFileSizeExceeded: 'A lenzawng belh khâwm tam ber a pêl',\n    labelMaxTotalFileSize: 'File lenzawng belh khâwm tam ber chu {filesize} a ni',\n    labelFileTypeNotAllowed: 'File type dik lo a ni',\n    fileValidateTypeLabelExpectedTypes: '{allButLastType} emaw {lastType} emaw beisei a ni',\n    imageValidateSizeLabelFormatError: 'Thlalâk type a thlâwplo',\n    imageValidateSizeLabelImageSizeTooSmall: 'Thlalâk hi a tê lutuk',\n    imageValidateSizeLabelImageSizeTooBig: 'Thlalâk hi a lian lutuk',\n    imageValidateSizeLabelExpectedMinSize: 'A lenzawng tlêm ber chu {minWidth} x {minHeight} a ni',\n    imageValidateSizeLabelExpectedMaxSize: 'A lenzawng tam ber chu {maxWidth} x {maxHeight} a ni',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolution a hniam lutuk',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolution a sâng lutuk',\n    imageValidateSizeLabelExpectedMinResolution: 'Resolution hniam ber chu {minResolution} a ni',\n    imageValidateSizeLabelExpectedMaxResolution: 'Resolution sâng ber chu {maxResolution} a ni'\n};\n"
  },
  {
    "path": "locale/lv-lv.js",
    "content": "export default {\n    labelIdle: 'Ievelciet savus failus vai <span class=\"filepond--label-action\"> pārlūkojiet šeit </span>',\n    labelInvalidField: 'Lauks satur nederīgus failus',\n    labelFileWaitingForSize: 'Gaidām faila izmēru',\n    labelFileSizeNotAvailable: 'Izmērs nav pieejams',\n    labelFileLoading: 'Notiek ielāde',\n    labelFileLoadError: 'Notika kļūda ielādes laikā',\n    labelFileProcessing: 'Notiek augšupielāde',\n    labelFileProcessingComplete: 'Augšupielāde pabeigta',\n    labelFileProcessingAborted: 'Augšupielāde atcelta',\n    labelFileProcessingError: 'Notika kļūda augšupielādes laikā',\n    labelFileProcessingRevertError: 'Notika kļūda atgriešanas laikā',\n    labelFileRemoveError: 'Notika kļūda dzēšanas laikā',\n    labelTapToCancel: 'pieskarieties, lai atceltu',\n    labelTapToRetry: 'pieskarieties, lai mēģinātu vēlreiz',\n    labelTapToUndo: 'pieskarieties, lai atsauktu',\n    labelButtonRemoveItem: 'Dzēst',\n    labelButtonAbortItemLoad: 'Pārtraukt',\n    labelButtonRetryItemLoad: 'Mēģināt vēlreiz',\n    labelButtonAbortItemProcessing: 'Pārtraucam',\n    labelButtonUndoItemProcessing: 'Atsaucam',\n    labelButtonRetryItemProcessing: 'Mēģinām vēlreiz',\n    labelButtonProcessItem: 'Augšupielādēt',\n    labelMaxFileSizeExceeded: 'Fails ir pārāk liels',\n    labelMaxFileSize: 'Maksimālais faila izmērs ir {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Pārsniegts maksimālais kopējais failu izmērs',\n    labelMaxTotalFileSize: 'Maksimālais kopējais failu izmērs ir {filesize}',\n    labelFileTypeNotAllowed: 'Nederīgs faila tips',\n    fileValidateTypeLabelExpectedTypes: 'Sagaidām {allButLastType} vai {lastType}',\n    imageValidateSizeLabelFormatError: 'Neatbilstošs attēla tips',\n    imageValidateSizeLabelImageSizeTooSmall: 'Attēls ir pārāk mazs',\n    imageValidateSizeLabelImageSizeTooBig: 'Attēls ir pārāk liels',\n    imageValidateSizeLabelExpectedMinSize: 'Minimālais izmērs ir {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimālais izmērs ir {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Izšķirtspēja ir pārāk zema',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Izšķirtspēja ir pārāk augsta',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimālā izšķirtspēja ir {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimālā izšķirtspēja ir {maxResolution}'\n};\n"
  },
  {
    "path": "locale/nl-nl.js",
    "content": "export default {\n    labelIdle: 'Drag & Drop je bestanden of <span class=\"filepond--label-action\"> Bladeren </span>',\n    labelInvalidField: 'Veld bevat ongeldige bestanden',\n    labelFileWaitingForSize: 'Wachten op grootte',\n    labelFileSizeNotAvailable: 'Grootte niet beschikbaar',\n    labelFileLoading: 'Laden',\n    labelFileLoadError: 'Fout tijdens laden',\n    labelFileProcessing: 'Uploaden',\n    labelFileProcessingComplete: 'Upload afgerond',\n    labelFileProcessingAborted: 'Upload geannuleerd',\n    labelFileProcessingError: 'Fout tijdens upload',\n    labelFileProcessingRevertError: 'Fout bij herstellen',\n    labelFileRemoveError: 'Fout bij verwijderen',\n    labelTapToCancel: 'tik om te annuleren',\n    labelTapToRetry: 'tik om opnieuw te proberen',\n    labelTapToUndo: 'tik om ongedaan te maken',\n    labelButtonRemoveItem: 'Verwijderen',\n    labelButtonAbortItemLoad: 'Afbreken',\n    labelButtonRetryItemLoad: 'Opnieuw proberen',\n    labelButtonAbortItemProcessing: 'Annuleren',\n    labelButtonUndoItemProcessing: 'Ongedaan maken',\n    labelButtonRetryItemProcessing: 'Opnieuw proberen',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'Bestand is te groot',\n    labelMaxFileSize: 'Maximale bestandsgrootte is {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maximale totale grootte overschreden',\n    labelMaxTotalFileSize: 'Maximale totale bestandsgrootte is {filesize}',\n    labelFileTypeNotAllowed: 'Ongeldig bestandstype',\n    fileValidateTypeLabelExpectedTypes: 'Verwacht {allButLastType} of {lastType}',\n    imageValidateSizeLabelFormatError: 'Afbeeldingstype niet ondersteund',\n    imageValidateSizeLabelImageSizeTooSmall: 'Afbeelding is te klein',\n    imageValidateSizeLabelImageSizeTooBig: 'Afbeelding is te groot',\n    imageValidateSizeLabelExpectedMinSize: 'Minimale afmeting is {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximale afmeting is {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolutie is te laag',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolution is too high',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimale resolutie is {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximale resolutie is {maxResolution}'\n};\n"
  },
  {
    "path": "locale/no_nb.js",
    "content": "export default {\n    labelIdle: 'Dra og slipp filene dine, eller <span class=\"filepond--label-action\"> Bla gjennom... </span>',\n    labelInvalidField: 'Feltet inneholder ugyldige filer',\n    labelFileWaitingForSize: 'Venter på størrelse',\n    labelFileSizeNotAvailable: 'Størrelse ikke tilgjengelig',\n    labelFileLoading: 'Laster',\n    labelFileLoadError: 'Feil under lasting',\n    labelFileProcessing: 'Laster opp',\n    labelFileProcessingComplete: 'Opplasting ferdig',\n    labelFileProcessingAborted: 'Opplasting avbrutt',\n    labelFileProcessingError: 'Feil under opplasting',\n    labelFileProcessingRevertError: 'Feil under reversering',\n    labelFileRemoveError: 'Feil under flytting',\n    labelTapToCancel: 'klikk for å avbryte',\n    labelTapToRetry: 'klikk for å prøve på nytt',\n    labelTapToUndo: 'klikk for å angre',\n    labelButtonRemoveItem: 'Fjern',\n    labelButtonAbortItemLoad: 'Avbryt',\n    labelButtonRetryItemLoad: 'Prøv på nytt',\n    labelButtonAbortItemProcessing: 'Avbryt',\n    labelButtonUndoItemProcessing: 'Angre',\n    labelButtonRetryItemProcessing: 'Prøv på nytt',\n    labelButtonProcessItem: 'Last opp',\n    labelMaxFileSizeExceeded: 'Filen er for stor',\n    labelMaxFileSize: 'Maksimal filstørrelse er {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maksimal total størrelse oversteget',\n    labelMaxTotalFileSize: 'Maksimal total størrelse er {filesize}',\n    labelFileTypeNotAllowed: 'Ugyldig filtype',\n    fileValidateTypeLabelExpectedTypes: 'Forventer {allButLastType} eller {lastType}',\n    imageValidateSizeLabelFormatError: 'Bildeformat ikke støttet',\n    imageValidateSizeLabelImageSizeTooSmall: 'Bildet er for lite',\n    imageValidateSizeLabelImageSizeTooBig: 'Bildet er for stort',\n    imageValidateSizeLabelExpectedMinSize: 'Minimumsstørrelse er {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksimumsstørrelse er {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Oppløsningen er for lav',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Oppløsningen er for høy',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimum oppløsning er {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksimal oppløsning er {maxResolution}'\n};\n"
  },
  {
    "path": "locale/pl-pl.js",
    "content": "export default {\n    labelIdle: 'Przeciągnij i upuść lub <span class=\"filepond--label-action\">wybierz</span> pliki',\n    labelInvalidField: 'Nieprawidłowe pliki',\n    labelFileWaitingForSize: 'Pobieranie rozmiaru',\n    labelFileSizeNotAvailable: 'Nieznany rozmiar',\n    labelFileLoading: 'Wczytywanie',\n    labelFileLoadError: 'Błąd wczytywania',\n    labelFileProcessing: 'Przesyłanie',\n    labelFileProcessingComplete: 'Przesłano',\n    labelFileProcessingAborted: 'Przerwano',\n    labelFileProcessingError: 'Przesyłanie nie powiodło się',\n    labelFileProcessingRevertError: 'Coś poszło nie tak',\n    labelFileRemoveError: 'Nieudane usunięcie',\n    labelTapToCancel: 'Anuluj',\n    labelTapToRetry: 'Ponów',\n    labelTapToUndo: 'Cofnij',\n    labelButtonRemoveItem: 'Usuń',\n    labelButtonAbortItemLoad: 'Przerwij',\n    labelButtonRetryItemLoad: 'Ponów',\n    labelButtonAbortItemProcessing: 'Anuluj',\n    labelButtonUndoItemProcessing: 'Cofnij',\n    labelButtonRetryItemProcessing: 'Ponów',\n    labelButtonProcessItem: 'Prześlij',\n    labelMaxFileSizeExceeded: 'Plik jest zbyt duży',\n    labelMaxFileSize: 'Dopuszczalna wielkość pliku to {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Przekroczono łączny rozmiar plików',\n    labelMaxTotalFileSize: 'Łączny rozmiar plików nie może przekroczyć {filesize}',\n    labelFileTypeNotAllowed: 'Niedozwolony rodzaj pliku',\n    fileValidateTypeLabelExpectedTypes: 'Oczekiwano {allButLastType} lub {lastType}',\n    imageValidateSizeLabelFormatError: 'Nieobsługiwany format obrazu',\n    imageValidateSizeLabelImageSizeTooSmall: 'Obraz jest zbyt mały',\n    imageValidateSizeLabelImageSizeTooBig: 'Obraz jest zbyt duży',\n    imageValidateSizeLabelExpectedMinSize: 'Minimalne wymiary obrazu to {minWidth}×{minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maksymalna wymiary obrazu to {maxWidth}×{maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rozdzielczość jest zbyt niska',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rozdzielczość jest zbyt wysoka',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimalna rozdzielczość to {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maksymalna rozdzielczość to {maxResolution}'\n};\n"
  },
  {
    "path": "locale/pt-br.js",
    "content": "export default {\n    labelIdle: 'Arraste e solte os arquivos ou <span class=\"filepond--label-action\"> Clique aqui </span>',\n    labelInvalidField: 'Arquivos inválidos',\n    labelFileWaitingForSize: 'Calculando o tamanho do arquivo',\n    labelFileSizeNotAvailable: 'Tamanho do arquivo indisponível',\n    labelFileLoading: 'Carregando',\n    labelFileLoadError: 'Erro durante o carregamento',\n    labelFileProcessing: 'Enviando',\n    labelFileProcessingComplete: 'Envio finalizado',\n    labelFileProcessingAborted: 'Envio cancelado',\n    labelFileProcessingError: 'Erro durante o envio',\n    labelFileProcessingRevertError: 'Erro ao reverter o envio',\n    labelFileRemoveError: 'Erro ao remover o arquivo',\n    labelTapToCancel: 'clique para cancelar',\n    labelTapToRetry: 'clique para reenviar',\n    labelTapToUndo: 'clique para desfazer',\n    labelButtonRemoveItem: 'Remover',\n    labelButtonAbortItemLoad: 'Abortar',\n    labelButtonRetryItemLoad: 'Reenviar',\n    labelButtonAbortItemProcessing: 'Cancelar',\n    labelButtonUndoItemProcessing: 'Desfazer',\n    labelButtonRetryItemProcessing: 'Reenviar',\n    labelButtonProcessItem: 'Enviar',\n    labelMaxFileSizeExceeded: 'Arquivo é muito grande',\n    labelMaxFileSize: 'O tamanho máximo permitido: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Tamanho total dos arquivos excedido',\n    labelMaxTotalFileSize: 'Tamanho total permitido: {filesize}',\n    labelFileTypeNotAllowed: 'Tipo de arquivo inválido',\n    fileValidateTypeLabelExpectedTypes: 'Tipos de arquivo suportados são {allButLastType} ou {lastType}',\n    imageValidateSizeLabelFormatError: 'Tipo de imagem inválida',\n    imageValidateSizeLabelImageSizeTooSmall: 'Imagem muito pequena',\n    imageValidateSizeLabelImageSizeTooBig: 'Imagem muito grande',\n    imageValidateSizeLabelExpectedMinSize: 'Tamanho mínimo permitida: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Tamanho máximo permitido: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Resolução muito baixa',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Resolução muito alta',\n    imageValidateSizeLabelExpectedMinResolution: 'Resolução mínima permitida: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Resolução máxima permitida: {maxResolution}',\n};\n"
  },
  {
    "path": "locale/pt-pt.js",
    "content": "export default {\n    labelIdle: 'Arraste & Largue os ficheiros ou <span class=\"filepond--label-action\"> Seleccione </span>',\n    labelInvalidField: 'O campo contém ficheiros inválidos',\n    labelFileWaitingForSize: 'A aguardar tamanho',\n    labelFileSizeNotAvailable: 'Tamanho não disponível',\n    labelFileLoading: 'A carregar',\n    labelFileLoadError: 'Erro ao carregar',\n    labelFileProcessing: 'A carregar',\n    labelFileProcessingComplete: 'Carregamento completo',\n    labelFileProcessingAborted: 'Carregamento cancelado',\n    labelFileProcessingError: 'Erro ao carregar',\n    labelFileProcessingRevertError: 'Erro ao reverter',\n    labelFileRemoveError: 'Erro ao remover',\n    labelTapToCancel: 'carregue para cancelar',\n    labelTapToRetry: 'carregue para tentar novamente',\n    labelTapToUndo: 'carregue para desfazer',\n    labelButtonRemoveItem: 'Remover',\n    labelButtonAbortItemLoad: 'Abortar',\n    labelButtonRetryItemLoad: 'Tentar novamente',\n    labelButtonAbortItemProcessing: 'Cancelar',\n    labelButtonUndoItemProcessing: 'Desfazer',\n    labelButtonRetryItemProcessing: 'Tentar novamente',\n    labelButtonProcessItem: 'Carregar',\n    labelMaxFileSizeExceeded: 'Ficheiro demasiado grande',\n    labelMaxFileSize: 'O tamanho máximo do ficheiro é de {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Tamanho máximo total excedido',\n    labelMaxTotalFileSize: 'O tamanho máximo total do ficheiro é de {filesize}',\n    labelFileTypeNotAllowed: 'Tipo de ficheiro inválido',\n    fileValidateTypeLabelExpectedTypes: 'É esperado {allButLastType} ou {lastType}',\n    imageValidateSizeLabelFormatError: 'Tipo de imagem não suportada',\n    imageValidateSizeLabelImageSizeTooSmall: 'A imagem é demasiado pequena',\n    imageValidateSizeLabelImageSizeTooBig: 'A imagem é demasiado grande',\n    imageValidateSizeLabelExpectedMinSize: 'O tamanho mínimo é de {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'O tamanho máximo é de {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'A resolução é demasiado baixa',\n    imageValidateSizeLabelImageResolutionTooHigh: 'A resolução é demasiado grande',\n    imageValidateSizeLabelExpectedMinResolution: 'A resolução mínima é de {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'A resolução máxima é de {maxResolution}'\n};\n"
  },
  {
    "path": "locale/ro-ro.js",
    "content": "export default {\n    labelIdle: 'Trage și plasează fișiere sau <span class=\"filepond--label-action\"> Caută-le </span>',\n    labelInvalidField: 'Câmpul conține fișiere care nu sunt valide',\n    labelFileWaitingForSize: 'În așteptarea dimensiunii',\n    labelFileSizeNotAvailable: 'Dimensiunea nu este diponibilă',\n    labelFileLoading: 'Se încarcă',\n    labelFileLoadError: 'Eroare la încărcare',\n    labelFileProcessing: 'Se încarcă',\n    labelFileProcessingComplete: 'Încărcare finalizată',\n    labelFileProcessingAborted: 'Încărcare anulată',\n    labelFileProcessingError: 'Eroare la încărcare',\n    labelFileProcessingRevertError: 'Eroare la anulare',\n    labelFileRemoveError: 'Eroare la ştergere',\n    labelTapToCancel: 'apasă pentru a anula',\n    labelTapToRetry: 'apasă pentru a reîncerca',\n    labelTapToUndo: 'apasă pentru a anula',\n    labelButtonRemoveItem: 'Şterge',\n    labelButtonAbortItemLoad: 'Anulează',\n    labelButtonRetryItemLoad: 'Reîncearcă',\n    labelButtonAbortItemProcessing: 'Anulează',\n    labelButtonUndoItemProcessing: 'Anulează',\n    labelButtonRetryItemProcessing: 'Reîncearcă',\n    labelButtonProcessItem: 'Încarcă',\n    labelMaxFileSizeExceeded: 'Fișierul este prea mare',\n    labelMaxFileSize: 'Dimensiunea maximă a unui fișier este de {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Dimensiunea totală maximă a fost depășită',\n    labelMaxTotalFileSize: 'Dimensiunea totală maximă a fișierelor este de {filesize}',\n    labelFileTypeNotAllowed: 'Tipul fișierului nu este valid',\n    fileValidateTypeLabelExpectedTypes: 'Se așteaptă {allButLastType} sau {lastType}',\n    imageValidateSizeLabelFormatError: 'Formatul imaginii nu este acceptat',\n    imageValidateSizeLabelImageSizeTooSmall: 'Imaginea este prea mică',\n    imageValidateSizeLabelImageSizeTooBig: 'Imaginea este prea mare',\n    imageValidateSizeLabelExpectedMinSize: 'Mărimea minimă este de {maxWidth} x {maxHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Mărimea maximă este de {maxWidth} x {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rezoluția este prea mică',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rezoluția este prea mare',\n    imageValidateSizeLabelExpectedMinResolution: 'Rezoluția minimă este de {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Rezoluția maximă este de {maxResolution}'\n};\n"
  },
  {
    "path": "locale/ru-ru.js",
    "content": "export default {\n    labelIdle: 'Перетащите файлы или <span class=\"filepond--label-action\"> выберите </span>',\n    labelInvalidField: 'Поле содержит недопустимые файлы',\n    labelFileWaitingForSize: 'Укажите размер',\n    labelFileSizeNotAvailable: 'Размер не поддерживается',\n    labelFileLoading: 'Ожидание',\n    labelFileLoadError: 'Ошибка при ожидании',\n    labelFileProcessing: 'Загрузка',\n    labelFileProcessingComplete: 'Загрузка завершена',\n    labelFileProcessingAborted: 'Загрузка отменена',\n    labelFileProcessingError: 'Ошибка при загрузке',\n    labelFileProcessingRevertError: 'Ошибка при возврате',\n    labelFileRemoveError: 'Ошибка при удалении',\n    labelTapToCancel: 'нажмите для отмены',\n    labelTapToRetry: 'нажмите, чтобы повторить попытку',\n    labelTapToUndo: 'нажмите для отмены последнего действия',\n    labelButtonRemoveItem: 'Удалить',\n    labelButtonAbortItemLoad: 'Прекращено',\n    labelButtonRetryItemLoad: 'Повторите попытку',\n    labelButtonAbortItemProcessing: 'Отмена',\n    labelButtonUndoItemProcessing: 'Отмена последнего действия',\n    labelButtonRetryItemProcessing: 'Повторите попытку',\n    labelButtonProcessItem: 'Загрузка',\n    labelMaxFileSizeExceeded: 'Файл слишком большой',\n    labelMaxFileSize: 'Максимальный размер файла: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Превышен максимальный размер',\n    labelMaxTotalFileSize: 'Максимальный размер файла: {filesize}',\n    labelFileTypeNotAllowed: 'Файл неверного типа',\n    fileValidateTypeLabelExpectedTypes: 'Ожидается {allButLastType} или {lastType}',    \n    imageValidateSizeLabelFormatError: 'Тип изображения не поддерживается',\n    imageValidateSizeLabelImageSizeTooSmall: 'Изображение слишком маленькое',\n    imageValidateSizeLabelImageSizeTooBig: 'Изображение слишком большое',\n    imageValidateSizeLabelExpectedMinSize: 'Минимальный размер: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Максимальный размер: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Разрешение слишком низкое',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Разрешение слишком высокое',\n    imageValidateSizeLabelExpectedMinResolution: 'Минимальное разрешение: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Максимальное разрешение: {maxResolution}'\n};\n"
  },
  {
    "path": "locale/sk-sk.js",
    "content": "export default {\n    labelIdle: 'Natiahnúť súbor (drag&drop) alebo <span class=\"filepond--label-action\"> Vyhľadať </span>',\n    labelInvalidField: 'Pole obsahuje chybné súbory',\n    labelFileWaitingForSize: 'Zisťuje sa veľkosť',\n    labelFileSizeNotAvailable: 'Neznáma veľkosť',\n    labelFileLoading: 'Prenáša sa',\n    labelFileLoadError: 'Chyba pri prenose',\n    labelFileProcessing: 'Prebieha upload',\n    labelFileProcessingComplete: 'Upload dokončený',\n    labelFileProcessingAborted: 'Upload stornovaný',\n    labelFileProcessingError: 'Chyba pri uploade',\n    labelFileProcessingRevertError: 'Chyba pri obnove',\n    labelFileRemoveError: 'Chyba pri odstránení',\n    labelTapToCancel: 'Kliknite pre storno',\n    labelTapToRetry: 'Kliknite pre opakovanie',\n    labelTapToUndo: 'Kliknite pre vrátenie',\n    labelButtonRemoveItem: 'Odstrániť',\n    labelButtonAbortItemLoad: 'Storno',\n    labelButtonRetryItemLoad: 'Opakovať',\n    labelButtonAbortItemProcessing: 'Späť',\n    labelButtonUndoItemProcessing: 'Vrátiť',\n    labelButtonRetryItemProcessing: 'Opakovať',\n    labelButtonProcessItem: 'Upload',\n    labelMaxFileSizeExceeded: 'Súbor je príliš veľký',\n    labelMaxFileSize: 'Najväčšia veľkosť súboru je {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Prekročená maximálna celková veľkosť súboru',\n    labelMaxTotalFileSize: 'Maximálna celková veľkosť súboru je {filesize}',\n    labelFileTypeNotAllowed: 'Súbor je nesprávneho typu',\n    fileValidateTypeLabelExpectedTypes: 'Očakáva sa {allButLastType} alebo {lastType}',\n    imageValidateSizeLabelFormatError: 'Obrázok tohto typu nie je podporovaný',\n    imageValidateSizeLabelImageSizeTooSmall: 'Obrázok je príliš malý',\n    imageValidateSizeLabelImageSizeTooBig: 'Obrázok je príliš veľký',\n    imageValidateSizeLabelExpectedMinSize: 'Minimálny rozmer je {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximálny rozmer je {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Rozlíšenie je príliš malé',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Rozlišenie je príliš veľké',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimálne rozlíšenie je {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximálne rozlíšenie je {maxResolution}'\n};\n"
  },
  {
    "path": "locale/sl-si.js",
    "content": "export default {\n    labelIdle: 'Povleci in spusti ali <span class=\"filepond--label-action\">izberi</span>',\n    labelInvalidField: 'Polje vsebuje neveljavne datoteke',\n    labelFileWaitingForSize: 'Čakanje na velikost',\n    labelFileSizeNotAvailable: 'Velikost ni na voljo',\n    labelFileLoading: 'Nalaganje',\n    labelFileLoadError: 'Napaka pri nalaganju',\n    labelFileProcessing: 'Prenašanje',\n    labelFileProcessingComplete: 'Prenos zaključen',\n    labelFileProcessingAborted: 'Prenos preklican',\n    labelFileProcessingError: 'Napaka pri prenosu',\n    labelFileProcessingRevertError: 'Napaka pri razveljavitvi',\n    labelFileRemoveError: 'Napaka pri odstranjevanju',\n    labelTapToCancel: 'kliknite za preklic',\n    labelTapToRetry: 'kliknite za ponovni poskus',\n    labelTapToUndo: 'kliknite za razveljavitev',\n    labelButtonRemoveItem: 'Odstrani',\n    labelButtonAbortItemLoad: 'Prekini',\n    labelButtonRetryItemLoad: 'Poskusi znova',\n    labelButtonAbortItemProcessing: 'Prekliči',\n    labelButtonUndoItemProcessing: 'Razveljavi',\n    labelButtonRetryItemProcessing: 'Poskusi znova',\n    labelButtonProcessItem: 'Prenesi',\n    labelMaxFileSizeExceeded: 'Datoteka je prevelika',\n    labelMaxFileSize: 'Največja velikost datoteke je {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Presežena je največja skupna velikost',\n    labelMaxTotalFileSize: 'Največja skupna velikost datotek je {filesize}',\n    labelFileTypeNotAllowed: 'Neveljavna vrsta datoteke',\n    fileValidateTypeLabelExpectedTypes: 'Pričakuje se: {allButLastType} ali {lastType}',\n    imageValidateSizeLabelFormatError: 'Vrsta slike ni podprta',\n    imageValidateSizeLabelImageSizeTooSmall: 'Slika je premajhna',\n    imageValidateSizeLabelImageSizeTooBig: 'Slika je prevelika',\n    imageValidateSizeLabelExpectedMinSize: 'Najmanjša velikost je {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Največja velikost je {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Ločljivost je prenizka',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Ločljivost je previsoka',\n    imageValidateSizeLabelExpectedMinResolution: 'Najmanjša ločljivost je {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Največja ločljivost je {maxResolution}'\n};\n"
  },
  {
    "path": "locale/sr-rs.js",
    "content": "export default {\n    labelIdle: 'Овде \"испустите\" датотеку или <span class=\"filepond--label-action\"> Претражи </span>',\n    labelInvalidField: 'Поље садржи неисправне датотеке',\n    labelFileWaitingForSize: 'Чекање на величину датотеке',\n    labelFileSizeNotAvailable: 'Величина датотеке није доступна',\n    labelFileLoading: 'Учитавање',\n    labelFileLoadError: 'Грешка приликом учитавања',\n    labelFileProcessing: 'Пренос',\n    labelFileProcessingComplete: 'Пренос завршен',\n    labelFileProcessingAborted: 'Пренос отказан',\n    labelFileProcessingError: 'Грешка приликом преноса',\n    labelFileProcessingRevertError: 'Грешка приликом враћања',\n    labelFileRemoveError: 'Грешка приликом уклањања датотеке',\n    labelTapToCancel: 'Додирни за прекид',\n    labelTapToRetry: 'Додирни за поновно',\n    labelTapToUndo: 'Додирни за враћање',\n    labelButtonRemoveItem: 'Уклони',\n    labelButtonAbortItemLoad: 'Одбаци',\n    labelButtonRetryItemLoad: 'Понови',\n    labelButtonAbortItemProcessing: 'Прекини',\n    labelButtonUndoItemProcessing: 'Врати',\n    labelButtonRetryItemProcessing: 'Понови',\n    labelButtonProcessItem: 'Пренос',\n    labelMaxFileSizeExceeded: 'Датотека је превелика',\n    labelMaxFileSize: 'Максимална величина датотеке је {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Максимална укупна величина датотеке је прекорачена',\n    labelMaxTotalFileSize: 'Максимална укупна величина датотеке је {filesize}',\n    labelFileTypeNotAllowed: 'Тип датотеке није подржан',\n    fileValidateTypeLabelExpectedTypes: 'Очекиван {allButLastType} или {lastType}',\n    imageValidateSizeLabelFormatError: 'Тип слике није подржан',\n    imageValidateSizeLabelImageSizeTooSmall: 'Слика је премала',\n    imageValidateSizeLabelImageSizeTooBig: 'Слика је превелика',\n    imageValidateSizeLabelExpectedMinSize: 'Минимална величина је {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Максимална величина је {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Резолуција је прениса',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Резолуција је превисока',\n    imageValidateSizeLabelExpectedMinResolution: 'Минимална резолуција је {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Максимална резолуција је {maxResolution}'\n};\n"
  },
  {
    "path": "locale/sv_se.js",
    "content": "export default {\n    labelIdle: 'Drag och släpp dina filer eller <span class=\"filepond--label-action\"> Bläddra </span>',\n    labelInvalidField: 'Fältet innehåller felaktiga filer',\n    labelFileWaitingForSize: 'Väntar på storlek',\n    labelFileSizeNotAvailable: 'Storleken finns inte tillgänglig',\n    labelFileLoading: 'Laddar',\n    labelFileLoadError: 'Fel under laddning',\n    labelFileProcessing: 'Laddar upp',\n    labelFileProcessingComplete: 'Uppladdning klar',\n    labelFileProcessingAborted: 'Uppladdning avbruten',\n    labelFileProcessingError: 'Fel under uppladdning',\n    labelFileProcessingRevertError: 'Fel under återställning',\n    labelFileRemoveError: 'Fel under borttagning',\n    labelTapToCancel: 'tryck för att avbryta',\n    labelTapToRetry: 'tryck för att försöka igen',\n    labelTapToUndo: 'tryck för att ångra',\n    labelButtonRemoveItem: 'Tabort',\n    labelButtonAbortItemLoad: 'Avbryt',\n    labelButtonRetryItemLoad: 'Försök igen',\n    labelButtonAbortItemProcessing: 'Avbryt',\n    labelButtonUndoItemProcessing: 'Ångra',\n    labelButtonRetryItemProcessing: 'Försök igen',\n    labelButtonProcessItem: 'Ladda upp',\n    labelMaxFileSizeExceeded: 'Filen är för stor',\n    labelMaxFileSize: 'Största tillåtna filstorlek är {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maximal uppladdningsstorlek uppnåd',\n    labelMaxTotalFileSize: 'Maximal uppladdningsstorlek är {filesize}',\n    labelFileTypeNotAllowed: 'Felaktig filtyp',\n    fileValidateTypeLabelExpectedTypes: 'Godkända filtyper {allButLastType} eller {lastType}',\n    imageValidateSizeLabelFormatError: 'Bildtypen saknar stöd',\n    imageValidateSizeLabelImageSizeTooSmall: 'Bilden är för liten',\n    imageValidateSizeLabelImageSizeTooBig: 'Bilden är för stor',\n    imageValidateSizeLabelExpectedMinSize: 'Minimal storlek är {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximal storlek är {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Upplösningen är för låg',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Upplösningen är för hög',\n    imageValidateSizeLabelExpectedMinResolution: 'Minsta tillåtna upplösning är {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Högsta tillåtna upplösning är {maxResolution}'\n};\n"
  },
  {
    "path": "locale/tr-tr.js",
    "content": "export default {\n    labelIdle: 'Dosyanızı Sürükleyin & Bırakın ya da <span class=\"filepond--label-action\"> Seçin </span>',\n    labelInvalidField: 'Alan geçersiz dosyalar içeriyor',\n    labelFileWaitingForSize: 'Boyut hesaplanıyor',\n    labelFileSizeNotAvailable: 'Boyut mevcut değil',\n    labelFileLoading: 'Yükleniyor',\n    labelFileLoadError: 'Yükleme sırasında hata oluştu',\n    labelFileProcessing: 'Yükleniyor',\n    labelFileProcessingComplete: 'Yükleme tamamlandı',\n    labelFileProcessingAborted: 'Yükleme iptal edildi',\n    labelFileProcessingError: 'Yüklerken hata oluştu',\n    labelFileProcessingRevertError: 'Geri çekerken hata oluştu',\n    labelFileRemoveError: 'Kaldırırken hata oluştu',\n    labelTapToCancel: 'İptal etmek için tıklayın',\n    labelTapToRetry: 'Tekrar denemek için tıklayın',\n    labelTapToUndo: 'Geri almak için tıklayın',\n    labelButtonRemoveItem: 'Kaldır',\n    labelButtonAbortItemLoad: 'İptal Et',\n    labelButtonRetryItemLoad: 'Tekrar dene',\n    labelButtonAbortItemProcessing: 'İptal et',\n    labelButtonUndoItemProcessing: 'Geri Al',\n    labelButtonRetryItemProcessing: 'Tekrar dene',\n    labelButtonProcessItem: 'Yükle',\n    labelMaxFileSizeExceeded: 'Dosya çok büyük',\n    labelMaxFileSize: 'En fazla dosya boyutu: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Maximum boyut aşıldı',\n    labelMaxTotalFileSize: 'Maximum dosya boyutu :{filesize}',\n    labelFileTypeNotAllowed: 'Geçersiz dosya tipi',\n    fileValidateTypeLabelExpectedTypes: 'Şu {allButLastType} ya da şu dosya olması gerekir: {lastType}',\n    imageValidateSizeLabelFormatError: 'Resim tipi desteklenmiyor',\n    imageValidateSizeLabelImageSizeTooSmall: 'Resim çok küçük',\n    imageValidateSizeLabelImageSizeTooBig: 'Resim çok büyük',\n    imageValidateSizeLabelExpectedMinSize: 'Minimum boyut {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Maximum boyut {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Çözünürlük çok düşük',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Çözünürlük çok yüksek',\n    imageValidateSizeLabelExpectedMinResolution: 'Minimum çözünürlük {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Maximum çözünürlük {maxResolution}'\n};\n"
  },
  {
    "path": "locale/uk-ua.js",
    "content": "export default {\n    labelIdle: 'Перетягніть файли або <span class=\"filepond--label-action\"> виберіть </span>',\n    labelInvalidField: 'Поле містить недопустимі файли',\n    labelFileWaitingForSize: 'Вкажіть розмір',\n    labelFileSizeNotAvailable: 'Розмір не доступний',\n    labelFileLoading: 'Очікування',\n    labelFileLoadError: 'Помилка при очікуванні',\n    labelFileProcessing: 'Завантаження',\n    labelFileProcessingComplete: 'Завантаження завершено',\n    labelFileProcessingAborted: 'Завантаження скасовано',\n    labelFileProcessingError: 'Помилка при завантаженні',\n    labelFileProcessingRevertError: 'Помилка при відновленні',\n    labelFileRemoveError: 'Помилка при видаленні',\n    labelTapToCancel: 'Відмінити',\n    labelTapToRetry: 'Натисніть, щоб повторити спробу',\n    labelTapToUndo: 'Натисніть, щоб відмінити останню дію',\n    labelButtonRemoveItem: 'Видалити',\n    labelButtonAbortItemLoad: 'Відмінити',\n    labelButtonRetryItemLoad: 'Повторити спробу',\n    labelButtonAbortItemProcessing: 'Відмінити',\n    labelButtonUndoItemProcessing: 'Відмінити останню дію',\n    labelButtonRetryItemProcessing: 'Повторити спробу',\n    labelButtonProcessItem: 'Завантаження',\n    labelMaxFileSizeExceeded: 'Файл занадто великий',\n    labelMaxFileSize: 'Максимальний розмір файлу: {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Перевищено максимальний загальний розмір',\n    labelMaxTotalFileSize: 'Максимальний загальний розмір: {filesize}',\n    labelFileTypeNotAllowed: 'Формат файлу не підтримується',\n    fileValidateTypeLabelExpectedTypes: 'Очікується {allButLastType} або {lastType}',\n    imageValidateSizeLabelFormatError: 'Формат зображення не підтримується',\n    imageValidateSizeLabelImageSizeTooSmall: 'Зображення занадто маленьке',\n    imageValidateSizeLabelImageSizeTooBig: 'Зображення занадто велике',\n    imageValidateSizeLabelExpectedMinSize: 'Мінімальний розмір: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Максимальний розмір: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Розміри зображення занадто маленькі',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Розміри зображення занадто великі',\n    imageValidateSizeLabelExpectedMinResolution: 'Мінімальні розміри: {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Максимальні розміри: {maxResolution}'\n};\n"
  },
  {
    "path": "locale/ur-ur.js",
    "content": "export default {\n    labelIdle: 'اپنی فائلز ڈریگ کریں یا <span class=\"filepond--label-action\"> براؤز کریں </span>',\n    labelInvalidField: 'فیلڈ میں غلط فائلز ہیں',\n    labelFileWaitingForSize: 'سائز کا انتظار ہو رہا ہے',\n    labelFileSizeNotAvailable: 'سائز دستیاب نہیں',\n    labelFileLoading: 'لوڈ ہو رہی ہے',\n    labelFileLoadError: 'لوڈنگ میں خرابی',\n    labelFileProcessing: 'اپلوڈ ہو رہی ہے',\n    labelFileProcessingComplete: 'اپلوڈ مکمل ہو گئی',\n    labelFileProcessingAborted: 'اپلوڈ منسوخ کر دی گئی',\n    labelFileProcessingError: 'اپلوڈ میں خرابی',\n    labelFileProcessingRevertError: 'ریورٹ کرنے میں خرابی',\n    labelFileRemoveError: 'فائل ہٹانے میں خرابی',\n    labelTapToCancel: 'منسوخ کرنے کے لیے ٹیپ کریں',\n    labelTapToRetry: 'دوبارہ کوشش کے لیے ٹیپ کریں',\n    labelTapToUndo: 'واپس کرنے کے لیے ٹیپ کریں',\n    labelButtonRemoveItem: 'ہٹائیں',\n    labelButtonAbortItemLoad: 'روکیں',\n    labelButtonRetryItemLoad: 'دوبارہ کوشش کریں',\n    labelButtonAbortItemProcessing: 'منسوخ کریں',\n    labelButtonUndoItemProcessing: 'واپس کریں',\n    labelButtonRetryItemProcessing: 'دوبارہ کوشش کریں',\n    labelButtonProcessItem: 'اپلوڈ کریں',\n    labelMaxFileSizeExceeded: 'فائل بہت بڑی ہے',\n    labelMaxFileSize: 'زیادہ سے زیادہ فائل سائز {filesize} ہے',\n    labelMaxTotalFileSizeExceeded: 'مجموعی سائز کی حد تجاوز کر گئی ہے',\n    labelMaxTotalFileSize: 'زیادہ سے زیادہ مجموعی فائل سائز {filesize} ہے',\n    labelFileTypeNotAllowed: 'فائل کی قسم غیر درست ہے',\n    fileValidateTypeLabelExpectedTypes: '{allButLastType} یا {lastType} متوقع ہیں',\n    imageValidateSizeLabelFormatError: 'تصویر کی قسم سپورٹڈ نہیں',\n    imageValidateSizeLabelImageSizeTooSmall: 'تصویر بہت چھوٹی ہے',\n    imageValidateSizeLabelImageSizeTooBig: 'تصویر بہت بڑی ہے',\n    imageValidateSizeLabelExpectedMinSize: 'کم از کم سائز {minWidth} × {minHeight} ہے',\n    imageValidateSizeLabelExpectedMaxSize: 'زیادہ سے زیادہ سائز {maxWidth} × {maxHeight} ہے',\n    imageValidateSizeLabelImageResolutionTooLow: 'ریزولوشن بہت کم ہے',\n    imageValidateSizeLabelImageResolutionTooHigh: 'ریزولوشن بہت زیادہ ہے',\n    imageValidateSizeLabelExpectedMinResolution: 'کم از کم ریزولوشن {minResolution} ہے',\n    imageValidateSizeLabelExpectedMaxResolution: 'زیادہ سے زیادہ ریزولوشن {maxResolution} ہے'\n};\n"
  },
  {
    "path": "locale/vi-vi.js",
    "content": "export default {\n    labelIdle: 'Kéo thả tệp của bạn hoặc <span class=\"filepond--label-action\"> Tìm kiếm </span>',\n    labelInvalidField: 'Trường chứa các tệp không hợp lệ',\n    labelFileWaitingForSize: 'Đang chờ kích thước',\n    labelFileSizeNotAvailable: 'Kích thước không có sẵn',\n    labelFileLoading: 'Đang tải',\n    labelFileLoadError: 'Lỗi khi tải',\n    labelFileProcessing: 'Đang tải lên',\n    labelFileProcessingComplete: 'Tải lên thành công',\n    labelFileProcessingAborted: 'Đã huỷ tải lên',\n    labelFileProcessingError: 'Lỗi khi tải lên',\n    labelFileProcessingRevertError: 'Lỗi khi hoàn nguyên',\n    labelFileRemoveError: 'Lỗi khi xóa',\n    labelTapToCancel: 'nhấn để hủy',\n    labelTapToRetry: 'nhấn để thử lại',\n    labelTapToUndo: 'nhấn để hoàn tác',\n    labelButtonRemoveItem: 'Xoá',\n    labelButtonAbortItemLoad: 'Huỷ bỏ',\n    labelButtonRetryItemLoad: 'Thử lại',\n    labelButtonAbortItemProcessing: 'Hủy bỏ',\n    labelButtonUndoItemProcessing: 'Hoàn tác',\n    labelButtonRetryItemProcessing: 'Thử lại',\n    labelButtonProcessItem: 'Tải lên',\n    labelMaxFileSizeExceeded: 'Tập tin quá lớn',\n    labelMaxFileSize: 'Kích thước tệp tối đa là {filesize}',\n    labelMaxTotalFileSizeExceeded: 'Đã vượt quá tổng kích thước tối đa',\n    labelMaxTotalFileSize: 'Tổng kích thước tệp tối đa là {filesize}',\n    labelFileTypeNotAllowed: 'Tệp thuộc loại không hợp lệ',\n    fileValidateTypeLabelExpectedTypes: 'Kiểu tệp hợp lệ là {allButLastType} hoặc {lastType}',\n    imageValidateSizeLabelFormatError: 'Loại hình ảnh không được hỗ trợ',\n    imageValidateSizeLabelImageSizeTooSmall: 'Hình ảnh quá nhỏ',\n    imageValidateSizeLabelImageSizeTooBig: 'Hình ảnh quá lớn',\n    imageValidateSizeLabelExpectedMinSize: 'Kích thước tối thiểu là {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: 'Kích thước tối đa là {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: 'Độ phân giải quá thấp',\n    imageValidateSizeLabelImageResolutionTooHigh: 'Độ phân giải quá cao',\n    imageValidateSizeLabelExpectedMinResolution: 'Độ phân giải tối thiểu là {minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: 'Độ phân giải tối đa là {maxResolution}'\n};\n"
  },
  {
    "path": "locale/zh-cn.js",
    "content": "export default {\n    labelIdle: '拖放文件，或者 <span class=\"filepond--label-action\"> 浏览 </span>',\n    labelInvalidField: '字段包含无效文件',\n    labelFileWaitingForSize: '计算文件大小',\n    labelFileSizeNotAvailable: '文件大小不可用',\n    labelFileLoading: '加载',\n    labelFileLoadError: '加载错误',\n    labelFileProcessing: '上传',\n    labelFileProcessingComplete: '已上传',\n    labelFileProcessingAborted: '上传已取消',\n    labelFileProcessingError: '上传出错',\n    labelFileProcessingRevertError: '还原出错',\n    labelFileRemoveError: '删除出错',\n    labelTapToCancel: '点击取消',\n    labelTapToRetry: '点击重试',\n    labelTapToUndo: '点击撤消',\n    labelButtonRemoveItem: '删除',\n    labelButtonAbortItemLoad: '中止',\n    labelButtonRetryItemLoad: '重试',\n    labelButtonAbortItemProcessing: '取消',\n    labelButtonUndoItemProcessing: '撤消',\n    labelButtonRetryItemProcessing: '重试',\n    labelButtonProcessItem: '上传',\n    labelMaxFileSizeExceeded: '文件太大',\n    labelMaxFileSize: '最大值: {filesize}',\n    labelMaxTotalFileSizeExceeded: '超过最大文件大小',\n    labelMaxTotalFileSize: '最大文件大小：{filesize}',\n    labelFileTypeNotAllowed: '文件类型无效',\n    fileValidateTypeLabelExpectedTypes: '应为 {allButLastType} 或 {lastType}',\n    imageValidateSizeLabelFormatError: '不支持图像类型',\n    imageValidateSizeLabelImageSizeTooSmall: '图像太小',\n    imageValidateSizeLabelImageSizeTooBig: '图像太大',\n    imageValidateSizeLabelExpectedMinSize: '最小值: {minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: '最大值: {maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: '分辨率太低',\n    imageValidateSizeLabelImageResolutionTooHigh: '分辨率太高',\n    imageValidateSizeLabelExpectedMinResolution: '最小分辨率：{minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: '最大分辨率：{maxResolution}'\n  };\n"
  },
  {
    "path": "locale/zh-hk.js",
    "content": "export default {\n    labelIdle: '拖放檔案，或者 <span class=\"filepond--label-action\"> 瀏覽 </span>',\n    labelInvalidField: '不支援此檔案',\n    labelFileWaitingForSize: '正在計算檔案大小',\n    labelFileSizeNotAvailable: '檔案大小不符',\n    labelFileLoading: '讀取中',\n    labelFileLoadError: '讀取錯誤',\n    labelFileProcessing: '上傳',\n    labelFileProcessingComplete: '已上傳',\n    labelFileProcessingAborted: '上傳已取消',\n    labelFileProcessingError: '上傳發生錯誤',\n    labelFileProcessingRevertError: '還原錯誤',\n    labelFileRemoveError: '刪除錯誤',\n    labelTapToCancel: '點擊取消',\n    labelTapToRetry: '點擊重試',\n    labelTapToUndo: '點擊還原',\n    labelButtonRemoveItem: '刪除',\n    labelButtonAbortItemLoad: '停止',\n    labelButtonRetryItemLoad: '重試',\n    labelButtonAbortItemProcessing: '取消',\n    labelButtonUndoItemProcessing: '取消',\n    labelButtonRetryItemProcessing: '重試',\n    labelButtonProcessItem: '上傳',\n    labelMaxFileSizeExceeded: '檔案過大',\n    labelMaxFileSize: '最大值：{filesize}',\n    labelMaxTotalFileSizeExceeded: '超過最大可上傳大小',\n    labelMaxTotalFileSize: '最大可上傳大小：{filesize}',\n    labelFileTypeNotAllowed: '不支援此類型檔案',\n    fileValidateTypeLabelExpectedTypes: '應為 {allButLastType} 或 {lastType}',\n    imageValidateSizeLabelFormatError: '不支持此類圖片類型',\n    imageValidateSizeLabelImageSizeTooSmall: '圖片過小',\n    imageValidateSizeLabelImageSizeTooBig: '圖片過大',\n    imageValidateSizeLabelExpectedMinSize: '最小尺寸：{minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: '最大尺寸：{maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: '解析度過低',\n    imageValidateSizeLabelImageResolutionTooHigh: '解析度過高',\n    imageValidateSizeLabelExpectedMinResolution: '最低解析度：{minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: '最高解析度：{maxResolution}'\n  };\n"
  },
  {
    "path": "locale/zh-tw.js",
    "content": "export default {\n    labelIdle: '拖放檔案，或者 <span class=\"filepond--label-action\"> 瀏覽 </span>',\n    labelInvalidField: '不支援此檔案',\n    labelFileWaitingForSize: '正在計算檔案大小',\n    labelFileSizeNotAvailable: '檔案大小不符',\n    labelFileLoading: '讀取中',\n    labelFileLoadError: '讀取錯誤',\n    labelFileProcessing: '上傳',\n    labelFileProcessingComplete: '已上傳',\n    labelFileProcessingAborted: '上傳已取消',\n    labelFileProcessingError: '上傳發生錯誤',\n    labelFileProcessingRevertError: '還原錯誤',\n    labelFileRemoveError: '刪除錯誤',\n    labelTapToCancel: '點擊取消',\n    labelTapToRetry: '點擊重試',\n    labelTapToUndo: '點擊還原',\n    labelButtonRemoveItem: '刪除',\n    labelButtonAbortItemLoad: '停止',\n    labelButtonRetryItemLoad: '重試',\n    labelButtonAbortItemProcessing: '取消',\n    labelButtonUndoItemProcessing: '取消',\n    labelButtonRetryItemProcessing: '重試',\n    labelButtonProcessItem: '上傳',\n    labelMaxFileSizeExceeded: '檔案過大',\n    labelMaxFileSize: '最大值：{filesize}',\n    labelMaxTotalFileSizeExceeded: '超過最大可上傳大小',\n    labelMaxTotalFileSize: '最大可上傳大小：{filesize}',\n    labelFileTypeNotAllowed: '不支援此類型檔案',\n    fileValidateTypeLabelExpectedTypes: '應為 {allButLastType} 或 {lastType}',\n    imageValidateSizeLabelFormatError: '不支持此類圖片類型',\n    imageValidateSizeLabelImageSizeTooSmall: '圖片過小',\n    imageValidateSizeLabelImageSizeTooBig: '圖片過大',\n    imageValidateSizeLabelExpectedMinSize: '最小尺寸：{minWidth} × {minHeight}',\n    imageValidateSizeLabelExpectedMaxSize: '最大尺寸：{maxWidth} × {maxHeight}',\n    imageValidateSizeLabelImageResolutionTooLow: '解析度過低',\n    imageValidateSizeLabelImageResolutionTooHigh: '解析度過高',\n    imageValidateSizeLabelExpectedMinResolution: '最低解析度：{minResolution}',\n    imageValidateSizeLabelExpectedMaxResolution: '最高解析度：{maxResolution}'\n  };\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"filepond\",\n    \"version\": \"4.32.12\",\n    \"description\": \"FilePond, Where files go to stretch their bits.\",\n    \"license\": \"MIT\",\n    \"author\": {\n        \"name\": \"PQINA\",\n        \"url\": \"https://pqina.nl/\"\n    },\n    \"homepage\": \"https://pqina.nl/filepond/\",\n    \"repository\": \"pqina/filepond\",\n    \"main\": \"dist/filepond.js\",\n    \"browser\": \"dist/filepond.js\",\n    \"module\": \"dist/filepond.esm.js\",\n    \"keywords\": [\n        \"javascript\",\n        \"file\",\n        \"upload\",\n        \"drag\",\n        \"drop\",\n        \"browse\",\n        \"paste\",\n        \"image\",\n        \"preview\"\n    ],\n    \"browserslist\": [\n        \"last 1 version and not Explorer 10\",\n        \"Explorer 11\",\n        \"iOS >= 9\",\n        \"Android >= 4.4\"\n    ],\n    \"files\": [\n        \"dist\",\n        \"locale\",\n        \"types/*.d.ts\"\n    ],\n    \"types\": \"types/index.d.ts\",\n    \"scripts\": {\n        \"test\": \"npx jest\",\n        \"dev\": \"npm run start\",\n        \"start\": \"npx rollup -c -w\",\n        \"build\": \"npm run scripts | npm run styles\",\n        \"scripts\": \"npx rollup -c\",\n        \"styles\": \"npm run styles:pretty && npm run styles:nano\",\n        \"styles:pretty\": \"npx postcss src/css/styles.css --no-map --use precss --use autoprefixer | npx prettier --single-quote --parser css | node banner-cli.js FilePond > dist/filepond.css\",\n        \"styles:nano\": \"npx postcss src/css/styles.css --no-map --use precss --use autoprefixer --use cssnano | node banner-cli.js FilePond > dist/filepond.min.css\",\n        \"dtslint\": \"dtslint types\"\n    },\n    \"devDependencies\": {\n        \"@babel/core\": \"^7.5.5\",\n        \"@babel/plugin-proposal-object-rest-spread\": \"^7.5.5\",\n        \"@babel/plugin-transform-template-literals\": \"^7.4.4\",\n        \"@babel/preset-env\": \"^7.5.5\",\n        \"autoprefixer\": \"^9.6.1\",\n        \"babel-jest\": \"^24.8.0\",\n        \"cssnano\": \"^4.1.10\",\n        \"dtslint\": \"^3.6.12\",\n        \"jest\": \"^24.8.0\",\n        \"jest-mock-console\": \"^1.2.3\",\n        \"postcss-cli\": \"^6.1.3\",\n        \"precss\": \"^4.0.0\",\n        \"prettier\": \"^1.18.2\",\n        \"rollup\": \"^1.17.0\",\n        \"rollup-plugin-babel\": \"^4.3.3\",\n        \"rollup-plugin-commonjs\": \"^9.3.4\",\n        \"rollup-plugin-license\": \"^0.8.1\",\n        \"rollup-plugin-node-resolve\": \"^4.2.4\",\n        \"rollup-plugin-prettier\": \"^0.6.0\",\n        \"rollup-plugin-terser\": \"^4.0.4\",\n        \"typescript\": \"^3.9.6\"\n    }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import * as pkg from './package.json';\nimport build from './rollup.scripts';\n\nexport default build(\n\t{\n\t\tid: 'FilePond',\n\t\t...pkg\n\t},\n\t[\n\t\t{\n\t\t\tformat: 'umd',\n\t\t\ttranspile: true\n\t\t},\n\t\t{\n\t\t\tformat: 'umd',\n\t\t\ttranspile: true,\n\t\t\tminify: true\n\t\t},\n\t\t{\n\t\t\tformat: 'es'\n\t\t},\n\t\t{\n\t\t\tformat: 'es',\n\t\t\tminify: true\n\t\t}\n\t]\n);"
  },
  {
    "path": "rollup.scripts.js",
    "content": "import babel from 'rollup-plugin-babel';\nimport license from 'rollup-plugin-license';\nimport { terser } from 'rollup-plugin-terser';\nimport prettier from 'rollup-plugin-prettier';\nconst banner = require('./banner');\n\nconst createBuild = (options) => {\n\tconst { format, id, name, minify = false, transpile = false } = options;\n\n\t// get filename\n\tconst filename = ['dist/', name];\n\tif (format === 'es') {\n\t\tfilename.push('.esm');\n\t}\n\tif (minify) {\n\t\tfilename.push('.min');\n\t}\n\tfilename.push('.js');\n\n\t// collect plugins\n\tconst plugins = [];\n\tif (transpile) {\n\t\tplugins.push(babel({\n\t\t\texclude: ['node_modules/**']\n\t\t}));\n\t}\n\tif (minify) {\n\t\tplugins.push(terser());\n\t}\n\telse {\n\t\tplugins.push(prettier({\n\t\t\tsingleQuote: true,\n\t\t\tparser: 'babel'\n\t\t}));\n\t}\n\tplugins.push(license({banner: banner(options)}));\n\t\n\t// return Rollup config\n\treturn {\n\t\tinput: 'src/js/index.js',\n\t\ttreeshake: false,\n\t\toutput: [\n\t\t\t{\n\t\t\t\tformat,\n\t\t\t\tname: id,\n\t\t\t\tfile: filename.join('')\n\t\t\t}\n\t\t],\n\t\tplugins\n\t}\n};\n\nexport default (metadata, configs) => configs.map(config => createBuild({ ...metadata, ...config }));"
  },
  {
    "path": "src/css/assistant.css",
    "content": ".filepond--assistant {\n    position: absolute;\n    overflow: hidden;\n    height: 1px;\n    width: 1px;\n    padding: 0;\n    border: 0;\n    clip: rect(1px, 1px, 1px, 1px);\n    clip-path: inset(50%);\n    white-space: nowrap;\n}\n"
  },
  {
    "path": "src/css/browser.css",
    "content": "/* Hard to override styles */\n.filepond--browser.filepond--browser {\n    /* is positioned absolute so it is focusable for form validation errors */\n    position: absolute;\n    margin: 0;\n    padding: 0;\n\n    /* is positioned ~behind drop label */\n    left: 1em;\n    top: 1.75em;\n    width: calc(100% - 2em);\n\n    /* hide visually */\n    opacity: 0;\n    font-size: 0; /* removes text cursor in Internet Explorer 11 */\n}\n"
  },
  {
    "path": "src/css/data.css",
    "content": ".filepond--data {\n    position: absolute;\n    width: 0;\n    height: 0;\n    padding: 0;\n    margin: 0;\n    border: none;\n    visibility: hidden;\n    pointer-events: none;\n    contain: strict;\n}\n"
  },
  {
    "path": "src/css/drip.css",
    "content": ".filepond--drip {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    overflow: hidden;\n    opacity: 0.1;\n\n    /* can't interact with this element */\n    pointer-events: none;\n\n    /* inherit border radius from parent (needed for drip-blob cut of) */\n    border-radius: 0.5em;\n\n    /* this seems to prevent Chrome from redrawing this layer constantly */\n    background: rgba(0, 0, 0, 0.01);\n}\n\n.filepond--drip-blob {\n    position: absolute;\n    transform-origin: center center;\n    top: 0;\n    left: 0;\n    width: 8em;\n    height: 8em;\n    margin-left: -4em;\n    margin-top: -4em;\n    background: #292625;\n    border-radius: 50%;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n"
  },
  {
    "path": "src/css/drop-label.css",
    "content": ".filepond--drop-label {\n    position: absolute;\n    left: 0;\n    right: 0;\n    top: 0;\n    margin: 0;\n    color: #4f4f4f;\n\n    /* center contents */\n    display: flex;\n    justify-content: center;\n    align-items: center;\n\n    /* fixes IE11 centering problems (is overruled by label min-height) */\n    height: 0px;\n\n    /* dont allow selection */\n    user-select: none;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n\n/* Hard to override styles on purpose */\n.filepond--drop-label.filepond--drop-label label {\n    display: block;\n    margin: 0;\n    padding: 0.5em; /* use padding instead of margin so click area is not impacted */\n}\n\n.filepond--drop-label label {\n    cursor: default;\n    font-size: 0.875em;\n    font-weight: normal;\n    text-align: center;\n    line-height: 1.5;\n}\n\n.filepond--label-action {\n    text-decoration: underline;\n    text-decoration-skip-ink: auto;\n    text-decoration-color: #a7a4a4;\n    cursor: pointer;\n}\n\n.filepond--root[data-disabled] {\n    & .filepond--drop-label label {\n        opacity: 0.5;\n    }\n}\n"
  },
  {
    "path": "src/css/file-action-button.css",
    "content": "/* Hard to override styles */\n.filepond--file-action-button.filepond--file-action-button {\n    font-size: 1em;\n    width: 1.625em;\n    height: 1.625em;\n\n    font-family: inherit;\n    line-height: inherit;\n\n    margin: 0;\n    padding: 0;\n    border: none;\n    outline: none;\n\n    will-change: transform, opacity;\n\n    /* hidden label */\n    & span {\n        position: absolute;\n        overflow: hidden;\n        height: 1px;\n        width: 1px;\n        padding: 0;\n        border: 0;\n        clip: rect(1px, 1px, 1px, 1px);\n        clip-path: inset(50%);\n        white-space: nowrap;\n    }\n\n    /* scale SVG to fill button */\n    & svg {\n        width: 100%;\n        height: 100%;\n    }\n\n    /* bigger touch area */\n    &::after {\n        position: absolute;\n        left: -0.75em;\n        right: -0.75em;\n        top: -0.75em;\n        bottom: -0.75em;\n        content: '';\n    }\n}\n\n/* Soft styles */\n.filepond--file-action-button {\n    /* use default arrow cursor */\n    cursor: auto;\n\n    /* reset default button styles */\n    color: #fff;\n\n    /* set default look n feel */\n    border-radius: 50%;\n    background-color: rgba(0, 0, 0, 0.5);\n    background-image: none;\n\n    /* we animate box shadow on focus */\n    /* it's only slightly slower than animating */\n    /* a pseudo-element with transforms and renders */\n    /* a lot better on chrome */\n    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);\n    transition: box-shadow 0.25s ease-in;\n\n    &:hover,\n    &:focus {\n        box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.9);\n    }\n\n    &[disabled] {\n        color: rgba(255, 255, 255, 0.5);\n        background-color: rgba(0, 0, 0, 0.25);\n    }\n\n    &[hidden] {\n        display: none;\n    }\n}\n\n/* edit button */\n.filepond--action-edit-item.filepond--action-edit-item {\n    width: 2em;\n    height: 2em;\n    padding: 0.1875em;\n\n    &[data-align*='center'] {\n        margin-left: -0.1875em;\n    }\n\n    &[data-align*='bottom'] {\n        margin-bottom: -0.1875em;\n    }\n}\n\n.filepond--action-edit-item-alt {\n    border: none;\n    line-height: inherit;\n    background: transparent;\n    font-family: inherit;\n    color: inherit;\n    outline: none;\n    padding: 0;\n    margin: 0 0 0 0.25em;\n    pointer-events: all;\n    position: absolute;\n\n    svg {\n        width: 1.3125em;\n        height: 1.3125em;\n    }\n\n    span {\n        font-size: 0;\n        opacity: 0;\n    }\n}\n"
  },
  {
    "path": "src/css/file-info.css",
    "content": ".filepond--file-info {\n    position: static;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    flex: 1;\n    margin: 0 0.5em 0 0;\n    min-width: 0;\n\n    /* will be animated */\n    will-change: transform, opacity;\n\n    /* can't do anything with this info */\n    pointer-events: none;\n    user-select: none;\n\n    /* no margins on children */\n    & * {\n        margin: 0;\n    }\n\n    /* we don't want to have these overrules so these selectors are a bit more specific */\n    & .filepond--file-info-main {\n        font-size: 0.75em;\n        line-height: 1.2;\n\n        /* we want ellipsis if this bar gets too wide */\n        text-overflow: ellipsis;\n        overflow: hidden;\n        white-space: nowrap;\n        width: 100%;\n    }\n\n    & .filepond--file-info-sub {\n        font-size: 0.625em;\n        opacity: 0.5;\n        transition: opacity 0.25s ease-in-out;\n        white-space: nowrap;\n    }\n\n    & .filepond--file-info-sub:empty {\n        display: none;\n    }\n}\n"
  },
  {
    "path": "src/css/file-status.css",
    "content": ".filepond--file-status {\n    position: static;\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n    flex-grow: 0;\n    flex-shrink: 0;\n\n    margin: 0;\n    min-width: 2.25em;\n    text-align: right;\n\n    /* will be animated */\n    will-change: transform, opacity;\n\n    /* can't do anything with this info */\n    pointer-events: none;\n    user-select: none;\n\n    /* no margins on children */\n    & * {\n        margin: 0;\n        white-space: nowrap;\n    }\n\n    /* font sizes */\n    & .filepond--file-status-main {\n        font-size: 0.75em;\n        line-height: 1.2;\n    }\n\n    & .filepond--file-status-sub {\n        font-size: 0.625em;\n        opacity: 0.5;\n        transition: opacity 0.25s ease-in-out;\n    }\n}\n"
  },
  {
    "path": "src/css/file-wrapper.css",
    "content": "/* Hard to override styles */\n.filepond--file-wrapper.filepond--file-wrapper {\n    border: none;\n    margin: 0;\n    padding: 0;\n    min-width: 0;\n    height: 100%;\n\n    /* hide legend for visual users */\n    & > legend {\n        position: absolute;\n        overflow: hidden;\n        height: 1px;\n        width: 1px;\n        padding: 0;\n        border: 0;\n        clip: rect(1px, 1px, 1px, 1px);\n        clip-path: inset(50%);\n        white-space: nowrap;\n    }\n}\n"
  },
  {
    "path": "src/css/file.css",
    "content": ".filepond--file {\n    position: static;\n    display: flex;\n    height: 100%;\n    align-items: flex-start;\n\n    padding: 0.5625em 0.5625em;\n\n    color: #fff;\n    border-radius: 0.5em;\n\n    /* control positions */\n    & .filepond--file-status {\n        margin-left: auto;\n        margin-right: 2.25em;\n    }\n\n    & .filepond--processing-complete-indicator {\n        pointer-events: none;\n        user-select: none;\n        z-index: 3;\n    }\n\n    & .filepond--processing-complete-indicator,\n    & .filepond--progress-indicator,\n    & .filepond--file-action-button {\n        position: absolute;\n    }\n\n    /* .filepond--file-action-button */\n    & [data-align*='left'] {\n        left: 0.5625em;\n    }\n\n    & [data-align*='right'] {\n        right: 0.5625em;\n    }\n\n    & [data-align*='center'] {\n        left: calc(50% - 0.8125em); /* .8125 is half of button width */\n    }\n\n    & [data-align*='bottom'] {\n        bottom: 1.125em;\n    }\n\n    & [data-align='center'] {\n        top: calc(50% - 0.8125em);\n    }\n\n    & .filepond--progress-indicator {\n        margin-top: 0.1875em;\n\n        &[data-align*='right'] {\n            margin-right: 0.1875em;\n        }\n\n        &[data-align*='left'] {\n            margin-left: 0.1875em;\n        }\n    }\n}\n\n/* make sure text does not overlap */\n[data-filepond-item-state='cancelled'],\n[data-filepond-item-state*='invalid'],\n[data-filepond-item-state*='error'] {\n    & .filepond--file-info {\n        margin-right: 2.25em;\n    }\n}\n\n[data-filepond-item-state~='processing'] {\n    & .filepond--file-status-sub {\n        opacity: 0;\n    }\n\n    & .filepond--action-abort-item-processing ~ .filepond--file-status .filepond--file-status-sub {\n        opacity: 0.5;\n    }\n}\n\n[data-filepond-item-state='processing-error'] {\n    & .filepond--file-status-sub {\n        opacity: 0;\n    }\n\n    & .filepond--action-retry-item-processing ~ .filepond--file-status .filepond--file-status-sub {\n        opacity: 0.5;\n    }\n}\n\n[data-filepond-item-state='processing-complete'] {\n    /* busy state */\n    & .filepond--action-revert-item-processing svg {\n        animation: fall 0.5s 0.125s linear both;\n    }\n\n    /* hide details by default, only show when can revert */\n    & .filepond--file-status-sub {\n        opacity: 0.5;\n    }\n\n    &\n        .filepond--processing-complete-indicator:not([style*='hidden'])\n        ~ .filepond--file-status\n        .filepond--file-status-sub {\n        opacity: 0;\n    }\n\n    & .filepond--file-info-sub {\n        opacity: 0;\n    }\n\n    & .filepond--action-revert-item-processing ~ .filepond--file-info .filepond--file-info-sub {\n        opacity: 0.5;\n    }\n}\n\n/* file state can be invalid or error, both are visually similar but */\n/* having them as separate states might be useful */\n[data-filepond-item-state*='invalid'],\n[data-filepond-item-state*='error'] {\n    & .filepond--panel,\n    & .filepond--file-wrapper {\n        animation: shake 0.65s linear both;\n    }\n}\n\n/* spins progress indicator when file is marked as busy */\n[data-filepond-item-state*='busy'] {\n    & .filepond--progress-indicator svg {\n        animation: spin 1s linear infinite;\n    }\n}\n\n/**\n * States\n */\n@keyframes spin {\n    0% {\n        transform: rotateZ(0deg);\n    }\n\n    100% {\n        transform: rotateZ(360deg);\n    }\n}\n\n@keyframes shake {\n    10%,\n    90% {\n        transform: translateX(-0.0625em);\n    }\n\n    20%,\n    80% {\n        transform: translateX(0.125em);\n    }\n\n    30%,\n    50%,\n    70% {\n        transform: translateX(-0.25em);\n    }\n\n    40%,\n    60% {\n        transform: translateX(0.25em);\n    }\n}\n\n@keyframes fall {\n    0% {\n        opacity: 0;\n        transform: scale(0.5);\n        animation-timing-function: ease-out;\n    }\n\n    70% {\n        opacity: 1;\n        transform: scale(1.1);\n        animation-timing-function: ease-in-out;\n    }\n\n    100% {\n        transform: scale(1);\n        animation-timing-function: ease-out;\n    }\n}\n"
  },
  {
    "path": "src/css/hopper.css",
    "content": "/* ignore all other interaction elements while dragging a file */\n.filepond--hopper[data-hopper-state='drag-over'] > * {\n    pointer-events: none;\n}\n\n/* capture all hit tests using a hidden layer, this speeds up the event flow */\n.filepond--hopper[data-hopper-state='drag-over']::after {\n    content: '';\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 100;\n}\n"
  },
  {
    "path": "src/css/item-order.css",
    "content": ".filepond--progress-indicator {\n    z-index: 103;\n}\n\n.filepond--file-action-button {\n    z-index: 102;\n}\n\n.filepond--file-status {\n    z-index: 101;\n}\n\n.filepond--file-info {\n    z-index: 100;\n}\n"
  },
  {
    "path": "src/css/item.css",
    "content": ".filepond--item {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    z-index: 1;\n\n    padding: 0;\n    margin: 0.25em;\n\n    will-change: transform, opacity;\n\n    touch-action: auto;\n\n    /* item children order */\n    & > .filepond--panel {\n        z-index: -1;\n\n        /* has a slight shadow */\n        .filepond--panel-bottom {\n            box-shadow: 0 0.0625em 0.125em -0.0625em rgba(0, 0, 0, 0.25);\n        }\n    }\n\n    /* drag related */\n    & > .filepond--file-wrapper,\n    & > .filepond--panel {\n        transition: opacity 0.15s ease-out;\n    }\n\n    &[data-drag-state] {\n        cursor: grab;\n        > .filepond--panel {\n            transition: box-shadow 0.125s ease-in-out;\n            box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n        }\n    }\n\n    &[data-drag-state='drag'] {\n        cursor: grabbing;\n        > .filepond--panel {\n            box-shadow: 0 0.125em 0.3125em rgba(0, 0, 0, 0.325);\n        }\n    }\n\n    &[data-drag-state]:not([data-drag-state='idle']) {\n        z-index: 2;\n    }\n}\n\n/* states */\n.filepond--item-panel {\n    background-color: #64605e;\n}\n\n[data-filepond-item-state='processing-complete'] {\n    .filepond--item-panel {\n        background-color: #369763;\n    }\n}\n\n[data-filepond-item-state*='invalid'],\n[data-filepond-item-state*='error'] {\n    .filepond--item-panel {\n        background-color: #c44e47;\n    }\n}\n\n/* style of item panel */\n.filepond--item-panel {\n    border-radius: 0.5em;\n    transition: background-color 0.25s;\n}\n"
  },
  {
    "path": "src/css/list-scroller.css",
    "content": "/* normal mode */\n.filepond--list-scroller {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    margin: 0;\n    will-change: transform;\n}\n\n/* scroll mode */\n.filepond--list-scroller[data-state='overflow'] {\n    & .filepond--list {\n        bottom: 0;\n        right: 0;\n    }\n\n    overflow-y: scroll;\n    overflow-x: hidden;\n    -webkit-overflow-scrolling: touch;\n    mask: linear-gradient(to bottom, #000 calc(100% - 0.5em), transparent 100%);\n}\n\n/* style scrollbar */\n.filepond--list-scroller::-webkit-scrollbar {\n    background: transparent;\n}\n\n.filepond--list-scroller::-webkit-scrollbar:vertical {\n    width: 1em;\n}\n\n.filepond--list-scroller::-webkit-scrollbar:horizontal {\n    height: 0;\n}\n\n.filepond--list-scroller::-webkit-scrollbar-thumb {\n    background-color: rgba(0, 0, 0, 0.3);\n    border-radius: 99999px;\n    border: 0.3125em solid transparent;\n    background-clip: content-box;\n}\n"
  },
  {
    "path": "src/css/list.css",
    "content": "/* hard to overide styles on purpose */\n.filepond--list.filepond--list {\n    position: absolute;\n    top: 0;\n    margin: 0;\n    padding: 0;\n    list-style-type: none;\n\n    /* prevents endless paint calls on filepond--list-scroller */\n    will-change: transform;\n}\n\n/* used for padding so allowed to be restyled */\n.filepond--list {\n    left: 0.75em;\n    right: 0.75em;\n}\n"
  },
  {
    "path": "src/css/modifiers.css",
    "content": ".filepond--root {\n    &[data-style-panel-layout~='integrated'] {\n        width: 100%;\n        height: 100%;\n        max-width: none;\n        margin: 0;\n    }\n\n    &[data-style-panel-layout~='circle'],\n    &[data-style-panel-layout~='integrated'] {\n        & .filepond--panel-root {\n            border-radius: 0;\n            > * {\n                display: none;\n            }\n        }\n\n        & .filepond--drop-label {\n            bottom: 0;\n            height: auto;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            z-index: 7;\n        }\n\n        /* we're only loading one item, this makes the intro animation a bit nicer */\n        & .filepond--item-panel {\n            display: none;\n        }\n    }\n\n    &[data-style-panel-layout~='compact'],\n    &[data-style-panel-layout~='integrated'] {\n        & .filepond--list-scroller {\n            overflow: hidden;\n            height: 100%;\n            margin-top: 0;\n            margin-bottom: 0;\n        }\n\n        & .filepond--list {\n            left: 0;\n            right: 0;\n            height: 100%;\n        }\n\n        & .filepond--item {\n            margin: 0;\n        }\n\n        & .filepond--file-wrapper {\n            height: 100%;\n        }\n\n        & .filepond--drop-label {\n            z-index: 7;\n        }\n    }\n\n    &[data-style-panel-layout~='circle'] {\n        border-radius: 99999rem;\n        overflow: hidden;\n\n        & > .filepond--panel {\n            border-radius: inherit;\n\n            > * {\n                display: none;\n            }\n        }\n\n        /* circle cuts of this info, so best to hide it */\n        & .filepond--file-info {\n            display: none;\n        }\n        & .filepond--file-status {\n            display: none;\n        }\n\n        & .filepond--action-edit-item {\n            opacity: 1 !important;\n            visibility: visible !important;\n        }\n    }\n}\n\n/* dirfty way to fix circular overflow issue on safari 11+ */\n@media not all and (min-resolution: 0.001dpcm) {\n    @supports (-webkit-appearance: none) and (stroke-color: transparent) {\n        .filepond--root[data-style-panel-layout~='circle'] {\n            will-change: transform;\n        }\n    }\n}\n"
  },
  {
    "path": "src/css/panel-root.css",
    "content": ".filepond--panel-root {\n    border-radius: 0.5em;\n    background-color: #f1f0ef;\n}\n"
  },
  {
    "path": "src/css/panel.css",
    "content": ".filepond--panel {\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    margin: 0;\n\n    /* defaults to 100% height (fixed height mode) this fixes problem with panel height in IE11 */\n    height: 100% !important;\n\n    /* no interaction possible with panel */\n    pointer-events: none;\n}\n\n.filepond-panel:not([data-scalable='false']) {\n    height: auto !important;\n}\n\n.filepond--panel[data-scalable='false'] {\n    > div {\n        display: none;\n    }\n}\n\n.filepond--panel[data-scalable='true'] {\n    /* this seems to fix Chrome performance issues */\n    /* - when box-shadow is enabled */\n    /* - when multiple ponds are active on the same page */\n    transform-style: preserve-3d;\n\n    /* prevent borders and backgrounds */\n    background-color: transparent !important;\n    border: none !important;\n}\n\n.filepond--panel-top,\n.filepond--panel-bottom,\n.filepond--panel-center {\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    margin: 0;\n    padding: 0;\n}\n\n.filepond--panel-top,\n.filepond--panel-bottom {\n    height: 0.5em;\n}\n\n.filepond--panel-top {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n    border-bottom: none !important;\n\n    /* fixes tiny transparant line between top and center panel */\n    &::after {\n        content: '';\n        position: absolute;\n        height: 2px;\n        left: 0;\n        right: 0;\n        bottom: -1px;\n        background-color: inherit;\n    }\n}\n\n.filepond--panel-center,\n.filepond--panel-bottom {\n    will-change: transform;\n    backface-visibility: hidden;\n    transform-origin: left top;\n    transform: translate3d(0, 0.5em, 0);\n}\n\n.filepond--panel-bottom {\n    border-top-left-radius: 0 !important;\n    border-top-right-radius: 0 !important;\n    border-top: none !important;\n\n    /* fixes tiny transparant line between bottom and center of panel */\n    &::before {\n        content: '';\n        position: absolute;\n        height: 2px;\n        left: 0;\n        right: 0;\n        top: -1px;\n        background-color: inherit;\n    }\n}\n\n.filepond--panel-center {\n    /* the center panel is scaled using scale3d to fit the correct height */\n    /* we use 100px instead of 1px as scaling 1px to a huge height is really laggy on chrome */\n    height: 100px !important;\n    border-top: none !important;\n    border-bottom: none !important;\n    border-radius: 0 !important;\n\n    /* hide if not transformed, prevents a little flash when the panel is at 100px height while attached for first time */\n    &:not([style]) {\n        visibility: hidden;\n    }\n}\n"
  },
  {
    "path": "src/css/progress-indicator.css",
    "content": ".filepond--progress-indicator {\n    position: static;\n    width: 1.25em;\n    height: 1.25em;\n\n    color: #fff;\n\n    /* can't have margins */\n    margin: 0;\n\n    /* no interaction possible with progress indicator */\n    pointer-events: none;\n\n    /* will be animated */\n    will-change: transform, opacity;\n}\n\n.filepond--progress-indicator svg {\n    width: 100%;\n    height: 100%;\n    vertical-align: top;\n    transform-box: fill-box; /* should center the animation correctly when zoomed in */\n}\n\n.filepond--progress-indicator path {\n    fill: none;\n    stroke: currentColor;\n}\n"
  },
  {
    "path": "src/css/root-order.css",
    "content": ".filepond--list-scroller {\n    z-index: 6;\n}\n\n.filepond--drop-label {\n    z-index: 5;\n}\n\n.filepond--drip {\n    z-index: 3;\n}\n\n.filepond--root > .filepond--panel {\n    z-index: 2;\n}\n\n.filepond--browser {\n    z-index: 1;\n}\n"
  },
  {
    "path": "src/css/root.css",
    "content": ".filepond--root {\n    /* layout*/\n    box-sizing: border-box;\n    position: relative;\n    margin-bottom: 1em;\n\n    /* base font size for whole component */\n    font-size: 1rem;\n\n    /* base line height */\n    line-height: normal;\n\n    /* up uses default system font family */\n    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,\n        'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';\n\n    /* will increase font weight a bit on Safari */\n    font-weight: 450;\n\n    /* default text alignment */\n    text-align: left;\n\n    /* better text rendering on Safari */\n    text-rendering: optimizeLegibility;\n\n    /* text direction is ltr for now */\n    direction: ltr;\n\n    /* optimize rendering */\n    /* https://developer.mozilla.org/en-US/docs/Web/CSS/contain */\n    contain: layout style size;\n\n    /* correct box sizing, line-height and positioning on child elements */\n    & * {\n        box-sizing: inherit;\n        line-height: inherit;\n    }\n\n    & *:not(text) {\n        font-size: inherit;\n    }\n\n    /* block everything */\n    &[data-disabled] {\n        pointer-events: none;\n\n        .filepond--list-scroller {\n            pointer-events: all;\n        }\n\n        .filepond--list {\n            pointer-events: none;\n        }\n    }\n}\n\n/**\n * Root element children layout\n */\n.filepond--root {\n    & .filepond--drop-label {\n        min-height: 4.75em;\n    }\n\n    & .filepond--list-scroller {\n        margin-top: 1em;\n        margin-bottom: 1em;\n    }\n\n    & .filepond--credits {\n        position: absolute;\n        right: 0;\n        opacity: 0.4;\n        line-height: 0.85;\n        font-size: 11px;\n        color: inherit;\n        text-decoration: none;\n        z-index: 3;\n        bottom: -14px;\n    }\n\n    & .filepond--credits[style] {\n        top: 0;\n        bottom: auto;\n        margin-top: 14px;\n    }\n}\n"
  },
  {
    "path": "src/css/styles.css",
    "content": "@import 'assistant.css';\n@import 'browser.css';\n@import 'data.css';\n@import 'drip.css';\n@import 'drop-label.css';\n@import 'file-action-button.css';\n@import 'file-info.css';\n@import 'file-status.css';\n@import 'file-wrapper.css';\n@import 'file.css';\n@import 'hopper.css';\n@import 'item-order.css';\n@import 'item.css';\n@import 'list-scroller.css';\n@import 'list.css';\n@import 'modifiers.css';\n@import 'panel-root.css';\n@import 'panel.css';\n@import 'progress-indicator.css';\n@import 'root-order.css';\n@import 'root.css';\n"
  },
  {
    "path": "src/js/__tests__/addFile.test.js",
    "content": "import './windowMatchMedia.mock';\nimport { create } from '../index.js';\n\ndescribe('adding files', () => {\n    let pond = null;\n\n    beforeEach(() => {\n        if (pond) {\n            pond.destroy();\n        }\n\n        pond = create();\n\n        // enables draw loop, else it seems that filepond is hidden\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1),\n        });\n    });\n\n    test('add file', done => {\n        const data = new File(['Hello World!'], 'dummy.txt', {\n            type: 'text/plain',\n            lastModified: new Date(),\n        });\n        pond.addFile(data).then(item => {\n            done();\n        });\n    });\n\n    test('add blob', done => {\n        const data = new Blob(['Hello World!'], { type: 'text/plain' });\n        pond.addFile(data).then(item => {\n            done();\n        });\n    });\n\n    test('add base64 string', done => {\n        const data = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';\n        pond.addFile(data).then(item => {\n            done();\n        });\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/callbacks.test.js",
    "content": "import mockConsole from \"jest-mock-console\";\n\nimport './windowMatchMedia.mock';\nimport { create, OptionTypes, FileStatus } from '../index.js';\n\ndescribe('adding files', () => {\n    const data = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';\n    let pond = null;\n\n    const createPond = options => {\n        if (pond) {\n            pond.destroy();\n        }\n\n        pond = create({\n            server: {\n                process: (fieldName, file, metadata, load, error, progress, abort) => {\n                    let p = 0;\n                    const interval = setInterval(() => {\n                        p += 0.01;\n                        progress(true, p, 1);\n                    }, 50);\n                    const timeout = setTimeout(() => {\n                        clearInterval(interval);\n                        progress(true, 1, 1);\n                        load(Date.now());\n                    }, 750);\n                    return {\n                        abort: () => {\n                            clearTimeout(timeout);\n                            abort();\n                        },\n                    };\n                },\n            },            \n            ...options,\n        });\n\n        // enables draw loop, else it seems that filepond is hidden and it won't run\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1),\n        });\n    };\n\n    test('oninit', done => {\n        createPond({\n            oninit: () => {\n                done();\n            },\n        });\n    });\n\n    test('onaddfilestart', done => {\n        createPond();\n        pond.onaddfilestart = () => {\n            done();\n        };\n        pond.addFile(data);\n    });\n\n    test('onaddfileprogress', done => {\n        createPond();\n        pond.onaddfilestart = () => {\n            done();\n        };\n        pond.addFile(data);\n    });\n\n    test('onaddfile', done => {\n        createPond();\n        pond.onaddfilestart = () => {\n            done();\n        };\n        pond.addFile(data);\n    });\n\n    test('onerror', done => {\n        // we don't want the console error about the server call failure to muddy up the console\n        const restoreConsole = mockConsole();\n\n        createPond({\n            server: './invalid-path'\n        });\n        pond.onerror = () => {\n            done();\n        };\n        pond.addFile(data);\n\n        // restore the console back to normal so that real issues aren't hidden\n        restoreConsole();\n    });\n\n    test('onremovefile', done => {\n        createPond();\n        pond.files = [data];\n        pond.onremovefile = () => {\n            done();\n        };\n        pond.removeFile();\n    });\n\n    test('onprocessfilestart', done => {\n        createPond();\n        pond.onprocessfilestart = () => {\n            done();\n        };\n        pond.files = [data];\n    });\n\n    test('onprocessfileprogress', done => {\n        createPond();\n        pond.onprocessfileprogress = () => {\n            done();\n        };\n        pond.files = [data];\n    });\n\n    test('onprocessfileabort', done => {\n        createPond();\n        pond.onprocessfileabort = () => {\n            done();\n        };\n        pond.files = [data];\n\n        pond.getFile().abortProcessing();\n    });\n\n    test('onprocessfile', done => {\n        createPond();\n        pond.onprocessfile = () => {\n            done();\n        };\n        pond.files = [data];\n    });\n\n    test('onprocessfiles', done => {\n        createPond();\n        pond.onprocessfiles = () => {\n            const result = pond\n                .getFiles()\n                .every(file => file.status === FileStatus.PROCESSING_COMPLETE);\n            expect(result).toBe(true);\n            done();\n        };\n        pond.files = [data, data];\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/contentDisposition.test.js",
    "content": "import { getFileNameFromHeader } from '../utils/getFileInfoFromHeaders';\n\ndescribe('parse filename', () => {\n    [\n        { value: ``, expected: null },\n        { value: `foo-bar`, expected: null },\n        { value: `Content-Disposition: attachment;`, expected: null },\n        { value: `Content-Disposition: attachment; filename=`, expected: null },\n        { value: `Content-Disposition: attachment; filename.jpg`, expected: null },\n        {\n            value: `Content-Disposition: attachment; filename=filename.jpg`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=filename.jpg;`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=\"filename.jpg\"`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=\"filename.jpg\";`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=file name.jpg`,\n            expected: 'file name.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=filename.jpg; filename*=UTF-8''filename.jpg`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=\"filename.jpg\"; filename*=UTF-8''filename.jpg`,\n            expected: 'filename.jpg',\n        },\n        {\n            value: `Content-Disposition: attachment; filename=\"file name.jpg\"; filename*=UTF-8''file%20name.jpg`,\n            expected: 'file name.jpg',\n        },\n    ].forEach(header => {\n        test(`Can parse: \"${header.value}\"`, () => {\n            const name = getFileNameFromHeader(header.value);\n            expect(name).toBe(header.expected);\n        });\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/createInstance.test.js",
    "content": "import './windowMatchMedia.mock';\nimport { create } from '../index.js';\n\ndescribe('create instance', () => {\n    test('without parameters', () => {\n        expect(create()).toBeDefined();\n    });\n\n    test('with options object only', () => {\n        expect(\n            create({\n                instantUpload: false,\n            }).instantUpload\n        ).toBe(false);\n    });\n\n    test('with element only', () => {\n        const form = document.createElement('form');\n        const input = document.createElement('input');\n        input.type = 'file';\n        form.appendChild(input);\n        expect(create(input).element.parentNode).toBe(form);\n    });\n\n    test('with element and options object', () => {\n        const form = document.createElement('form');\n        const input = document.createElement('input');\n        input.type = 'file';\n        input.dataset.dropOnPage = false;\n        form.appendChild(input);\n        const pond = create(input, {\n            dropOnPage: true,\n        });\n        expect(pond.dropOnPage).toBe(false);\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/removeFile.test.js",
    "content": "import './windowMatchMedia.mock';\nimport { create, isSupported } from '../index.js';\n\nconst server = {\n    process: (fieldName, file, metadata, load, error, progress, abort) => {\n        let p = 0;\n        const interval = setInterval(() => {\n            p += 0.01;\n            progress(true, p, 1);\n        }, 50);\n        setTimeout(() => {\n            clearInterval(interval);\n            progress(true, 1, 1);\n            load(Date.now());\n        }, 750);\n    },\n};\n\ndescribe('removing files', () => {\n    let pond = null;\n\n    const DUMMY_FILE = new File(['Hello World!'], 'text_file_a.txt', {\n        type: 'text/plain',\n        lastModified: new Date(),\n    });\n    const LOCAL_FILE = {\n        source: '12345',\n        options: {\n            type: 'local',\n            file: {\n                name: 'my-file.png',\n                size: 12345,\n                type: 'image/png',\n            },\n        },\n    };\n\n    beforeEach(() => {\n        if (pond) {\n            pond.destroy();\n        }\n\n        pond = create({\n            instantUpload: false,\n            server,\n        });\n\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1),\n        });\n    });\n\n    test('remove file object', () => {\n        pond.files = [DUMMY_FILE];\n        pond.removeFile();\n        expect(pond.getFiles().length).toBe(0);\n    });\n\n    test('process, then remove file object', done => {\n        pond.onremovefile = (error, file) => {\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        };\n        pond.onaddfile = () => {\n            pond.processFile().then(() => {\n                pond.removeFile();\n            });\n        };\n        pond.files = [DUMMY_FILE];\n    });\n\n    test('remove file object from client and from server', done => {\n        pond.server = {\n            ...server,\n            remove: (source, load, error) => {\n                setTimeout(() => {\n                    load();\n                }, 10);\n            },\n        };\n\n        pond.onremovefile = (error, file) => {\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        };\n\n        pond.onaddfile = () => {\n            pond.removeFile();\n        };\n\n        pond.files = [LOCAL_FILE];\n    });\n\n    test('remove file object from client and fail to remove from server', done => {\n        pond.server = {\n            ...server,\n            remove: (source, load, error) => {\n                setTimeout(() => {\n                    error('fail');\n                }, 10);\n            },\n        };\n\n        const onremovefile = jest.fn();\n        pond.onremovefile = onremovefile;\n\n        pond.onremovefile = (error, file) => {\n            expect(error.type).toBe('error');\n            expect(onremovefile).not.toHaveBeenCalled();\n            expect(pond.getFiles().length).toBe(1);\n            done();\n        };\n\n        pond.onaddfile = () => {\n            pond.removeFile();\n        };\n\n        pond.files = [LOCAL_FILE];\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/revertUploadOnRemove.test.js",
    "content": "import \"./windowMatchMedia.mock\";\nimport { create } from '../index.js';\nimport { actions } from '../app/actions.js';\n\n/**\n * These tests verify that revert calls are made to revert uploads on removal of\n * files from the UI in certain circumstances. Reverting of uploads is generally\n * handled directly through the REVERT_ITEM_PROCESSING action which is triggered\n * when clicking the 'x' button that appears to the right hand side of a successful\n * file upload entry in the filepond UI. There are some cases, such as with\n * failed chunked uploads, where it's necessary to call revert in response to\n * a REMOVE_ITEM action, triggered through the remove button the 'x' that appears\n * to the left hand side of a failed file upload entry. In these cases, the\n * REVERT_ITEM_PROCESSING action is not triggered and reverting is handled within\n * REMOVE_ITEM.\n */\ndescribe('reverting file uploads on remove', () => {\n\n    const server = {\n        remove: (source, load, error) => { }\n    };\n\n    let pond = null;\n    let item = null;\n\n    // Create 16k of random data to test chunked uploads\n    const fileData = [];\n    for (let i = 0; i < 16384; i++) {\n        fileData.push(Math.floor(Math.random() * 128));\n    }\n\n    const TEXT_FILE = new File(['Hello World!'], 'text_file_a.txt', { type: 'text/plain', lastModified: new Date() });\n    const TEXT_FILE_LARGE = new File(fileData, 'text_file_b.txt', { type: 'text/plain', lastModified: new Date() });\n\n    const setupPond = (options, file, fileType = 'input') => {\n        pond = create({\n            ...options,\n            allowMultiple: false,\n            server\n        });\n\n        // Set up an uploaded file with FileOrigin set to INPUT\n        pond.files = [{ source: file, options: { type: fileType } }];\n        item = pond.getFiles()[0];\n        // Mock the revert function on item so we can check it's been called\n        item.revert = jest.fn();\n\n        // enables draw loop, else it seems that filepond is hidden\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1)\n        });\n\n        return pond;\n    };\n\n    beforeEach(() => {\n        item = null;\n        if (pond) {\n            pond.destroy();\n        }\n    });\n\n    test('no revert on removal of standard upload with chunks disabled', done => {\n        pond = setupPond({ chunkUploads: false }, TEXT_FILE);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).not.toHaveBeenCalled();\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n\n    });\n\n    test('no revert on removal of single chunk upload with chunks enabled', done => {\n        pond = setupPond({ chunkUploads: true, chunkSize: 1024 }, TEXT_FILE);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).not.toHaveBeenCalled();\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n    });\n\n    test('revert on removal of single chunk upload with chunkForce set', done => {\n        pond = setupPond({ chunkUploads: true, chunkForce: true, chunkSize: 1024}, TEXT_FILE);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).toHaveBeenCalledWith(expect.any(Function), false);\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n    });\n\n    test('revert on removal of chunked upload without chunkForce', done => {\n        pond = setupPond({ chunkUploads: true, chunkForce: false, chunkSize: 1024 }, TEXT_FILE_LARGE);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).toHaveBeenCalledWith(expect.any(Function), false);\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n    });\n\n    test('revert on removal of chunked upload with chunkForce set', () => {\n        pond = setupPond({ chunkUploads: true, chunkForce: true, chunkSize: 1024 }, TEXT_FILE_LARGE);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).toHaveBeenCalledWith(expect.any(Function), false);\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n    });\n\n    test('revert limbo with serverId set', () => {\n        const fileId = 'abcdefghijklmnop';\n        pond = setupPond({ chunkUploads: false }, fileId, 'limbo');\n        // Check that serverId is not null (anything accepts values that are not null or undefined)\n        expect(item.serverId).toBe(fileId);\n        pond.onremovefile = (error, file) => {\n            expect(item.revert).toHaveBeenCalledWith(expect.any(Function), false);\n            expect(error).toBe(null);\n            expect(pond.getFiles().length).toBe(0);\n            done();\n        }\n        pond.removeFile(item);\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/server.test.js",
    "content": "import './windowMatchMedia.mock';\nimport { create } from '../index.js';\n\ndescribe('setting server property', () => {\n    let pond;\n\n    beforeEach(() => {\n        // new pond for each test\n        if (pond) pond.destroy();\n        pond = create();\n\n        // enables draw loop, else it seems that filepond is hidden\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1),\n        });\n    });\n\n    test('add fetch headers', () => {\n        pond.server = {\n            headers: {\n                foo: 'bar',\n            },\n            revert: {\n                headers: {\n                    foo: 'baz',\n                },\n            },\n        };\n\n        expect(pond.server).toMatchObject({\n            url: '',\n            timeout: 0,\n            process: null,\n            patch: {\n                url: '?patch=',\n                method: 'PATCH',\n                headers: { foo: 'bar' },\n                withCredentials: false,\n                timeout: 0,\n                onload: null,\n                ondata: null,\n                onerror: null,\n            },\n            revert: {\n                url: '',\n                method: 'DELETE',\n                headers: { foo: 'baz' },\n                withCredentials: false,\n                timeout: 0,\n                onload: null,\n                ondata: null,\n                onerror: null,\n            },\n            fetch: {\n                url: '?fetch=',\n                method: 'GET',\n                headers: { foo: 'bar' },\n                withCredentials: false,\n                timeout: 0,\n                onload: null,\n                ondata: null,\n                onerror: null,\n            },\n            restore: {\n                url: '?restore=',\n                method: 'GET',\n                headers: { foo: 'bar' },\n                withCredentials: false,\n                timeout: 0,\n                onload: null,\n                ondata: null,\n                onerror: null,\n            },\n            load: {\n                url: '?load=',\n                method: 'GET',\n                headers: { foo: 'bar' },\n                withCredentials: false,\n                timeout: 0,\n                onload: null,\n                ondata: null,\n                onerror: null,\n            },\n            remove: null,\n        });\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/setFiles.test.js",
    "content": "import './windowMatchMedia.mock';\nimport { create } from '../index.js';\n\nconst next = cb => {\n    setTimeout(() => {\n        cb();\n    }, 20);\n};\n\ndescribe('setting the files property', () => {\n    let pond = null;\n\n    const TEXT_DATAURI_A = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';\n    const TEXT_FILE_A = new File(['Hello World!'], 'text_file_a.txt', {\n        type: 'text/plain',\n        lastModified: new Date(),\n    });\n    const TEXT_FILE_B = new File(['Hello World!'], 'text_file_b.txt', {\n        type: 'text/plain',\n        lastModified: new Date(),\n    });\n\n    beforeEach(() => {\n        if (pond) {\n            pond.destroy();\n        }\n        pond = create({\n            allowMultiple: true,\n        });\n\n        // enables draw loop, else it seems that filepond is hidden\n        Object.defineProperty(pond.element, 'offsetParent', {\n            get: jest.fn(() => 1),\n        });\n    });\n\n    test('set single file object', () => {\n        pond.files = [TEXT_FILE_A];\n        expect(pond.getFiles().length).toBe(1);\n    });\n\n    test('remove single file object', () => {\n        pond.files = [TEXT_FILE_A];\n        pond.files = [];\n        expect(pond.getFiles().length).toBe(0);\n    });\n\n    test('replace single file object', () => {\n        pond.files = [TEXT_FILE_A];\n        pond.files = [TEXT_FILE_B];\n        expect(pond.getFile().filename).toBe('text_file_b.txt');\n    });\n\n    test('re-add own file object', done => {\n        // set data uri\n        pond.files = [TEXT_DATAURI_A];\n\n        // set marker\n        pond.getFile().setMetadata('marker', 'hello');\n\n        next(() => {\n            // update files array with created file object from input file\n            pond.files = [pond.getFile().file];\n\n            // expect FilePond to find that this file already exists in array\n            expect(pond.getFile().getMetadata('marker')).toBe('hello');\n\n            done();\n        });\n    });\n\n    test('replace file in list of multiple files', done => {\n        // set data uri\n        pond.files = [TEXT_DATAURI_A, TEXT_FILE_A];\n\n        // set marker\n        pond.getFile().setMetadata('marker', 'hello');\n\n        next(() => {\n            // update files array with created file object from input file\n            pond.files = [TEXT_FILE_B, pond.getFile().file];\n\n            // expect FilePond to find that this file already exists in array\n            expect(pond.getFile(1).getMetadata('marker')).toBe('hello');\n\n            done();\n        });\n    });\n});\n"
  },
  {
    "path": "src/js/__tests__/windowMatchMedia.mock",
    "content": "// Mocking window.matchMedia as described in the jest docks\n// since this is not defined in JSDOM and causes the tests\n// to fail. See: \"https://jestjs.io/docs/en/manual-\n// mocks#mocking-methods-which-are-not-implemented-in-jsdom\"\nObject.defineProperty(window, 'matchMedia', {\n    writable: true,\n    value: jest.fn().mockImplementation(query => ({\n        matches: false,\n        media: query,\n        onchange: null,\n        addListener: jest.fn(), // deprecated\n        removeListener: jest.fn(), // deprecated\n        addEventListener: jest.fn(),\n        removeEventListener: jest.fn(),\n        dispatchEvent: jest.fn(),\n    })),\n});\n"
  },
  {
    "path": "src/js/app/actions.js",
    "content": "import { isEmpty } from '../utils/isEmpty';\nimport { forin } from '../utils/forin';\nimport { fromCamels } from '../utils/fromCamels';\nimport { hasRoomForItem } from './utils/hasRoomForItem';\nimport { insertItem } from './utils/insertItem';\nimport { createFileLoader } from './utils/createFileLoader';\nimport { createFetchFunction } from './utils/createFetchFunction';\nimport { createProcessorFunction } from './utils/createProcessorFunction';\nimport { createRevertFunction } from './utils/createRevertFunction';\nimport { createFileProcessor } from './utils/createFileProcessor';\nimport { createItem } from './utils/createItem';\nimport { ItemStatus } from './enum/ItemStatus';\nimport { FileOrigin } from './enum/FileOrigin';\nimport { getItemById } from './utils/getItemById';\nimport { getItemByQuery } from './utils/getItemByQuery';\nimport { InteractionMethod } from './enum/InteractionMethod';\nimport { applyFilterChain, applyFilters } from '../filter';\nimport { createItemAPI } from './utils/createItemAPI';\nimport { createResponse } from '../utils/createResponse';\nimport { fetchBlob } from './utils/fetchBlob';\nimport { isExternalURL } from '../utils/isExternalURL';\nimport { isString } from '../utils/isString';\nimport { isFile } from '../utils/isFile';\nimport { dynamicLabel } from './utils/dynamicLabel';\nimport { getActiveItems } from './utils/getActiveItems';\nimport { isFunction } from '../utils/isFunction';\nimport { limit } from '../utils/limit';\n\nconst isMockItem = item => !isFile(item.file);\n\nconst listUpdated = (dispatch, state) => {\n    clearTimeout(state.listUpdateTimeout);\n    state.listUpdateTimeout = setTimeout(() => {\n        dispatch('DID_UPDATE_ITEMS', { items: getActiveItems(state.items) });\n    }, 0);\n};\n\nconst optionalPromise = (fn, ...params) =>\n    new Promise(resolve => {\n        if (!fn) {\n            return resolve(true);\n        }\n\n        const result = fn(...params);\n\n        if (result == null) {\n            return resolve(true);\n        }\n\n        if (typeof result === 'boolean') {\n            return resolve(result);\n        }\n\n        if (typeof result.then === 'function') {\n            result.then(resolve);\n        }\n    });\n\nconst sortItems = (state, compare) => {\n    state.items.sort((a, b) => compare(createItemAPI(a), createItemAPI(b)));\n};\n\n// returns item based on state\nconst getItemByQueryFromState = (state, itemHandler) => ({\n    query,\n    success = () => {},\n    failure = () => {},\n    ...options\n} = {}) => {\n    const item = getItemByQuery(state.items, query);\n    if (!item) {\n        failure({\n            error: createResponse('error', 0, 'Item not found'),\n            file: null,\n        });\n        return;\n    }\n    itemHandler(item, success, failure, options || {});\n};\n\nexport const actions = (dispatch, query, state) => ({\n    /**\n     * Aborts all ongoing processes\n     */\n    ABORT_ALL: () => {\n        getActiveItems(state.items).forEach(item => {\n            item.freeze();\n            item.abortLoad();\n            item.abortProcessing();\n        });\n    },\n\n    /**\n     * Sets initial files\n     */\n    DID_SET_FILES: ({ value = [] }) => {\n        // map values to file objects\n        const files = value.map(file => ({\n            source: file.source ? file.source : file,\n            options: file.options,\n        }));\n\n        // loop over files, if file is in list, leave it be, if not, remove\n        // test if items should be moved\n        let activeItems = getActiveItems(state.items);\n\n        activeItems.forEach(item => {\n            // if item not is in new value, remove\n            if (!files.find(file => file.source === item.source || file.source === item.file)) {\n                dispatch('REMOVE_ITEM', { query: item, remove: false });\n            }\n        });\n\n        // add new files\n        activeItems = getActiveItems(state.items);\n        files.forEach((file, index) => {\n            // if file is already in list\n            if (activeItems.find(item => item.source === file.source || item.file === file.source))\n                return;\n\n            // not in list, add\n            dispatch('ADD_ITEM', {\n                ...file,\n                interactionMethod: InteractionMethod.NONE,\n                index,\n            });\n        });\n    },\n\n    DID_UPDATE_ITEM_METADATA: ({ id, action, change }) => {\n        // don't do anything\n        if (change.silent) return;\n\n        // if is called multiple times in close succession we combined all calls together to save resources\n        clearTimeout(state.itemUpdateTimeout);\n        state.itemUpdateTimeout = setTimeout(() => {\n            const item = getItemById(state.items, id);\n\n            // only revert and attempt to upload when we're uploading to a server\n            if (!query('IS_ASYNC')) {\n                // should we update the output data\n                applyFilterChain('SHOULD_PREPARE_OUTPUT', false, {\n                    item,\n                    query,\n                    action,\n                    change,\n                }).then(shouldPrepareOutput => {\n                    // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                    const beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                    if (beforePrepareFile)\n                        shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                    if (!shouldPrepareOutput) return;\n\n                    dispatch(\n                        'REQUEST_PREPARE_OUTPUT',\n                        {\n                            query: id,\n                            item,\n                            success: file => {\n                                dispatch('DID_PREPARE_OUTPUT', { id, file });\n                            },\n                        },\n                        true\n                    );\n                });\n\n                return;\n            }\n\n            // if is local item we need to enable upload button so change can be propagated to server\n            if (item.origin === FileOrigin.LOCAL) {\n                dispatch('DID_LOAD_ITEM', {\n                    id: item.id,\n                    error: null,\n                    serverFileReference: item.source,\n                });\n            }\n\n            // for async scenarios\n            const upload = () => {\n                // we push this forward a bit so the interface is updated correctly\n                setTimeout(() => {\n                    dispatch('REQUEST_ITEM_PROCESSING', { query: id });\n                }, 32);\n            };\n\n            const revert = doUpload => {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                )\n                    .then(doUpload ? upload : () => {})\n                    .catch(() => {});\n            };\n\n            const abort = doUpload => {\n                item.abortProcessing().then(doUpload ? upload : () => {});\n            };\n\n            // if we should re-upload the file immediately\n            if (item.status === ItemStatus.PROCESSING_COMPLETE) {\n                return revert(state.options.instantUpload);\n            }\n\n            // if currently uploading, cancel upload\n            if (item.status === ItemStatus.PROCESSING) {\n                return abort(state.options.instantUpload);\n            }\n\n            if (state.options.instantUpload) {\n                upload();\n            }\n        }, 0);\n    },\n\n    MOVE_ITEM: ({ query, index }) => {\n        const item = getItemByQuery(state.items, query);\n        if (!item) return;\n        const currentIndex = state.items.indexOf(item);\n        index = limit(index, 0, state.items.length - 1);\n        if (currentIndex === index) return;\n        state.items.splice(index, 0, state.items.splice(currentIndex, 1)[0]);\n    },\n\n    SORT: ({ compare }) => {\n        sortItems(state, compare);\n        dispatch('DID_SORT_ITEMS', {\n            items: query('GET_ACTIVE_ITEMS'),\n        });\n    },\n\n    ADD_ITEMS: ({ items, index, interactionMethod, success = () => {}, failure = () => {} }) => {\n        let currentIndex = index;\n\n        if (index === -1 || typeof index === 'undefined') {\n            const insertLocation = query('GET_ITEM_INSERT_LOCATION');\n            const totalItems = query('GET_TOTAL_ITEMS');\n            currentIndex = insertLocation === 'before' ? 0 : totalItems;\n        }\n\n        const ignoredFiles = query('GET_IGNORED_FILES');\n        const isValidFile = source =>\n            isFile(source) ? !ignoredFiles.includes(source.name.toLowerCase()) : !isEmpty(source);\n        const validItems = items.filter(isValidFile);\n\n        const promises = validItems.map(\n            source =>\n                new Promise((resolve, reject) => {\n                    dispatch('ADD_ITEM', {\n                        interactionMethod,\n                        source: source.source || source,\n                        success: resolve,\n                        failure: reject,\n                        index: currentIndex++,\n                        options: source.options || {},\n                    });\n                })\n        );\n\n        Promise.all(promises)\n            .then(success)\n            .catch(failure);\n    },\n\n    /**\n     * @param source\n     * @param index\n     * @param interactionMethod\n     */\n    ADD_ITEM: ({\n        source,\n        index = -1,\n        interactionMethod,\n        success = () => {},\n        failure = () => {},\n        options = {},\n    }) => {\n        // if no source supplied\n        if (isEmpty(source)) {\n            failure({\n                error: createResponse('error', 0, 'No source'),\n                file: null,\n            });\n            return;\n        }\n\n        // filter out invalid file items, used to filter dropped directory contents\n        if (isFile(source) && state.options.ignoredFiles.includes(source.name.toLowerCase())) {\n            // fail silently\n            return;\n        }\n\n        // test if there's still room in the list of files\n        if (!hasRoomForItem(state)) {\n            // if multiple allowed, we can't replace\n            // or if only a single item is allowed but we're not allowed to replace it we exit\n            if (\n                state.options.allowMultiple ||\n                (!state.options.allowMultiple && !state.options.allowReplace)\n            ) {\n                const error = createResponse('warning', 0, 'Max files');\n\n                dispatch('DID_THROW_MAX_FILES', {\n                    source,\n                    error,\n                });\n\n                failure({ error, file: null });\n\n                return;\n            }\n\n            // let's replace the item\n            // id of first item we're about to remove\n            const item = getActiveItems(state.items)[0];\n\n            // if has been processed remove it from the server as well\n            if (\n                item.status === ItemStatus.PROCESSING_COMPLETE ||\n                item.status === ItemStatus.PROCESSING_REVERT_ERROR\n            ) {\n                const forceRevert = query('GET_FORCE_REVERT');\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    forceRevert\n                )\n                    .then(() => {\n                        if (!forceRevert) return;\n\n                        // try to add now\n                        dispatch('ADD_ITEM', {\n                            source,\n                            index,\n                            interactionMethod,\n                            success,\n                            failure,\n                            options,\n                        });\n                    })\n                    .catch(() => {}); // no need to handle this catch state for now\n\n                if (forceRevert) return;\n            }\n\n            // remove first item as it will be replaced by this item\n            dispatch('REMOVE_ITEM', { query: item.id });\n        }\n\n        // where did the file originate\n        const origin =\n            options.type === 'local'\n                ? FileOrigin.LOCAL\n                : options.type === 'limbo'\n                ? FileOrigin.LIMBO\n                : FileOrigin.INPUT;\n\n        // create a new blank item\n        const item = createItem(\n            // where did this file come from\n            origin,\n\n            // an input file never has a server file reference\n            origin === FileOrigin.INPUT ? null : source,\n\n            // file mock data, if defined\n            options.file\n        );\n\n        // set initial meta data\n        Object.keys(options.metadata || {}).forEach(key => {\n            item.setMetadata(key, options.metadata[key]);\n        });\n\n        // created the item, let plugins add methods\n        applyFilters('DID_CREATE_ITEM', item, { query, dispatch });\n\n        // where to insert new items\n        const itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n\n        // adjust index if is not allowed to pick location\n        if (!state.options.itemInsertLocationFreedom) {\n            index = itemInsertLocation === 'before' ? -1 : state.items.length;\n        }\n\n        // add item to list\n        insertItem(state.items, item, index);\n\n        // sort items in list\n        if (isFunction(itemInsertLocation) && source) {\n            sortItems(state, itemInsertLocation);\n        }\n\n        // get a quick reference to the item id\n        const id = item.id;\n\n        // observe item events\n        item.on('init', () => {\n            dispatch('DID_INIT_ITEM', { id });\n        });\n\n        item.on('load-init', () => {\n            dispatch('DID_START_ITEM_LOAD', { id });\n        });\n\n        item.on('load-meta', () => {\n            dispatch('DID_UPDATE_ITEM_META', { id });\n        });\n\n        item.on('load-progress', progress => {\n            dispatch('DID_UPDATE_ITEM_LOAD_PROGRESS', { id, progress });\n        });\n\n        item.on('load-request-error', error => {\n            const mainStatus = dynamicLabel(state.options.labelFileLoadError)(error);\n\n            // is client error, no way to recover\n            if (error.code >= 400 && error.code < 500) {\n                dispatch('DID_THROW_ITEM_INVALID', {\n                    id,\n                    error,\n                    status: {\n                        main: mainStatus,\n                        sub: `${error.code} (${error.body})`,\n                    },\n                });\n\n                // reject the file so can be dealt with through API\n                failure({ error, file: createItemAPI(item) });\n                return;\n            }\n\n            // is possible server error, so might be possible to retry\n            dispatch('DID_THROW_ITEM_LOAD_ERROR', {\n                id,\n                error,\n                status: {\n                    main: mainStatus,\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('load-file-error', error => {\n            dispatch('DID_THROW_ITEM_INVALID', {\n                id,\n                error: error.status,\n                status: error.status,\n            });\n            failure({ error: error.status, file: createItemAPI(item) });\n        });\n\n        item.on('load-abort', () => {\n            dispatch('REMOVE_ITEM', { query: id });\n        });\n\n        item.on('load-skip', () => {\n            item.on('metadata-update', change => {\n                if (!isFile(item.file)) return;\n                dispatch('DID_UPDATE_ITEM_METADATA', { id, change });\n            });\n\n            dispatch('COMPLETE_LOAD_ITEM', {\n                query: id,\n                item,\n                data: {\n                    source,\n                    success,\n                },\n            });\n        });\n\n        item.on('load', () => {\n            const handleAdd = shouldAdd => {\n                // no should not add this file\n                if (!shouldAdd) {\n                    dispatch('REMOVE_ITEM', {\n                        query: id,\n                    });\n                    return;\n                }\n\n                // now interested in metadata updates\n                item.on('metadata-update', change => {\n                    dispatch('DID_UPDATE_ITEM_METADATA', { id, change });\n                });\n\n                // let plugins decide if the output data should be prepared at this point\n                // means we'll do this and wait for idle state\n                applyFilterChain('SHOULD_PREPARE_OUTPUT', false, { item, query }).then(\n                    shouldPrepareOutput => {\n                        // plugins determined the output data should be prepared (or not), can be adjusted with beforePrepareOutput hook\n                        const beforePrepareFile = query('GET_BEFORE_PREPARE_FILE');\n                        if (beforePrepareFile)\n                            shouldPrepareOutput = beforePrepareFile(item, shouldPrepareOutput);\n\n                        const loadComplete = () => {\n                            dispatch('COMPLETE_LOAD_ITEM', {\n                                query: id,\n                                item,\n                                data: {\n                                    source,\n                                    success,\n                                },\n                            });\n\n                            listUpdated(dispatch, state);\n                        };\n\n                        // exit\n                        if (shouldPrepareOutput) {\n                            // wait for idle state and then run PREPARE_OUTPUT\n                            dispatch(\n                                'REQUEST_PREPARE_OUTPUT',\n                                {\n                                    query: id,\n                                    item,\n                                    success: file => {\n                                        dispatch('DID_PREPARE_OUTPUT', { id, file });\n                                        loadComplete();\n                                    },\n                                },\n                                true\n                            );\n\n                            return;\n                        }\n\n                        loadComplete();\n                    }\n                );\n            };\n\n            // item loaded, allow plugins to\n            // - read data (quickly)\n            // - add metadata\n            applyFilterChain('DID_LOAD_ITEM', item, { query, dispatch })\n                .then(() => {\n                    optionalPromise(query('GET_BEFORE_ADD_FILE'), createItemAPI(item)).then(\n                        handleAdd\n                    );\n                })\n                .catch(e => {\n                    if (!e || !e.error || !e.status) return handleAdd(false);\n                    dispatch('DID_THROW_ITEM_INVALID', {\n                        id,\n                        error: e.error,\n                        status: e.status,\n                    });\n                });\n        });\n\n        item.on('process-start', () => {\n            dispatch('DID_START_ITEM_PROCESSING', { id });\n        });\n\n        item.on('process-progress', progress => {\n            dispatch('DID_UPDATE_ITEM_PROCESS_PROGRESS', { id, progress });\n        });\n\n        item.on('process-error', error => {\n            dispatch('DID_THROW_ITEM_PROCESSING_ERROR', {\n                id,\n                error,\n                status: {\n                    main: dynamicLabel(state.options.labelFileProcessingError)(error),\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('process-revert-error', error => {\n            dispatch('DID_THROW_ITEM_PROCESSING_REVERT_ERROR', {\n                id,\n                error,\n                status: {\n                    main: dynamicLabel(state.options.labelFileProcessingRevertError)(error),\n                    sub: state.options.labelTapToRetry,\n                },\n            });\n        });\n\n        item.on('process-complete', serverFileReference => {\n            dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                id,\n                error: null,\n                serverFileReference,\n            });\n            dispatch('DID_DEFINE_VALUE', { id, value: serverFileReference });\n        });\n\n        item.on('process-abort', () => {\n            dispatch('DID_ABORT_ITEM_PROCESSING', { id });\n        });\n\n        item.on('process-revert', () => {\n            dispatch('DID_REVERT_ITEM_PROCESSING', { id });\n            dispatch('DID_DEFINE_VALUE', { id, value: null });\n        });\n\n        // let view know the item has been inserted\n        dispatch('DID_ADD_ITEM', { id, index, interactionMethod });\n\n        listUpdated(dispatch, state);\n\n        // start loading the source\n        const { url, load, restore, fetch } = state.options.server || {};\n\n        item.load(\n            source,\n\n            // this creates a function that loads the file based on the type of file (string, base64, blob, file) and location of file (local, remote, limbo)\n            createFileLoader(\n                origin === FileOrigin.INPUT\n                    ? // input, if is remote, see if should use custom fetch, else use default fetchBlob\n                      isString(source) && isExternalURL(source)\n                        ? fetch\n                            ? createFetchFunction(url, fetch)\n                            : fetchBlob // remote url\n                        : fetchBlob // try to fetch url\n                    : // limbo or local\n                    origin === FileOrigin.LIMBO\n                    ? createFetchFunction(url, restore) // limbo\n                    : createFetchFunction(url, load) // local\n            ),\n\n            // called when the file is loaded so it can be piped through the filters\n            (file, success, error) => {\n                // let's process the file\n                applyFilterChain('LOAD_FILE', file, { query })\n                    .then(success)\n                    .catch(error);\n            }\n        );\n    },\n\n    REQUEST_PREPARE_OUTPUT: ({ item, success, failure = () => {} }) => {\n        // error response if item archived\n        const err = {\n            error: createResponse('error', 0, 'Item not found'),\n            file: null,\n        };\n\n        // don't handle archived items, an item could have been archived (load aborted) while waiting to be prepared\n        if (item.archived) return failure(err);\n\n        // allow plugins to alter the file data\n        applyFilterChain('PREPARE_OUTPUT', item.file, { query, item }).then(result => {\n            applyFilterChain('COMPLETE_PREPARE_OUTPUT', result, { query, item }).then(result => {\n                // don't handle archived items, an item could have been archived (load aborted) while being prepared\n                if (item.archived) return failure(err);\n\n                // we done!\n                success(result);\n            });\n        });\n    },\n\n    COMPLETE_LOAD_ITEM: ({ item, data }) => {\n        const { success, source } = data;\n\n        // sort items in list\n        const itemInsertLocation = query('GET_ITEM_INSERT_LOCATION');\n        if (isFunction(itemInsertLocation) && source) {\n            sortItems(state, itemInsertLocation);\n        }\n\n        // let interface know the item has loaded\n        dispatch('DID_LOAD_ITEM', {\n            id: item.id,\n            error: null,\n            serverFileReference: item.origin === FileOrigin.INPUT ? null : source,\n        });\n\n        // item has been successfully loaded and added to the\n        // list of items so can now be safely returned for use\n        success(createItemAPI(item));\n\n        // if this is a local server file we need to show a different state\n        if (item.origin === FileOrigin.LOCAL) {\n            dispatch('DID_LOAD_LOCAL_ITEM', { id: item.id });\n            return;\n        }\n\n        // if is a temp server file we prevent async upload call here (as the file is already on the server)\n        if (item.origin === FileOrigin.LIMBO) {\n            dispatch('DID_COMPLETE_ITEM_PROCESSING', {\n                id: item.id,\n                error: null,\n                serverFileReference: source,\n            });\n\n            dispatch('DID_DEFINE_VALUE', {\n                id: item.id,\n                value: item.serverId || source,\n            });\n            return;\n        }\n\n        // id we are allowed to upload the file immediately, lets do it\n        if (query('IS_ASYNC') && state.options.instantUpload) {\n            dispatch('REQUEST_ITEM_PROCESSING', { query: item.id });\n        }\n    },\n\n    RETRY_ITEM_LOAD: getItemByQueryFromState(state, item => {\n        // try loading the source one more time\n        item.retryLoad();\n    }),\n\n    REQUEST_ITEM_PREPARE: getItemByQueryFromState(state, (item, success, failure) => {\n        dispatch(\n            'REQUEST_PREPARE_OUTPUT',\n            {\n                query: item.id,\n                item,\n                success: file => {\n                    dispatch('DID_PREPARE_OUTPUT', { id: item.id, file });\n                    success({\n                        file: item,\n                        output: file,\n                    });\n                },\n                failure,\n            },\n            true\n        );\n    }),\n\n    REQUEST_ITEM_PROCESSING: getItemByQueryFromState(state, (item, success, failure) => {\n        // cannot be queued (or is already queued)\n        const itemCanBeQueuedForProcessing =\n            // waiting for something\n            item.status === ItemStatus.IDLE ||\n            // processing went wrong earlier\n            item.status === ItemStatus.PROCESSING_ERROR;\n\n        // not ready to be processed\n        if (!itemCanBeQueuedForProcessing) {\n            const processNow = () =>\n                dispatch('REQUEST_ITEM_PROCESSING', { query: item, success, failure });\n\n            const process = () => (document.hidden ? processNow() : setTimeout(processNow, 32));\n\n            // if already done processing or tried to revert but didn't work, try again\n            if (\n                item.status === ItemStatus.PROCESSING_COMPLETE ||\n                item.status === ItemStatus.PROCESSING_REVERT_ERROR\n            ) {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                )\n                    .then(process)\n                    .catch(() => {}); // don't continue with processing if something went wrong\n            } else if (item.status === ItemStatus.PROCESSING) {\n                item.abortProcessing().then(process);\n            }\n\n            return;\n        }\n\n        // already queued for processing\n        if (item.status === ItemStatus.PROCESSING_QUEUED) return;\n\n        item.requestProcessing();\n\n        dispatch('DID_REQUEST_ITEM_PROCESSING', { id: item.id });\n\n        dispatch('PROCESS_ITEM', { query: item, success, failure }, true);\n    }),\n\n    PROCESS_ITEM: getItemByQueryFromState(state, (item, success, failure) => {\n        const maxParallelUploads = query('GET_MAX_PARALLEL_UPLOADS');\n        const totalCurrentUploads = query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING).length;\n\n        // queue and wait till queue is freed up\n        if (totalCurrentUploads === maxParallelUploads) {\n            // queue for later processing\n            state.processingQueue.push({\n                id: item.id,\n                success,\n                failure,\n            });\n\n            // stop it!\n            return;\n        }\n\n        // if was not queued or is already processing exit here\n        if (item.status === ItemStatus.PROCESSING) return;\n\n        const processNext = () => {\n            // process queueud items\n            const queueEntry = state.processingQueue.shift();\n\n            // no items left\n            if (!queueEntry) return;\n\n            // get item reference\n            const { id, success, failure } = queueEntry;\n            const itemReference = getItemByQuery(state.items, id);\n\n            // if item was archived while in queue, jump to next\n            if (!itemReference || itemReference.archived) {\n                processNext();\n                return;\n            }\n\n            // process queued item\n            dispatch('PROCESS_ITEM', { query: id, success, failure }, true);\n        };\n\n        // we done function\n        item.onOnce('process-complete', () => {\n            success(createItemAPI(item));\n            processNext();\n\n            // if origin is local, and we're instant uploading, trigger remove of original\n            // as revert will remove file from list\n            const server = state.options.server;\n            const instantUpload = state.options.instantUpload;\n            if (instantUpload && item.origin === FileOrigin.LOCAL && isFunction(server.remove)) {\n                const noop = () => {};\n                item.origin = FileOrigin.LIMBO;\n                state.options.server.remove(item.source, noop, noop);\n            }\n\n            // All items processed? No errors?\n            const allItemsProcessed =\n                query('GET_ITEMS_BY_STATUS', ItemStatus.PROCESSING_COMPLETE).length ===\n                state.items.length;\n            if (allItemsProcessed) {\n                dispatch('DID_COMPLETE_ITEM_PROCESSING_ALL');\n            }\n        });\n\n        // we error function\n        item.onOnce('process-error', error => {\n            failure({ error, file: createItemAPI(item) });\n            processNext();\n        });\n\n        // abort function\n        item.onOnce('process-abort', () => {\n            processNext();\n        });\n\n        // start file processing\n        const options = state.options;\n        item.process(\n            createFileProcessor(\n                createProcessorFunction(options.server.url, options.server.process, options.name, {\n                    chunkTransferId: item.transferId,\n                    chunkServer: options.server.patch,\n                    chunkUploads: options.chunkUploads,\n                    chunkForce: options.chunkForce,\n                    chunkSize: options.chunkSize,\n                    chunkRetryDelays: options.chunkRetryDelays,\n                }),\n                {\n                    allowMinimumUploadDuration: query('GET_ALLOW_MINIMUM_UPLOAD_DURATION'),\n                }\n            ),\n            // called when the file is about to be processed so it can be piped through the transform filters\n            (file, success, error) => {\n                // allow plugins to alter the file data\n                applyFilterChain('PREPARE_OUTPUT', file, { query, item })\n                    .then(file => {\n                        dispatch('DID_PREPARE_OUTPUT', { id: item.id, file });\n\n                        success(file);\n                    })\n                    .catch(error);\n            }\n        );\n    }),\n\n    RETRY_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        dispatch('REQUEST_ITEM_PROCESSING', { query: item });\n    }),\n\n    REQUEST_REMOVE_ITEM: getItemByQueryFromState(state, item => {\n        optionalPromise(query('GET_BEFORE_REMOVE_FILE'), createItemAPI(item)).then(shouldRemove => {\n            if (!shouldRemove) {\n                return;\n            }\n            dispatch('REMOVE_ITEM', { query: item });\n        });\n    }),\n\n    RELEASE_ITEM: getItemByQueryFromState(state, item => {\n        item.release();\n    }),\n\n    REMOVE_ITEM: getItemByQueryFromState(state, (item, success, failure, options) => {\n        const removeFromView = () => {\n            // get id reference\n            const id = item.id;\n\n            // archive the item, this does not remove it from the list\n            getItemById(state.items, id).archive();\n\n            // tell the view the item has been removed\n            dispatch('DID_REMOVE_ITEM', { error: null, id, item });\n\n            // now the list has been modified\n            listUpdated(dispatch, state);\n\n            // correctly removed\n            success(createItemAPI(item));\n        };\n\n        // if this is a local file and the `server.remove` function has been configured,\n        // send source there so dev can remove file from server\n        const server = state.options.server;\n        if (\n            item.origin === FileOrigin.LOCAL &&\n            server &&\n            isFunction(server.remove) &&\n            options.remove !== false\n        ) {\n            dispatch('DID_START_ITEM_REMOVE', { id: item.id });\n\n            server.remove(\n                item.source,\n                () => removeFromView(),\n                status => {\n                    dispatch('DID_THROW_ITEM_REMOVE_ERROR', {\n                        id: item.id,\n                        error: createResponse('error', 0, status, null),\n                        status: {\n                            main: dynamicLabel(state.options.labelFileRemoveError)(status),\n                            sub: state.options.labelTapToRetry,\n                        },\n                    });\n                }\n            );\n        } else {\n            // if is requesting revert and can revert need to call revert handler (not calling request_ because that would also trigger beforeRemoveHook)\n            if (\n                (options.revert && item.origin !== FileOrigin.LOCAL && item.serverId !== null) ||\n                // if chunked uploads are enabled and we're uploading in chunks for this specific file\n                // or if the file isn't big enough for chunked uploads but chunkForce is set then call\n                // revert before removing from the view...\n                (state.options.chunkUploads && item.file.size > state.options.chunkSize) ||\n                (state.options.chunkUploads && state.options.chunkForce)\n            ) {\n                item.revert(\n                    createRevertFunction(state.options.server.url, state.options.server.revert),\n                    query('GET_FORCE_REVERT')\n                );\n            }\n\n            // can now safely remove from view\n            removeFromView();\n        }\n    }),\n\n    ABORT_ITEM_LOAD: getItemByQueryFromState(state, item => {\n        item.abortLoad();\n    }),\n\n    ABORT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        // test if is already processed\n        if (item.serverId) {\n            dispatch('REVERT_ITEM_PROCESSING', { id: item.id });\n            return;\n        }\n\n        // abort\n        item.abortProcessing().then(() => {\n            const shouldRemove = state.options.instantUpload;\n            if (shouldRemove) {\n                dispatch('REMOVE_ITEM', { query: item.id });\n            }\n        });\n    }),\n\n    REQUEST_REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        // not instant uploading, revert immediately\n        if (!state.options.instantUpload) {\n            dispatch('REVERT_ITEM_PROCESSING', { query: item });\n            return;\n        }\n\n        // if we're instant uploading the file will also be removed if we revert,\n        // so if a before remove file hook is defined we need to run it now\n        const handleRevert = shouldRevert => {\n            if (!shouldRevert) return;\n            dispatch('REVERT_ITEM_PROCESSING', { query: item });\n        };\n\n        const fn = query('GET_BEFORE_REMOVE_FILE');\n        if (!fn) {\n            return handleRevert(true);\n        }\n\n        const requestRemoveResult = fn(createItemAPI(item));\n        if (requestRemoveResult == null) {\n            // undefined or null\n            return handleRevert(true);\n        }\n\n        if (typeof requestRemoveResult === 'boolean') {\n            return handleRevert(requestRemoveResult);\n        }\n\n        if (typeof requestRemoveResult.then === 'function') {\n            requestRemoveResult.then(handleRevert);\n        }\n    }),\n\n    REVERT_ITEM_PROCESSING: getItemByQueryFromState(state, item => {\n        item.revert(\n            createRevertFunction(state.options.server.url, state.options.server.revert),\n            query('GET_FORCE_REVERT')\n        )\n            .then(() => {\n                const shouldRemove = state.options.instantUpload || isMockItem(item);\n                if (shouldRemove) {\n                    dispatch('REMOVE_ITEM', { query: item.id });\n                }\n            })\n            .catch(() => {});\n    }),\n\n    SET_OPTIONS: ({ options }) => {\n        // get all keys passed\n        const optionKeys = Object.keys(options);\n\n        // get prioritized keyed to include (remove once not in options object)\n        const prioritizedOptionKeys = PrioritizedOptions.filter(key => optionKeys.includes(key));\n\n        // order the keys, prioritized first, then rest\n        const orderedOptionKeys = [\n            // add prioritized first if passed to options, else remove\n            ...prioritizedOptionKeys,\n\n            // prevent duplicate keys\n            ...Object.keys(options).filter(key => !prioritizedOptionKeys.includes(key)),\n        ];\n\n        // dispatch set event for each option\n        orderedOptionKeys.forEach(key => {\n            dispatch(`SET_${fromCamels(key, '_').toUpperCase()}`, {\n                value: options[key],\n            });\n        });\n    },\n});\n\nconst PrioritizedOptions = [\n    'server', // must be processed before \"files\"\n];\n"
  },
  {
    "path": "src/js/app/enum/ChunkStatus.js",
    "content": "export const ChunkStatus = {\n\tQUEUED: 0,\n\tCOMPLETE: 1,\n\tPROCESSING: 2,\n\tERROR: 3,\n\tWAITING: 4\n};"
  },
  {
    "path": "src/js/app/enum/FileOrigin.js",
    "content": "export const FileOrigin = {\n    INPUT:1,\n    LIMBO:2,\n    LOCAL:3\n};"
  },
  {
    "path": "src/js/app/enum/InteractionMethod.js",
    "content": "export const InteractionMethod = {\n    API: 1,\n    DROP: 2,\n    BROWSE: 3,\n    PASTE: 4,\n    NONE: 5\n};\n"
  },
  {
    "path": "src/js/app/enum/ItemStatus.js",
    "content": "export const ItemStatus = {\n    INIT: 1,\n    IDLE: 2,\n    PROCESSING_QUEUED: 9,\n    PROCESSING: 3,\n    PROCESSING_COMPLETE: 5,\n    PROCESSING_ERROR: 6,\n    PROCESSING_REVERT_ERROR: 10,\n    LOADING: 7,\n    LOAD_ERROR: 8\n};\n"
  },
  {
    "path": "src/js/app/enum/Key.js",
    "content": "export const Key = {\n    ENTER: 13,\n    SPACE: 32\n};\n"
  },
  {
    "path": "src/js/app/enum/Status.js",
    "content": "export const Status = {\n    EMPTY: 0,\n    IDLE: 1, // waiting\n    ERROR: 2, // a file is in error state\n    BUSY: 3, // busy processing or loading\n    READY: 4 // all files uploaded\n};"
  },
  {
    "path": "src/js/app/enum/Type.js",
    "content": "export const Type = {\n    BOOLEAN: 'boolean',\n    INT: 'int',\n    NUMBER: 'number',\n    STRING: 'string',\n    ARRAY: 'array',\n    OBJECT: 'object',\n    FUNCTION: 'function',\n    ACTION: 'action',\n    SERVER_API: 'serverapi',\n    REGEX: 'regex'\n};\n"
  },
  {
    "path": "src/js/app/frame/createPainter.js",
    "content": "export const createPainter = (read, write, fps = 60) => {\n\n    const name = '__framePainter';\n\n    // set global painter\n    if (window[name]) {\n        window[name].readers.push(read);\n        window[name].writers.push(write);\n        return;\n    }\n    \n    window[name] = {\n        readers:[read],\n        writers:[write]\n    }\n\n    const painter = window[name];\n\n    const interval = 1000 / fps;\n    let last = null;\n    let id = null;\n    let requestTick = null;\n    let cancelTick = null;\n\n    const setTimerType = () => {\n        if (document.hidden) {\n            requestTick = () => window.setTimeout(() => tick(performance.now()), interval);\n            cancelTick = () => window.clearTimeout(id);\n        }\n        else {\n            requestTick = () => window.requestAnimationFrame(tick);\n            cancelTick = () => window.cancelAnimationFrame(id);\n        }\n    }\n\n    document.addEventListener('visibilitychange', () => {\n        if (cancelTick) cancelTick();\n        setTimerType();\n        tick(performance.now());\n    });\n\n    const tick = ts => {\n\n        // queue next tick\n        id = requestTick(tick);\n\n        // limit fps\n        if (!last) {\n            last = ts;\n        }\n\n        const delta = ts - last;\n\n        if (delta <= interval) {\n            // skip frame\n            return;\n        }\n\n        // align next frame\n        last = ts - delta % interval;\n\n        // update view\n        painter.readers.forEach(read => read());\n        painter.writers.forEach(write => write(ts));\n    };\n\n    setTimerType();\n    tick(performance.now());\n\n    return {\n        pause: () => {\n            cancelTick(id);\n        }\n    };\n};\n"
  },
  {
    "path": "src/js/app/frame/createRoute.js",
    "content": "export const createRoute = (routes, fn) => ({ root, props, actions = [], timestamp, shouldOptimize }) => {\n    actions.filter(action => routes[action.type])\n        .forEach(action =>\n            routes[action.type]({ root, props, action: action.data, timestamp, shouldOptimize })\n        );\n    if (fn) {\n        fn({ root, props, actions, timestamp, shouldOptimize });\n    };\n};\n"
  },
  {
    "path": "src/js/app/frame/createStore.js",
    "content": "export const createStore = (initialState, queries = [], actions = []) => {\n    // internal state\n    const state = {\n        ...initialState\n    };\n\n    // contains all actions for next frame, is clear when actions are requested\n    const actionQueue = [];\n    const dispatchQueue = [];\n\n    // returns a duplicate of the current state\n    const getState = () => ({ ...state });\n\n    // returns a duplicate of the actions array and clears the actions array\n    const processActionQueue = () => {\n        // create copy of actions queue\n        const queue = [...actionQueue];\n        \n        // clear actions queue (we don't want no double actions)\n        actionQueue.length = 0;\n\n        return queue;\n    };\n\n    // processes actions that might block the main UI thread\n    const processDispatchQueue = () => {\n        // create copy of actions queue\n        const queue = [...dispatchQueue];\n\n        // clear actions queue (we don't want no double actions)\n        dispatchQueue.length = 0;\n\n        // now dispatch these actions\n        queue.forEach(({ type, data }) => {\n            dispatch(type, data);\n        });\n    };\n\n    // adds a new action, calls its handler and\n    const dispatch = (type, data, isBlocking) => {\n\n        // is blocking action (should never block if document is hidden)\n        if (isBlocking && !document.hidden) {\n            dispatchQueue.push({ type, data });\n            return;\n        }\n\n        // if this action has a handler, handle the action\n        if (actionHandlers[type]) {\n            actionHandlers[type](data);\n        }\n\n        // now add action\n        actionQueue.push({\n            type,\n            data\n        });\n    };\n\n    const query = (str, ...args) =>\n        queryHandles[str] ? queryHandles[str](...args) : null;\n\n    const api = {\n        getState,\n        processActionQueue,\n        processDispatchQueue,\n        dispatch,\n        query\n    };\n\n    let queryHandles = {};\n    queries.forEach(query => {\n        queryHandles = {\n            ...query(state),\n            ...queryHandles\n        };\n    });\n\n    let actionHandlers = {};\n    actions.forEach(action => {\n        actionHandlers = {\n            ...action(dispatch, query, state),\n            ...actionHandlers\n        };\n    });\n\n    return api;\n};\n"
  },
  {
    "path": "src/js/app/frame/createView.js",
    "content": "import { createObject } from '../../utils/createObject';\nimport { createElement } from './utils/createElement';\nimport { appendChild } from './utils/appendChild';\nimport { appendChildView } from './utils/appendChildView';\nimport { removeChildView } from './utils/removeChildView';\nimport { getChildCount } from './utils/getChildCount';\nimport { getViewRect } from './utils/getViewRect';\nimport { Mixins } from './mixins/index';\nimport { updateRect } from './utils/updateRect';\n\nexport const createView =\n    // default view definition\n    ({\n        // element definition\n        tag = 'div',\n        name = null,\n        attributes = {},\n\n        // view interaction\n        read = () => {},\n        write = () => {},\n        create = () => {},\n        destroy = () => {},\n\n        // hooks\n        filterFrameActionsForChild = (child, actions) => actions,\n        didCreateView = () => {},\n        didWriteView = () => {},\n\n        // rect related\n        ignoreRect = false,\n        ignoreRectUpdate = false,\n\n        // mixins\n        mixins = []\n    } = {}) => (\n        // each view requires reference to store\n        store,\n        // specific properties for this view\n        props = {}\n    ) => {\n            // root element should not be changed\n            const element = createElement(tag, `filepond--${name}`, attributes);\n\n            // style reference should also not be changed\n            const style = window.getComputedStyle(element, null);\n\n            // element rectangle\n            const rect = updateRect();\n            let frameRect = null;\n\n            // rest state\n            let isResting = false;\n\n            // pretty self explanatory\n            const childViews = [];\n\n            // loaded mixins\n            const activeMixins = [];\n\n            // references to created children\n            const ref = {};\n\n            // state used for each instance\n            const state = {};\n\n            // list of writers that will be called to update this view\n            const writers = [\n                write // default writer\n            ];\n\n            const readers = [\n                read // default reader\n            ];\n\n            const destroyers = [\n                destroy // default destroy\n            ];\n\n            // core view methods\n            const getElement = () => element;\n            const getChildViews = () => childViews.concat();\n            const getReference = () => ref;\n            const createChildView = store => (view, props) => view(store, props);\n            const getRect = () => {\n                if (frameRect) {\n                    return frameRect;\n                }\n                frameRect = getViewRect(rect, childViews, [0, 0], [1, 1])\n                return frameRect;\n            };\n            const getStyle = () => style;\n\n            /**\n             * Read data from DOM\n             * @private\n             */\n            const _read = () => {\n\n                frameRect = null;\n\n                // read child views\n                childViews.forEach(child => child._read());\n\n                const shouldUpdate = !(ignoreRectUpdate && rect.width && rect.height)\n                if (shouldUpdate) {\n                    updateRect(rect, element, style);\n                }\n\n                // readers\n                const api = { root: internalAPI, props, rect };\n                readers.forEach(reader =>\n                    reader(api)\n                );\n\n            };\n\n            /**\n             * Write data to DOM\n             * @private\n             */\n            const _write = (ts, frameActions, shouldOptimize) => {\n                // if no actions, we assume that the view is resting\n                let resting = frameActions.length === 0;\n\n                // writers\n                writers.forEach(writer => {\n                    const writerResting = writer({\n                        props,\n                        root: internalAPI,\n                        actions: frameActions,\n                        timestamp: ts,\n                        shouldOptimize\n                    });\n                    if (writerResting === false) {\n                        resting = false;\n                    }\n                });\n\n                // run mixins\n                activeMixins.forEach(mixin => {\n                    // if one of the mixins is still busy after write operation, we are not resting\n                    const mixinResting = mixin.write(ts);\n                    if (mixinResting === false) {\n                        resting = false;\n                    }\n                });\n\n                // updates child views that are currently attached to the DOM\n                childViews\n                    .filter(child => !!child.element.parentNode)\n                    .forEach(child => {\n                        // if a child view is not resting, we are not resting\n                        const childResting = child._write(\n                            ts,\n                            filterFrameActionsForChild(child, frameActions),\n                            shouldOptimize\n                        );\n                        if (!childResting) {\n                            resting = false;\n                        }\n                    });\n                    \n                // append new elements to DOM and update those\n                childViews\n                    //.filter(child => !child.element.parentNode)\n                    .forEach((child, index) => {\n\n                        // skip \n                        if (child.element.parentNode) {\n                            return;\n                        }\n\n                        // append to DOM\n                        internalAPI.appendChild(child.element, index);\n\n                        // call read (need to know the size of these elements)\n                        child._read();\n\n                        // re-call write\n                        child._write(\n                            ts,\n                            filterFrameActionsForChild(child, frameActions),\n                            shouldOptimize\n                        );\n\n                        // we just added somthing to the dom, no rest\n                        resting = false;\n                    });\n\n                // update resting state\n                isResting = resting;\n\n                didWriteView({\n                    props,\n                    root: internalAPI,\n                    actions: frameActions,\n                    timestamp: ts\n                });\n\n                // let parent know if we are resting\n                return resting;\n            };\n\n            const _destroy = () => {\n                activeMixins.forEach(mixin => mixin.destroy());\n                destroyers.forEach(destroyer => { destroyer({ root: internalAPI, props })});\n                childViews.forEach(child => child._destroy());\n            };\n\n            // sharedAPI\n            const sharedAPIDefinition = {\n                element: {\n                    get: getElement\n                },\n                style: {\n                    get: getStyle\n                },\n                childViews: {\n                    get: getChildViews\n                }\n            };\n\n            // private API definition\n            const internalAPIDefinition = { ...sharedAPIDefinition,\n                rect: {\n                    get: getRect\n                },\n\n                // access to custom children references\n                ref: {\n                    get: getReference\n                },\n\n                // dom modifiers\n                is: needle => name === needle,\n                appendChild: appendChild(element),\n                createChildView: createChildView(store),\n                linkView: view => { childViews.push(view); return view },\n                unlinkView: view => { childViews.splice(childViews.indexOf(view), 1); },\n                appendChildView: appendChildView(element, childViews),\n                removeChildView: removeChildView(element, childViews),\n                registerWriter: writer => writers.push(writer),\n                registerReader: reader => readers.push(reader),\n                registerDestroyer: destroyer => destroyers.push(destroyer),\n                invalidateLayout: () => element.layoutCalculated = false,\n\n                // access to data store\n                dispatch: store.dispatch,\n                query: store.query\n            };\n\n            // public view API methods\n            const externalAPIDefinition = {\n                element: {\n                    get: getElement\n                },\n                childViews: {\n                    get: getChildViews\n                },\n                rect: {\n                    get: getRect\n                },\n                resting: {\n                    get: () => isResting\n                },\n                isRectIgnored: () => ignoreRect,\n                _read,\n                _write,\n                _destroy\n            };\n\n            // mixin API methods\n            const mixinAPIDefinition = { ...sharedAPIDefinition,\n                rect: {\n                    get: () => rect\n                }\n            };\n\n            // add mixin functionality\n            Object.keys(mixins).sort((a,b) => {\n                // move styles to the back of the mixin list (so adjustments of other mixins are applied to the props correctly)\n                if (a === 'styles') {\n                    return 1;\n                }\n                else if (b ==='styles') {\n                    return -1;\n                }\n                return 0;\n            }).forEach(key => {\n\n                const mixinAPI = Mixins[key]({\n                    mixinConfig: mixins[key],\n                    viewProps: props,\n                    viewState: state,\n                    viewInternalAPI: internalAPIDefinition,\n                    viewExternalAPI: externalAPIDefinition,\n                    view: createObject(mixinAPIDefinition)\n                });\n\n                if (mixinAPI) {\n                    activeMixins.push(mixinAPI);\n                }\n            })\n\n            // construct private api\n            const internalAPI = createObject(internalAPIDefinition);\n\n            // create the view\n            create({\n                root: internalAPI,\n                props\n            });\n\n            // append created child views to root node\n            const childCount = getChildCount(element); // need to know the current child count so appending happens in correct order\n            childViews.forEach((child, index) => {\n                internalAPI.appendChild(child.element, childCount + index);\n            });\n\n            // call did create\n            didCreateView(internalAPI);\n\n            // expose public api\n            return createObject(externalAPIDefinition);\n        };\n"
  },
  {
    "path": "src/js/app/frame/index.js",
    "content": "import { createStore } from './createStore';\nimport { createView } from './createView';\nimport { createPainter } from './createPainter';\nimport { createRoute } from './createRoute';\n\nexport { createRoute, createPainter, createStore, createView };"
  },
  {
    "path": "src/js/app/frame/mixins/animations.js",
    "content": "import { createAnimator } from '../utils/createAnimator';\nimport { forin } from '../../../utils/forin';\nimport { addGetSet } from './utils/addGetSet';\n\n// add to state,\n// add getters and setters to internal and external api (if not set)\n// setup animators\n\nexport const animations = ({\n    mixinConfig,\n    viewProps,\n    viewInternalAPI,\n    viewExternalAPI\n}) => {\n    // initial properties\n    const initialProps = { ...viewProps };\n\n    // list of all active animations\n    const animations = [];\n\n    // setup animators\n    forin(mixinConfig, (property, animation) => {\n        const animator = createAnimator(animation);\n        if (!animator) {\n            return;\n        }\n\n        // when the animator updates, update the view state value\n        animator.onupdate = value => {\n            viewProps[property] = value;\n        };\n\n        // set animator target\n        animator.target = initialProps[property];\n\n        // when value is set, set the animator target value\n        const prop = {\n            key: property,\n            setter: value => {\n\n                // if already at target, we done!\n                if (animator.target === value) {\n                    return;\n                }\n\n                animator.target = value;\n            },\n            getter: () => viewProps[property]\n        };\n\n        // add getters and setters\n        addGetSet([prop], [viewInternalAPI, viewExternalAPI], viewProps, true);\n\n        // add it to the list for easy updating from the _write method\n        animations.push(animator);\n    });\n\n    // expose internal write api\n    return {\n        write: ts => {\n            let skipToEndState = document.hidden;\n            let resting = true;\n            animations.forEach(animation => {\n                if (!animation.resting) resting = false;\n                animation.interpolate(ts, skipToEndState);\n            });\n            return resting;\n        },\n        destroy: () => {}\n    };\n};\n"
  },
  {
    "path": "src/js/app/frame/mixins/apis.js",
    "content": "import { addGetSet } from './utils/addGetSet';\n\n// add to external api and link to props\n\nexport const apis = ({ mixinConfig, viewProps, viewExternalAPI }) => {\n    addGetSet(mixinConfig, viewExternalAPI, viewProps);\n};\n"
  },
  {
    "path": "src/js/app/frame/mixins/index.js",
    "content": "import { animations } from './animations';\nimport { listeners } from './listeners';\nimport { apis } from './apis';\nimport { styles } from './styles';\n\nexport const Mixins = {\n    styles,\n    listeners,\n    animations,\n    apis\n};\n"
  },
  {
    "path": "src/js/app/frame/mixins/listeners.js",
    "content": "import { addEvent } from '../utils/addEvent';\nimport { removeEvent } from '../utils/removeEvent';\n\n// mixin\nexport const listeners = ({\n    mixinConfig,\n    viewProps,\n    viewInternalAPI,\n    viewExternalAPI,\n    viewState,\n    view\n}) => {\n    const events = [];\n\n    const add = addEvent(view.element);\n    const remove = removeEvent(view.element);\n\n    viewExternalAPI.on = (type, fn) => {\n        events.push({\n            type,\n            fn\n        });\n        add(type, fn);\n    };\n\n    viewExternalAPI.off = (type, fn) => {\n        events.splice(\n            events.findIndex(event => event.type === type && event.fn === fn),\n            1\n        );\n        remove(type, fn);\n    };\n\n    return {\n        write: () => {\n            // not busy\n            return true;\n        },\n        destroy: () => {\n            events.forEach(event => {\n                remove(event.type, event.fn);\n            });\n        }\n    };\n};\n"
  },
  {
    "path": "src/js/app/frame/mixins/styles.js",
    "content": "import { getViewRect } from '../utils/getViewRect';\nimport { addGetSet } from './utils/addGetSet';\nimport { isDefined } from '../../../utils/isDefined';\n\n// add to state,\n// add getters and setters to internal and external api (if not set)\n// set initial state based on props in viewProps\n// apply as transforms each frame\n\nconst defaults = {\n    opacity: 1,\n    scaleX: 1,\n    scaleY: 1,\n    translateX: 0,\n    translateY: 0,\n    rotateX: 0,\n    rotateY: 0,\n    rotateZ: 0,\n    originX: 0,\n    originY: 0\n};\n\nexport const styles = ({\n    mixinConfig,\n    viewProps,\n    viewInternalAPI,\n    viewExternalAPI,\n    view\n}) => {\n    // initial props\n    const initialProps = { ...viewProps };\n\n    // current props\n    const currentProps = {};\n\n    // we will add those properties to the external API and link them to the viewState\n    addGetSet(mixinConfig, [viewInternalAPI, viewExternalAPI], viewProps);\n\n    // override rect on internal and external rect getter so it takes in account transforms\n    const getOffset = () => [\n        viewProps['translateX'] || 0,\n        viewProps['translateY'] || 0\n    ];\n    const getScale = () => [viewProps['scaleX'] || 0, viewProps['scaleY'] || 0];\n    const getRect = () =>\n        view.rect\n            ? getViewRect(view.rect, view.childViews, getOffset(), getScale())\n            : null;\n    viewInternalAPI.rect = { get: getRect };\n    viewExternalAPI.rect = { get: getRect };\n\n    // apply view props\n    mixinConfig.forEach(key => {\n        viewProps[key] =\n            typeof initialProps[key] === 'undefined'\n                ? defaults[key]\n                : initialProps[key];\n    });\n\n    // expose api\n    return {\n        write: () => {\n\n            // see if props have changed\n            if (!propsHaveChanged(currentProps, viewProps)) {\n                return;\n            }\n\n            // moves element to correct position on screen\n            applyStyles(view.element, viewProps);\n\n            // store new transforms\n            Object.assign(currentProps, {...viewProps});\n\n            // no longer busy\n            return true;\n        },\n        destroy: () => {}\n    };\n};\n\nconst propsHaveChanged = (currentProps, newProps) => {\n    // different amount of keys\n    if (Object.keys(currentProps).length !== Object.keys(newProps).length) {\n        return true;\n    }\n\n    // lets analyze the individual props\n    for (const prop in newProps) {\n        if (newProps[prop] !== currentProps[prop]) {\n            return true;\n        }\n    }\n\n    return false;\n};\n\nconst applyStyles = (\n    element,\n    {\n        opacity,\n        perspective,\n        translateX,\n        translateY,\n        scaleX,\n        scaleY,\n        rotateX,\n        rotateY,\n        rotateZ,\n        originX,\n        originY,\n        width,\n        height\n    }\n) => {\n    \n    let transforms = '';\n    let styles = '';\n\n    // handle transform origin\n    if (isDefined(originX) || isDefined(originY)) {\n        styles += `transform-origin: ${originX || 0}px ${originY || 0}px;`;\n    }\n\n    // transform order is relevant\n    // 0. perspective\n    if (isDefined(perspective)) {\n        transforms += `perspective(${perspective}px) `;\n    }\n\n    // 1. translate\n    if (isDefined(translateX) || isDefined(translateY)) {\n        transforms += `translate3d(${translateX || 0}px, ${translateY || 0}px, 0) `;\n    }\n\n    // 2. scale\n    if (isDefined(scaleX) || isDefined(scaleY)) {\n        transforms += `scale3d(${isDefined(scaleX) ? scaleX : 1}, ${\n            isDefined(scaleY) ? scaleY : 1\n        }, 1) `;\n    }\n\n    // 3. rotate\n    if (isDefined(rotateZ)) {\n        transforms += `rotateZ(${rotateZ}rad) `;\n    }\n\n    if (isDefined(rotateX)) {\n        transforms += `rotateX(${rotateX}rad) `;\n    }\n\n    if (isDefined(rotateY)) {\n        transforms += `rotateY(${rotateY}rad) `;\n    }\n\n    // add transforms\n    if (transforms.length) {\n        styles += `transform:${transforms};`;\n    }\n\n    // add opacity\n    if (isDefined(opacity)) {\n        styles += `opacity:${opacity};`;\n\n        // if we reach zero, we make the element inaccessible\n        if (opacity === 0) {\n            styles += `visibility:hidden;`;\n        }\n\n        // if we're below 100% opacity this element can't be clicked\n        if (opacity < 1) {\n            styles += `pointer-events:none;`;\n        }\n    }\n\n    // add height\n    if (isDefined(height)) {\n        styles += `height:${height}px;`;\n    }\n\n    // add width\n    if (isDefined(width)) {\n        styles += `width:${width}px;`;\n    }\n\n    // apply styles\n    const elementCurrentStyle = element.elementCurrentStyle || '';\n\n    // if new styles does not match current styles, lets update!\n    if (\n        styles.length !== elementCurrentStyle.length ||\n        styles !== elementCurrentStyle\n    ) {\n        element.style.cssText = styles;\n        // store current styles so we can compare them to new styles later on\n        // _not_ getting the style value is faster\n        element.elementCurrentStyle = styles;\n    }\n};"
  },
  {
    "path": "src/js/app/frame/mixins/utils/addGetSet.js",
    "content": "export const addGetSet = (keys, obj, props, overwrite = false) => {\n    obj = Array.isArray(obj) ? obj : [obj];\n    obj.forEach(o => {\n        keys.forEach(key => {\n            let name = key;\n            let getter = () => props[key];\n            let setter = value => (props[key] = value);\n\n            if (typeof key === 'object') {\n                name = key.key;\n                getter = key.getter || getter;\n                setter = key.setter || setter;\n            }\n\n            if (o[name] && !overwrite) {\n                return;\n            }\n\n            o[name] = {\n                get: getter,\n                set: setter\n            };\n        });\n    });\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/AxisEnum.js",
    "content": "export const AxisEnum = {\n    X: 0,\n    Y: 1,\n    Z: 2\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/addEvent.js",
    "content": "export const addEvent = element => (type, fn) => {\n    element.addEventListener(type, fn);\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/animators/easing.js",
    "content": "export const easeLinear = t => t;\nexport const easeInOutQuad = t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t);\n"
  },
  {
    "path": "src/js/app/frame/utils/animators/spring.js",
    "content": "import { createObject } from '../../../../utils/createObject';\nimport { isNumber } from '../../../../utils/isNumber';\n\n/**\n * Determines if position is at destination\n * @param position\n * @param destination\n * @param velocity\n * @param errorMargin\n * @returns {boolean}\n */\nconst thereYet = (position, destination, velocity, errorMargin = 0.001) => {\n    return (\n        Math.abs(position - destination) < errorMargin &&\n        Math.abs(velocity) < errorMargin\n    );\n};\n\n/**\n * Spring animation\n */\nexport const spring =\n    // default options\n    ({ stiffness = 0.5, damping = 0.75, mass = 10 } = {}) =>\n        // method definition\n        {\n            let target = null;\n            let position = null;\n            let velocity = 0;\n            let resting = false;\n\n            // updates spring state\n            const interpolate = (ts, skipToEndState) => {\n\n                // in rest, don't animate\n                if (resting) return;\n\n                // need at least a target or position to do springy things\n                if (!(isNumber(target) && isNumber(position))) {\n                    resting = true;\n                    velocity = 0;\n                    return;\n                }\n\n                // calculate spring force\n                const f = -(position - target) * stiffness;\n\n                // update velocity by adding force based on mass\n                velocity += f / mass;\n\n                // update position by adding velocity\n                position += velocity;\n\n                // slow down based on amount of damping\n                velocity *= damping;\n\n                // we've arrived if we're near target and our velocity is near zero\n                if (thereYet(position, target, velocity) || skipToEndState) {\n                    position = target;\n                    velocity = 0;\n                    resting = true;\n\n                    // we done\n                    api.onupdate(position);\n                    api.oncomplete(position);\n                } else {\n                    // progress update\n                    api.onupdate(position);\n                }\n            };\n\n            /**\n             * Set new target value\n             * @param value\n             */\n            const setTarget = value => {\n\n                // if currently has no position, set target and position to this value\n                if (isNumber(value) && !isNumber(position)) {\n                    position = value;\n                }\n\n                // next target value will not be animated to\n                if (target === null) {\n                    target = value;\n                    position = value;\n                }\n\n                // let start moving to target\n                target = value;\n\n                // already at target\n                if (position === target || typeof target === 'undefined') {\n                    // now resting as target is current position, stop moving\n                    resting = true;\n                    velocity = 0;\n\n                    // done!\n                    api.onupdate(position);\n                    api.oncomplete(position);\n\n                    return;\n                }\n\n                resting = false;\n            };\n\n            // need 'api' to call onupdate callback\n            const api = createObject({\n                interpolate,\n                target: {\n                    set: setTarget,\n                    get: () => target\n                },\n                resting: {\n                    get: () => resting\n                },\n                onupdate: value => {},\n                oncomplete: value => {}\n            });\n\n            return api;\n        };\n"
  },
  {
    "path": "src/js/app/frame/utils/animators/tween.js",
    "content": "import { createObject } from '../../../../utils/createObject';\nimport { easeInOutQuad } from './easing';\n\nexport const tween =\n    // default values\n    ({ duration = 500, easing = easeInOutQuad, delay = 0 } = {}) =>\n        // method definition\n        {\n            let start = null;\n            let t;\n            let p;\n            let resting = true;\n            let reverse = false;\n            let target = null;\n\n            const interpolate = (ts, skipToEndState) => {\n                if (resting || target === null) return;\n\n                if (start === null) {\n                    start = ts;\n                }\n\n                if (ts - start < delay) return;\n\n                t = ts - start - delay;\n\n                if (t >= duration || skipToEndState) {\n                    t = 1;\n                    p = reverse ? 0 : 1;\n                    api.onupdate(p * target);\n                    api.oncomplete(p * target);\n                    resting = true;\n                }\n                else {\n                    p = t / duration;\n                    api.onupdate(\n                        (t >= 0 ? easing(reverse ? 1 - p : p) : 0) * target\n                    );\n                }\n            };\n\n            // need 'api' to call onupdate callback\n            const api = createObject({\n                interpolate,\n                target: {\n                    get: () => (reverse ? 0 : target),\n                    set: value => {\n                        // is initial value\n                        if (target === null) {\n                            target = value;\n                            api.onupdate(value);\n                            api.oncomplete(value);\n                            return;\n                        }\n\n                        // want to tween to a smaller value and have a current value\n                        if (value < target) {\n                            target = 1;\n                            reverse = true;\n                        } else {\n                            // not tweening to a smaller value\n                            reverse = false;\n                            target = value;\n                        }\n\n                        // let's go!\n                        resting = false;\n                        start = null;\n                    }\n                },\n                resting: {\n                    get: () => resting\n                },\n                onupdate: value => {},\n                oncomplete: value => {}\n            });\n\n            return api;\n        };\n"
  },
  {
    "path": "src/js/app/frame/utils/appendChild.js",
    "content": "export const appendChild = parent => (child, index) => {\n    if (typeof index !== 'undefined' && parent.children[index]) {\n        parent.insertBefore(child, parent.children[index]);\n    } else {\n        parent.appendChild(child);\n    }\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/appendChildView.js",
    "content": "export const appendChildView = (parent, childViews) => (view, index) => {\n    \n    if (typeof index !== 'undefined') {\n        childViews.splice(index, 0, view);\n    } else {\n        childViews.push(view);\n    }\n    \n    return view;\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/createAnimator.js",
    "content": "import { spring } from './animators/spring';\nimport { tween } from './animators/tween';\n\nconst animator = {\n    spring,\n    tween\n};\n\n/*\n { type: 'spring', stiffness: .5, damping: .75, mass: 10 };\n { translation: { type: 'spring', ... }, ... }\n { translation: { x: { type: 'spring', ... } } }\n*/\nexport const createAnimator = (definition, category, property) => {\n    // default is single definition\n    // we check if transform is set, if so, we check if property is set\n    const def =\n        definition[category] &&\n        typeof definition[category][property] === 'object'\n            ? definition[category][property]\n            : definition[category] || definition;\n\n    const type = typeof def === 'string' ? def : def.type;\n    const props = typeof def === 'object' ? { ...def } : {};\n\n    return animator[type] ? animator[type](props) : null;\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/createElement.js",
    "content": "import { forin } from '../../../utils/forin';\nimport { attr } from '../../../utils/attr';\n\nconst ns = 'http://www.w3.org/2000/svg';\nconst svgElements = ['svg', 'path']; // only svg elements used\n\nconst isSVGElement = tag => svgElements.includes(tag);\n\nexport const createElement = (tag, className, attributes = {}) => {\n    if (typeof className === 'object') {\n        attributes = className;\n        className = null;\n    }\n    const element = isSVGElement(tag)\n        ? document.createElementNS(ns, tag)\n        : document.createElement(tag);\n    if (className) {\n        if (isSVGElement(tag)) {\n            attr(element, 'class', className);\n        } else {\n            element.className = className;\n        }\n    }\n    forin(attributes, (name, value) => {\n        attr(element, name, value);\n    });\n    return element;\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/getChildCount.js",
    "content": "import { createElement } from './createElement';\nimport { isBrowser } from '../../../utils/isBrowser';\nconst testElement = isBrowser() ? createElement('svg') : {};\nexport const getChildCount = 'children' in testElement ? el => el.children.length : el => el.childNodes.length;"
  },
  {
    "path": "src/js/app/frame/utils/getViewRect.js",
    "content": "export const getViewRect = (elementRect, childViews, offset, scale) => {\n    const left = offset[0] || elementRect.left;\n    const top = offset[1] || elementRect.top;\n    const right = left + elementRect.width;\n    const bottom = top + elementRect.height * (scale[1] || 1);\n\n    const rect = {\n        // the rectangle of the element itself\n        element: {\n            ...elementRect\n        },\n\n        // the rectangle of the element expanded to contain its children, does not include any margins\n        inner: {\n            left: elementRect.left,\n            top: elementRect.top,\n            right: elementRect.right,\n            bottom: elementRect.bottom\n        },\n\n        // the rectangle of the element expanded to contain its children including own margin and child margins\n        // margins will be added after we've recalculated the size\n        outer: {\n            left,\n            top,\n            right,\n            bottom\n        }\n    };\n\n    // expand rect to fit all child rectangles\n    childViews\n        .filter(childView => !childView.isRectIgnored())\n        .map(childView => childView.rect)\n        .forEach(childViewRect => {\n            expandRect(rect.inner, { ...childViewRect.inner });\n            expandRect(rect.outer, { ...childViewRect.outer });\n        });\n\n    // calculate inner width and height\n    calculateRectSize(rect.inner);\n\n    // append additional margin (top and left margins are included in top and left automatically)\n    rect.outer.bottom += rect.element.marginBottom;\n    rect.outer.right += rect.element.marginRight;\n\n    // calculate outer width and height\n    calculateRectSize(rect.outer);\n\n    return rect;\n};\n\nconst expandRect = (parent, child) => {\n    // adjust for parent offset\n    child.top += parent.top;\n    child.right += parent.left;\n    child.bottom += parent.top;\n    child.left += parent.left;\n\n    if (child.bottom > parent.bottom) {\n        parent.bottom = child.bottom;\n    }\n\n    if (child.right > parent.right) {\n        parent.right = child.right;\n    }\n};\n\nconst calculateRectSize = rect => {\n    rect.width = rect.right - rect.left;\n    rect.height = rect.bottom - rect.top;\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/removeChildView.js",
    "content": "export const removeChildView = (parent, childViews) => view => {\n    // remove from child views\n    childViews.splice(childViews.indexOf(view), 1);\n\n    // remove the element\n    if (view.element.parentNode) {\n        parent.removeChild(view.element);\n    }\n\n    return view;\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/removeEvent.js",
    "content": "export const removeEvent = element => (type, fn) => {\n    element.removeEventListener(type, fn);\n};\n"
  },
  {
    "path": "src/js/app/frame/utils/updateRect.js",
    "content": "export const updateRect = (rect = {}, element = {}, style = {}) => {\n\n    if (!element.layoutCalculated) {\n        rect.paddingTop = parseInt(style.paddingTop, 10) || 0;\n        rect.marginTop = parseInt(style.marginTop, 10) || 0;\n        rect.marginRight = parseInt(style.marginRight, 10) || 0;\n        rect.marginBottom = parseInt(style.marginBottom, 10) || 0;\n        rect.marginLeft = parseInt(style.marginLeft, 10) || 0;\n        element.layoutCalculated = true;\n    }\n\n    rect.left = element.offsetLeft || 0;\n    rect.top = element.offsetTop || 0;\n    rect.width = element.offsetWidth || 0;\n    rect.height = element.offsetHeight || 0;\n\n    rect.right = rect.left + rect.width;\n    rect.bottom = rect.top + rect.height;\n\n    rect.scrollTop = element.scrollTop;\n\n    rect.hidden = element.offsetParent === null;\n\n    return rect;\n};\n"
  },
  {
    "path": "src/js/app/index.js",
    "content": "import { createStore } from './frame/index';\nimport { insertBefore } from '../utils/insertBefore';\nimport { insertAfter } from '../utils/insertAfter';\nimport { createInitialState } from './utils/createInitialState';\nimport { createObject } from '../utils/createObject';\nimport { createOptionAPI } from './utils/createOptionAPI';\nimport { createOptionActions } from './utils/createOptionActions';\nimport { createOptionQueries } from './utils/createOptionQueries';\nimport { InteractionMethod } from './enum/InteractionMethod';\nimport { getUniqueId } from '../utils/getUniqueId';\nimport { on } from './utils/on';\nimport { isArray } from '../utils/isArray';\nimport { isNumber } from '../utils/isNumber';\nimport { createItemAPI } from './utils/createItemAPI';\nimport { removeReleasedItems } from './utils/removeReleasedItems';\nimport { ItemStatus } from './enum/ItemStatus';\nimport { FileOrigin } from './enum/FileOrigin';\n\n// defaults\nimport { getOptions } from './options';\nimport { queries } from './queries';\nimport { actions } from './actions';\n\n// view\nimport { root } from './view/root';\n\n// creates the app\nexport const createApp = (initialOptions = {}) => {\n    // let element\n    let originalElement = null;\n\n    // get default options\n    const defaultOptions = getOptions();\n\n    // create the data store, this will contain all our app info\n    const store = createStore(\n        // initial state (should be serializable)\n        createInitialState(defaultOptions),\n\n        // queries\n        [queries, createOptionQueries(defaultOptions)],\n\n        // action handlers\n        [actions, createOptionActions(defaultOptions)]\n    );\n\n    // set initial options\n    store.dispatch('SET_OPTIONS', { options: initialOptions });\n\n    // kick thread if visibility changes\n    const visibilityHandler = () => {\n        if (document.hidden) return;\n        store.dispatch('KICK');\n    }\n    document.addEventListener('visibilitychange', visibilityHandler);\n\n    // re-render on window resize start and finish\n    let resizeDoneTimer = null;\n    let isResizing = false;\n    let isResizingHorizontally = false;\n    let initialWindowWidth = null;\n    let currentWindowWidth = null;\n    const resizeHandler = () => {\n        if (!isResizing) {\n            isResizing = true;\n        }\n        clearTimeout(resizeDoneTimer);\n        resizeDoneTimer = setTimeout(() => {\n            isResizing = false;\n            initialWindowWidth = null;\n            currentWindowWidth = null;\n            if (isResizingHorizontally) {\n                isResizingHorizontally = false;\n                store.dispatch('DID_STOP_RESIZE');\n            }\n        }, 500);\n    };\n    window.addEventListener('resize', resizeHandler);\n\n    // render initial view\n    const view = root(store, { id: getUniqueId() });\n\n    //\n    // PRIVATE API -------------------------------------------------------------------------------------\n    //\n    let isResting = false;\n    let isHidden = false;\n\n    const readWriteApi = {\n        // necessary for update loop\n\n        /**\n         * Reads from dom (never call manually)\n         * @private\n         */\n        _read: () => {\n\n            // test if we're resizing horizontally\n            // TODO: see if we can optimize this by measuring root rect\n            if (isResizing) {\n\n                currentWindowWidth = window.innerWidth;\n                if (!initialWindowWidth) {\n                    initialWindowWidth = currentWindowWidth;\n                }\n\n                if (!isResizingHorizontally && currentWindowWidth !== initialWindowWidth) {\n                    store.dispatch('DID_START_RESIZE');\n                    isResizingHorizontally = true;\n                }\n            }\n\n            if (isHidden && isResting) {\n                // test if is no longer hidden\n                isResting = view.element.offsetParent === null;\n            }\n\n            // if resting, no need to read as numbers will still all be correct\n            if (isResting) return;\n\n            // read view data\n            view._read();\n\n            // if is hidden we need to know so we exit rest mode when revealed\n            isHidden = view.rect.element.hidden;\n        },\n\n        /**\n         * Writes to dom (never call manually)\n         * @private\n         */\n        _write: ts => {\n\n            // get all actions from store\n            const actions = store\n                .processActionQueue()\n\n                // filter out set actions (these will automatically trigger DID_SET)\n                .filter(action => !/^SET_/.test(action.type));\n\n            // if was idling and no actions stop here\n            if (isResting && !actions.length) return;\n            \n            // some actions might trigger events\n            routeActionsToEvents(actions);\n\n            // update the view\n            isResting = view._write(ts, actions, isResizingHorizontally);\n\n            // will clean up all archived items\n            removeReleasedItems(store.query('GET_ITEMS'));\n            \n            // now idling\n            if (isResting) {\n                store.processDispatchQueue();\n            }\n\n        }\n    };\n\n    //\n    // EXPOSE EVENTS -------------------------------------------------------------------------------------\n    //\n    const createEvent = name => data => {\n        // create default event\n        const event = {\n            type: name\n        };\n\n        // no data to add\n        if (!data) {\n            return event;\n        }\n\n        // copy relevant props\n        if (data.hasOwnProperty('error')) {\n            event.error = data.error ? { ...data.error } : null;\n        }\n\n        if (data.status) {\n            event.status = { ...data.status };\n        }\n\n        if (data.file) {\n            event.output = data.file;\n        }\n\n        // only source is available, else add item if possible\n        if (data.source) {\n            event.file = data.source;\n        } else if (data.item || data.id) {\n            const item = data.item\n                ? data.item\n                : store.query('GET_ITEM', data.id);\n            event.file = item ? createItemAPI(item) : null;\n        }\n\n        // map all items in a possible items array\n        if (data.items) {\n            event.items = data.items.map(createItemAPI);\n        }\n\n        // if this is a progress event add the progress amount\n        if (/progress/.test(name)) {\n            event.progress = data.progress;\n        }\n\n        // copy relevant props\n        if (data.hasOwnProperty('origin') && data.hasOwnProperty('target')) {\n            event.origin = data.origin;\n            event.target = data.target;\n        }\n\n        return event;\n    };\n\n    const eventRoutes = {\n        DID_DESTROY: createEvent('destroy'),\n\n        DID_INIT: createEvent('init'),\n\n        DID_THROW_MAX_FILES: createEvent('warning'),\n\n        DID_INIT_ITEM: createEvent('initfile'),\n        DID_START_ITEM_LOAD: createEvent('addfilestart'),\n        DID_UPDATE_ITEM_LOAD_PROGRESS: createEvent('addfileprogress'),\n        DID_LOAD_ITEM: createEvent('addfile'),\n        \n        DID_THROW_ITEM_INVALID: [\n            createEvent('error'), \n            createEvent('addfile')\n        ],\n\n        DID_THROW_ITEM_LOAD_ERROR: [\n            createEvent('error'),\n            createEvent('addfile')\n        ],\n\n        DID_THROW_ITEM_REMOVE_ERROR: [\n            createEvent('error'),\n            createEvent('removefile')\n        ],\n\n        DID_PREPARE_OUTPUT: createEvent('preparefile'),\n\n        DID_START_ITEM_PROCESSING: createEvent('processfilestart'),\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: createEvent('processfileprogress'),\n        DID_ABORT_ITEM_PROCESSING: createEvent('processfileabort'),\n        DID_COMPLETE_ITEM_PROCESSING: createEvent('processfile'),\n        DID_COMPLETE_ITEM_PROCESSING_ALL: createEvent('processfiles'),\n        DID_REVERT_ITEM_PROCESSING: createEvent('processfilerevert'),\n\n        DID_THROW_ITEM_PROCESSING_ERROR: [\n            createEvent('error'),\n            createEvent('processfile')\n        ],\n\n        DID_REMOVE_ITEM: createEvent('removefile'),\n\n        DID_UPDATE_ITEMS: createEvent('updatefiles'),\n\n        DID_ACTIVATE_ITEM: createEvent('activatefile'),\n\n        DID_REORDER_ITEMS: createEvent('reorderfiles')\n    };\n\n    const exposeEvent = event => {\n\n        // create event object to be dispatched\n        const detail = { pond: exports, ...event };\n        delete detail.type;\n        view.element.dispatchEvent(\n            new CustomEvent(`FilePond:${event.type}`, {\n                // event info\n                detail,\n\n                // event behaviour\n                bubbles: true,\n                cancelable: true,\n                composed: true // triggers listeners outside of shadow root\n            })\n        );\n\n        // event object to params used for `on()` event handlers and callbacks `oninit()`\n        const params = [];\n\n        // if is possible error event, make it the first param\n        if (event.hasOwnProperty('error')) {\n            params.push(event.error);\n        }\n        \n        // file is always section\n        if (event.hasOwnProperty('file')) {\n            params.push(event.file);\n        }\n\n        // append other props\n        const filtered = ['type', 'error', 'file'];\n        Object.keys(event)\n            .filter(key => !filtered.includes(key))\n            .forEach(key => params.push(event[key]));\n\n        // on(type, () => { })\n        exports.fire(event.type, ...params);\n\n        // oninit = () => {}\n        const handler = store.query(`GET_ON${event.type.toUpperCase()}`);\n        if (handler) {\n            handler(...params);\n        }\n    };\n\n    const routeActionsToEvents = actions => {\n        if (!actions.length) return;\n        actions\n            .filter(action => eventRoutes[action.type])\n            .forEach(action => {\n                const routes = eventRoutes[action.type];\n                (Array.isArray(routes) ? routes : [routes]).forEach(route => {\n                    // this isn't fantastic, but because of the stacking of settimeouts plugins can handle the did_load before the did_init\n                    if (action.type === 'DID_INIT_ITEM') {\n                        exposeEvent(route(action.data));\n                    }\n                    else {\n                        setTimeout(() => {\n                            exposeEvent(route(action.data));\n                        }, 0);\n                    }\n                });\n            });\n    };\n\n    //\n    // PUBLIC API -------------------------------------------------------------------------------------\n    //\n    const setOptions = options => store.dispatch('SET_OPTIONS', { options });\n\n    const getFile = query => store.query('GET_ACTIVE_ITEM', query);\n\n    const prepareFile = query => new Promise((resolve, reject) => {\n        store.dispatch('REQUEST_ITEM_PREPARE', {\n            query,\n            success: (item) => {\n                resolve(item)\n            },\n            failure: (error) => {\n                reject(error)\n            },\n        });\n    });\n\n    const addFile = (source, options = {}) => new Promise((resolve, reject) => {\n        addFiles([{source, options}], { index: options.index })\n            .then(items => resolve(items && items[0]))\n            .catch(reject)\n    });\n\n    const isFilePondFile = (obj) => obj.file && obj.id;\n\n    const removeFile = (query, options) => {\n\n        // if only passed options\n        if (typeof query === 'object' && !isFilePondFile(query) && !options) {\n            options = query;\n            query = undefined;\n        }\n\n        // request item removal\n        store.dispatch('REMOVE_ITEM', { ...options, query });\n\n        // see if item has been removed\n        return store.query('GET_ACTIVE_ITEM', query) === null;\n    };\n\n    const addFiles = (...args) =>\n        new Promise((resolve, reject) => {\n\n            const sources = [];\n            const options = {};\n\n            // user passed a sources array\n            if (isArray(args[0])) {\n                sources.push.apply(sources, args[0]);\n                Object.assign(options, args[1] || {});\n            } \n            else {\n                // user passed sources as arguments, last one might be options object\n                const lastArgument = args[args.length - 1];\n                if (\n                    typeof lastArgument === 'object' &&\n                    !(lastArgument instanceof Blob)\n                ) {\n                    Object.assign(options, args.pop());\n                }\n\n                // add rest to sources\n                sources.push(...args);\n            }\n\n            store.dispatch('ADD_ITEMS', {\n                items: sources,\n                index: options.index,\n                interactionMethod: InteractionMethod.API,\n                success: resolve,\n                failure: reject\n            });\n\n        });\n\n    const getFiles = () => store.query('GET_ACTIVE_ITEMS');\n\n    const processFile = query => new Promise((resolve, reject) => {\n        store.dispatch('REQUEST_ITEM_PROCESSING', {\n            query,\n            success: (item) => {\n                resolve(item)\n            },\n            failure: (error) => {\n                reject(error)\n            },\n        });\n    });\n\n    const prepareFiles = (...args) => {\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n        const items = queries.length ? queries : getFiles();\n        return Promise.all(items.map(prepareFile));\n    };\n\n    const processFiles = (...args) => {\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n        if (!queries.length) {\n            const files = getFiles().filter(item => \n                !(item.status === ItemStatus.IDLE && item.origin === FileOrigin.LOCAL) &&\n                item.status !== ItemStatus.PROCESSING &&\n                item.status !== ItemStatus.PROCESSING_COMPLETE &&\n                item.status !== ItemStatus.PROCESSING_REVERT_ERROR\n            );\n            return Promise.all(files.map(processFile));\n        }\n        return Promise.all(queries.map(processFile));\n    };\n\n    const removeFiles = (...args) => {\n\n        const queries = Array.isArray(args[0]) ? args[0] : args;\n\n        let options;\n        if (typeof queries[queries.length - 1] === 'object') {\n            options = queries.pop();\n        }\n        else if (Array.isArray(args[0])) {\n            options = args[1];\n        }\n\n        const files = getFiles();\n\n        if (!queries.length) return Promise.all(files.map(file => removeFile(file, options)));\n\n        // when removing by index the indexes shift after each file removal so we need to convert indexes to ids\n        const mappedQueries = queries.map(query =>\n            isNumber(query) ? files[query] ? files[query].id : null : query\n        ).filter(query => query);\n\n        return mappedQueries.map(q => removeFile(q, options));\n    };\n\n    const exports = {\n        // supports events\n        ...on(),\n\n        // inject private api methods\n        ...readWriteApi,\n\n        // inject all getters and setters\n        ...createOptionAPI(store, defaultOptions),\n\n        /**\n         * Override options defined in options object\n         * @param options\n         */\n        setOptions,\n\n        /**\n         * Load the given file\n         * @param source - the source of the file (either a File, base64 data uri or url)\n         * @param options - object, { index: 0 }\n         */\n        addFile,\n\n        /**\n         * Load the given files\n         * @param sources - the sources of the files to load\n         * @param options - object, { index: 0 }\n         */\n        addFiles,\n\n        /**\n         * Returns the file objects matching the given query\n         * @param query { string, number, null }\n         */\n        getFile,\n\n        /**\n         * Upload file with given name\n         * @param query { string, number, null  }\n         */\n        processFile,\n\n\n        /**\n         * Request prepare output for file with given name\n         * @param query { string, number, null  }\n         */\n        prepareFile,\n\n        /**\n         * Removes a file by its name\n         * @param query { string, number, null  }\n         */\n        removeFile,\n\n        /**\n         * Moves a file to a new location in the files list\n         */\n        moveFile: (query, index) => store.dispatch('MOVE_ITEM', { query, index }),\n\n        /**\n         * Returns all files (wrapped in public api)\n         */\n        getFiles,\n\n        /**\n         * Starts uploading all files\n         */\n        processFiles,\n\n        /**\n         * Clears all files from the files list\n         */\n        removeFiles,\n\n        /**\n         * Starts preparing output of all files\n         */\n        prepareFiles,\n\n        /**\n         * Sort list of files\n         */\n        sort: (compare) => store.dispatch('SORT', { compare }),\n\n        /**\n         * Browse the file system for a file\n         */\n        browse: () => {\n            // needs to be trigger directly as user action needs to be traceable (is not traceable in requestAnimationFrame)\n            var input = view.element.querySelector('input[type=file]');\n            if (input) {\n                input.click();\n            }\n        },\n\n        /**\n         * Destroys the app\n         */\n        destroy: () => {\n            // request destruction\n            exports.fire('destroy', view.element);\n\n            // stop active processes (file uploads, fetches, stuff like that)\n            // loop over items and depending on states call abort for ongoing processes\n            store.dispatch('ABORT_ALL');\n\n            // destroy view\n            view._destroy();\n\n            // stop listening to resize\n            window.removeEventListener('resize', resizeHandler);\n\n            // stop listening to the visiblitychange event\n            document.removeEventListener('visibilitychange', visibilityHandler);\n\n            // dispatch destroy\n            store.dispatch('DID_DESTROY');\n        },\n\n        /**\n         * Inserts the plugin before the target element\n         */\n        insertBefore: element => insertBefore(view.element, element),\n\n        /**\n         * Inserts the plugin after the target element\n         */\n        insertAfter: element => insertAfter(view.element, element),\n\n        /**\n         * Appends the plugin to the target element\n         */\n        appendTo: element => element.appendChild(view.element),\n\n        /**\n         * Replaces an element with the app\n         */\n        replaceElement: element => {\n            // insert the app before the element\n            insertBefore(view.element, element);\n\n            // remove the original element\n            element.parentNode.removeChild(element);\n\n            // remember original element\n            originalElement = element;\n        },\n\n        /**\n         * Restores the original element\n         */\n        restoreElement: () => {\n            if (!originalElement) {\n                return; // no element to restore\n            }\n\n            // restore original element\n            insertAfter(originalElement, view.element);\n\n            // remove our element\n            view.element.parentNode.removeChild(view.element);\n\n            // remove reference\n            originalElement = null;\n        },\n\n        /**\n         * Returns true if the app root is attached to given element\n         * @param element\n         */\n        isAttachedTo: element =>\n            view.element === element || originalElement === element,\n\n        /**\n         * Returns the root element\n         */\n        element: {\n            get: () => view.element\n        },\n\n        /**\n         * Returns the current pond status\n         */\n        status: {\n            get: () => store.query('GET_STATUS')\n        }\n    };\n\n    // Done!\n    store.dispatch('DID_INIT');\n\n    // create actual api object\n    return createObject(exports);\n};\n"
  },
  {
    "path": "src/js/app/options.js",
    "content": "import { getDecimalSeparator } from '../utils/getDecimalSeparator';\nimport { getThousandsSeparator } from '../utils/getThousandsSeparator';\nimport { Type } from './enum/Type';\nimport { applyFilters } from './../filter';\nimport { forin } from '../utils/forin';\nimport { isString } from '../utils/isString';\nimport { createServerAPI } from './utils/createServerAPI';\nimport { getValueByType } from './utils/getValueByType';\n\nexport const extendDefaultOptions = additionalOptions =>\n    Object.assign(defaultOptions, additionalOptions);\n\nexport const getOptions = () => ({ ...defaultOptions });\n\nexport const setOptions = opts => {\n    forin(opts, (key, value) => {\n        // key does not exist, so this option cannot be set\n        if (!defaultOptions[key]) {\n            return;\n        }\n        defaultOptions[key][0] = getValueByType(\n            value,\n            defaultOptions[key][0],\n            defaultOptions[key][1]\n        );\n    });\n};\n\n// default options on app\nexport const defaultOptions = {\n    // the id to add to the root element\n    id: [null, Type.STRING],\n\n    // input field name to use\n    name: ['filepond', Type.STRING],\n\n    // disable the field\n    disabled: [false, Type.BOOLEAN],\n\n    // classname to put on wrapper\n    className: [null, Type.STRING],\n\n    // is the field required\n    required: [false, Type.BOOLEAN],\n\n    // Allow media capture when value is set\n    captureMethod: [null, Type.STRING],\n    // - \"camera\", \"microphone\" or \"camcorder\",\n    // - Does not work with multiple on apple devices\n    // - If set, acceptedFileTypes must be made to match with media wildcard \"image/*\", \"audio/*\" or \"video/*\"\n\n    // sync `acceptedFileTypes` property with `accept` attribute\n    allowSyncAcceptAttribute: [true, Type.BOOLEAN],\n\n    // Feature toggles\n    allowDrop: [true, Type.BOOLEAN], // Allow dropping of files\n    allowBrowse: [true, Type.BOOLEAN], // Allow browsing the file system\n    allowPaste: [true, Type.BOOLEAN], // Allow pasting files\n    allowMultiple: [false, Type.BOOLEAN], // Allow multiple files (disabled by default, as multiple attribute is also required on input to allow multiple)\n    allowReplace: [true, Type.BOOLEAN], // Allow dropping a file on other file to replace it (only works when multiple is set to false)\n    allowRevert: [true, Type.BOOLEAN], // Allows user to revert file upload\n    allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file\n    allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button\n    allowReorder: [false, Type.BOOLEAN], // Allow reordering of files\n    allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)\n\n    // Try store file if `server` not set\n    storeAsFile: [false, Type.BOOLEAN],\n\n    // Revert mode\n    forceRevert: [false, Type.BOOLEAN], // Set to 'force' to require the file to be reverted before removal\n\n    // Input requirements\n    maxFiles: [null, Type.INT], // Max number of files\n    checkValidity: [false, Type.BOOLEAN], // Enables custom validity messages\n\n    // Where to put file\n    itemInsertLocationFreedom: [true, Type.BOOLEAN], // Set to false to always add items to begin or end of list\n    itemInsertLocation: ['before', Type.STRING], // Default index in list to add items that have been dropped at the top of the list\n    itemInsertInterval: [75, Type.INT],\n\n    // Drag 'n Drop related\n    dropOnPage: [false, Type.BOOLEAN], // Allow dropping of files anywhere on page (prevents browser from opening file if dropped outside of Up)\n    dropOnElement: [true, Type.BOOLEAN], // Drop needs to happen on element (set to false to also load drops outside of Up)\n    dropValidation: [false, Type.BOOLEAN], // Enable or disable validating files on drop\n    ignoredFiles: [['.ds_store', 'thumbs.db', 'desktop.ini'], Type.ARRAY],\n\n    // Upload related\n    instantUpload: [true, Type.BOOLEAN], // Should upload files immediately on drop\n    maxParallelUploads: [2, Type.INT], // Maximum files to upload in parallel\n    allowMinimumUploadDuration: [true, Type.BOOLEAN], // if true uploads take at least 750 ms, this ensures the user sees the upload progress giving trust the upload actually happened\n\n    // Chunks\n    chunkUploads: [false, Type.BOOLEAN], // Enable chunked uploads\n    chunkForce: [false, Type.BOOLEAN], // Force use of chunk uploads even for files smaller than chunk size\n    chunkSize: [5000000, Type.INT], // Size of chunks (5MB default)\n    chunkRetryDelays: [[500, 1000, 3000], Type.ARRAY], // Amount of times to retry upload of a chunk when it fails\n\n    // The server api end points to use for uploading (see docs)\n    server: [null, Type.SERVER_API],\n\n    // File size calculations, can set to 1024, this is only used for display, properties use file size base 1000\n    fileSizeBase: [1000, Type.INT],\n\n    // Labels and status messages\n    labelFileSizeBytes: ['bytes', Type.STRING],\n    labelFileSizeKilobytes: ['KB', Type.STRING],\n    labelFileSizeMegabytes: ['MB', Type.STRING],\n    labelFileSizeGigabytes: ['GB', Type.STRING],\n\n    labelDecimalSeparator: [getDecimalSeparator(), Type.STRING], // Default is locale separator\n    labelThousandsSeparator: [getThousandsSeparator(), Type.STRING], // Default is locale separator\n\n    labelIdle: [\n        'Drag & Drop your files or <span class=\"filepond--label-action\">Browse</span>',\n        Type.STRING,\n    ],\n    labelInvalidField: ['Field contains invalid files', Type.STRING],\n    labelFileWaitingForSize: ['Waiting for size', Type.STRING],\n    labelFileSizeNotAvailable: ['Size not available', Type.STRING],\n    labelFileCountSingular: ['file in list', Type.STRING],\n    labelFileCountPlural: ['files in list', Type.STRING],\n    labelFileLoading: ['Loading', Type.STRING],\n    labelFileAdded: ['Added', Type.STRING], // assistive only\n    labelFileLoadError: ['Error during load', Type.STRING],\n    labelFileRemoved: ['Removed', Type.STRING], // assistive only\n    labelFileRemoveError: ['Error during remove', Type.STRING],\n    labelFileProcessing: ['Uploading', Type.STRING],\n    labelFileProcessingComplete: ['Upload complete', Type.STRING],\n    labelFileProcessingAborted: ['Upload cancelled', Type.STRING],\n    labelFileProcessingError: ['Error during upload', Type.STRING],\n    labelFileProcessingRevertError: ['Error during revert', Type.STRING],\n\n    labelTapToCancel: ['tap to cancel', Type.STRING],\n    labelTapToRetry: ['tap to retry', Type.STRING],\n    labelTapToUndo: ['tap to undo', Type.STRING],\n\n    labelButtonRemoveItem: ['Remove', Type.STRING],\n    labelButtonAbortItemLoad: ['Abort', Type.STRING],\n    labelButtonRetryItemLoad: ['Retry', Type.STRING],\n    labelButtonAbortItemProcessing: ['Cancel', Type.STRING],\n    labelButtonUndoItemProcessing: ['Undo', Type.STRING],\n    labelButtonRetryItemProcessing: ['Retry', Type.STRING],\n    labelButtonProcessItem: ['Upload', Type.STRING],\n\n    // make sure width and height plus viewpox are even numbers so icons are nicely centered\n    iconRemove: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.586 13l-2.293 2.293a1 1 0 0 0 1.414 1.414L13 14.414l2.293 2.293a1 1 0 0 0 1.414-1.414L14.414 13l2.293-2.293a1 1 0 0 0-1.414-1.414L13 11.586l-2.293-2.293a1 1 0 0 0-1.414 1.414L11.586 13z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconProcess: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M14 10.414v3.585a1 1 0 0 1-2 0v-3.585l-1.293 1.293a1 1 0 0 1-1.414-1.415l3-3a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1-1.414 1.415L14 10.414zM9 18a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2H9z\" fill=\"currentColor\" fill-rule=\"evenodd\"/></svg>',\n        Type.STRING,\n    ],\n    iconRetry: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10.81 9.185l-.038.02A4.997 4.997 0 0 0 8 13.683a5 5 0 0 0 5 5 5 5 0 0 0 5-5 1 1 0 0 1 2 0A7 7 0 1 1 9.722 7.496l-.842-.21a.999.999 0 1 1 .484-1.94l3.23.806c.535.133.86.675.73 1.21l-.804 3.233a.997.997 0 0 1-1.21.73.997.997 0 0 1-.73-1.21l.23-.928v-.002z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconUndo: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.185 10.81l.02-.038A4.997 4.997 0 0 1 13.683 8a5 5 0 0 1 5 5 5 5 0 0 1-5 5 1 1 0 0 0 0 2A7 7 0 1 0 7.496 9.722l-.21-.842a.999.999 0 1 0-1.94.484l.806 3.23c.133.535.675.86 1.21.73l3.233-.803a.997.997 0 0 0 .73-1.21.997.997 0 0 0-1.21-.73l-.928.23-.002-.001z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n    iconDone: [\n        '<svg width=\"26\" height=\"26\" viewBox=\"0 0 26 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M18.293 9.293a1 1 0 0 1 1.414 1.414l-7.002 7a1 1 0 0 1-1.414 0l-3.998-4a1 1 0 1 1 1.414-1.414L12 15.586l6.294-6.293z\" fill=\"currentColor\" fill-rule=\"nonzero\"/></svg>',\n        Type.STRING,\n    ],\n\n    // event handlers\n    oninit: [null, Type.FUNCTION],\n    onwarning: [null, Type.FUNCTION],\n    onerror: [null, Type.FUNCTION],\n    onactivatefile: [null, Type.FUNCTION],\n    oninitfile: [null, Type.FUNCTION],\n    onaddfilestart: [null, Type.FUNCTION],\n    onaddfileprogress: [null, Type.FUNCTION],\n    onaddfile: [null, Type.FUNCTION],\n    onprocessfilestart: [null, Type.FUNCTION],\n    onprocessfileprogress: [null, Type.FUNCTION],\n    onprocessfileabort: [null, Type.FUNCTION],\n    onprocessfilerevert: [null, Type.FUNCTION],\n    onprocessfile: [null, Type.FUNCTION],\n    onprocessfiles: [null, Type.FUNCTION],\n    onremovefile: [null, Type.FUNCTION],\n    onpreparefile: [null, Type.FUNCTION],\n    onupdatefiles: [null, Type.FUNCTION],\n    onreorderfiles: [null, Type.FUNCTION],\n\n    // hooks\n    beforeDropFile: [null, Type.FUNCTION],\n    beforeAddFile: [null, Type.FUNCTION],\n    beforeRemoveFile: [null, Type.FUNCTION],\n    beforePrepareFile: [null, Type.FUNCTION],\n\n    // styles\n    stylePanelLayout: [null, Type.STRING], // null 'integrated', 'compact', 'circle'\n    stylePanelAspectRatio: [null, Type.STRING], // null or '3:2' or 1\n    styleItemPanelAspectRatio: [null, Type.STRING],\n    styleButtonRemoveItemPosition: ['left', Type.STRING],\n    styleButtonProcessItemPosition: ['right', Type.STRING],\n    styleLoadIndicatorPosition: ['right', Type.STRING],\n    styleProgressIndicatorPosition: ['right', Type.STRING],\n    styleButtonRemoveItemAlign: [false, Type.BOOLEAN],\n\n    // custom initial files array\n    files: [[], Type.ARRAY],\n\n    // show support by displaying credits\n    credits: [['https://filepond.com', 'Powered by FilePond'], Type.ARRAY],\n};\n"
  },
  {
    "path": "src/js/app/queries.js",
    "content": "import { isObject } from '../utils/isObject';\nimport { isFunction } from '../utils/isFunction';\nimport { getItemByQuery } from './utils/getItemByQuery';\nimport { getNumericAspectRatioFromString } from '../utils/getNumericAspectRatioFromString';\nimport { getActiveItems } from './utils/getActiveItems';\nimport { Status } from './enum/Status';\nimport { ItemStatus } from './enum/ItemStatus';\nimport { canUpdateFileInput } from '../utils/canUpdateFileInput';\n\nconst ITEM_ERROR = [\n    ItemStatus.LOAD_ERROR,\n    ItemStatus.PROCESSING_ERROR,\n    ItemStatus.PROCESSING_REVERT_ERROR,\n];\nconst ITEM_BUSY = [\n    ItemStatus.LOADING,\n    ItemStatus.PROCESSING,\n    ItemStatus.PROCESSING_QUEUED,\n    ItemStatus.INIT,\n];\nconst ITEM_READY = [ItemStatus.PROCESSING_COMPLETE];\n\nconst isItemInErrorState = item => ITEM_ERROR.includes(item.status);\nconst isItemInBusyState = item => ITEM_BUSY.includes(item.status);\nconst isItemInReadyState = item => ITEM_READY.includes(item.status);\n\nconst isAsync = state =>\n    isObject(state.options.server) &&\n    (isObject(state.options.server.process) || isFunction(state.options.server.process));\n\nexport const queries = state => ({\n    GET_STATUS: () => {\n        const items = getActiveItems(state.items);\n\n        const { EMPTY, ERROR, BUSY, IDLE, READY } = Status;\n\n        if (items.length === 0) return EMPTY;\n\n        if (items.some(isItemInErrorState)) return ERROR;\n\n        if (items.some(isItemInBusyState)) return BUSY;\n\n        if (items.some(isItemInReadyState)) return READY;\n\n        return IDLE;\n    },\n\n    GET_ITEM: query => getItemByQuery(state.items, query),\n\n    GET_ACTIVE_ITEM: query => getItemByQuery(getActiveItems(state.items), query),\n\n    GET_ACTIVE_ITEMS: () => getActiveItems(state.items),\n\n    GET_ITEMS: () => state.items,\n\n    GET_ITEM_NAME: query => {\n        const item = getItemByQuery(state.items, query);\n        return item ? item.filename : null;\n    },\n\n    GET_ITEM_SIZE: query => {\n        const item = getItemByQuery(state.items, query);\n        return item ? item.fileSize : null;\n    },\n\n    GET_STYLES: () =>\n        Object.keys(state.options)\n            .filter(key => /^style/.test(key))\n            .map(option => ({\n                name: option,\n                value: state.options[option],\n            })),\n\n    GET_PANEL_ASPECT_RATIO: () => {\n        const isShapeCircle = /circle/.test(state.options.stylePanelLayout);\n        const aspectRatio = isShapeCircle\n            ? 1\n            : getNumericAspectRatioFromString(state.options.stylePanelAspectRatio);\n        return aspectRatio;\n    },\n\n    GET_ITEM_PANEL_ASPECT_RATIO: () => state.options.styleItemPanelAspectRatio,\n\n    GET_ITEMS_BY_STATUS: status =>\n        getActiveItems(state.items).filter(item => item.status === status),\n\n    GET_TOTAL_ITEMS: () => getActiveItems(state.items).length,\n\n    SHOULD_UPDATE_FILE_INPUT: () =>\n        state.options.storeAsFile && canUpdateFileInput() && !isAsync(state),\n\n    IS_ASYNC: () => isAsync(state),\n\n    GET_FILE_SIZE_LABELS: query => ({\n        labelBytes: query('GET_LABEL_FILE_SIZE_BYTES') || undefined,\n        labelKilobytes: query('GET_LABEL_FILE_SIZE_KILOBYTES') || undefined,\n        labelMegabytes: query('GET_LABEL_FILE_SIZE_MEGABYTES') || undefined,\n        labelGigabytes: query('GET_LABEL_FILE_SIZE_GIGABYTES') || undefined,\n    }),\n});\n"
  },
  {
    "path": "src/js/app/utils/buildURL.js",
    "content": "const hasQS = str => /\\?/.test(str);\nexport const buildURL = (...parts) => {\n    let url = '';\n    parts.forEach(part => {\n        url += hasQS(url) && hasQS(part) ? part.replace(/\\?/, '&') : part;\n    });\n    return url;\n}"
  },
  {
    "path": "src/js/app/utils/convertTo.js",
    "content": "import { toArray } from '../../utils/toArray';\nimport { toBoolean } from '../../utils/toBoolean';\nimport { toInt } from '../../utils/toInt';\nimport { toFloat } from '../../utils/toFloat';\nimport { toBytes } from '../../utils/toBytes';\nimport { toString } from '../../utils/toString';\nimport { isFunction } from '../../utils/isFunction';\nimport { toFunctionReference } from '../../utils/toFunctionReference';\nimport { toServerAPI } from './toServerAPI';\nimport { getType } from './getType';\n\nconst replaceSingleQuotes = (str) => str\n    .replace(/{\\s*'/g,'{\"')\n    .replace(/'\\s*}/g,'\"}')\n    .replace(/'\\s*:/g,'\":')\n    .replace(/:\\s*'/g,':\"')\n    .replace(/,\\s*'/g,',\"')\n    .replace(/'\\s*,/g,'\",')\n\nconst conversionTable = {\n    array: toArray,\n    boolean: toBoolean,\n    int: value => getType(value) === 'bytes' ? toBytes(value) : toInt(value),\n    number: toFloat,\n    float: toFloat,\n    bytes: toBytes,\n    string: value => isFunction(value) ? value : toString(value),\n    function: value => toFunctionReference(value),\n    serverapi: toServerAPI,\n    object: value => {\n        try {\n            return JSON.parse(replaceSingleQuotes(value))\n        }\n        catch(e) {\n            return null;\n        }\n    }\n};\n\nexport const convertTo = (value, type) => conversionTable[type](value);\n"
  },
  {
    "path": "src/js/app/utils/createDragHelper.js",
    "content": "export const createDragHelper = (items) => {\n    const itemIds = items.map(item => item.id);\n    let prevIndex = undefined;\n    return {\n        setIndex: (index) => {\n            prevIndex = index;\n        },\n        getIndex: () => prevIndex,\n        getItemIndex: (item) => itemIds.indexOf(item.id)\n    }\n}"
  },
  {
    "path": "src/js/app/utils/createFetchFunction.js",
    "content": "import { sendRequest } from '../../utils/sendRequest';\nimport { createResponse } from '../../utils/createResponse';\nimport { createTimeoutResponse } from '../../utils/createDefaultResponse';\nimport { getFileInfoFromHeaders } from '../../utils/getFileInfoFromHeaders';\nimport { getFilenameFromURL } from '../../utils/getFilenameFromURL';\nimport { getFileFromBlob } from '../../utils/getFileFromBlob';\nimport { isString } from '../../utils/isString';\nimport { buildURL } from './buildURL';\n\nexport const createFetchFunction = (apiUrl = '', action) => {\n    // custom handler (should also handle file, load, error, progress and abort)\n    if (typeof action === 'function') {\n        return action;\n    }\n\n    // no action supplied\n    if (!action || !isString(action.url)) {\n        return null;\n    }\n\n    // set onload hanlder\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    // internal handler\n    return (url, load, error, progress, abort, headers) => {\n        \n        // do local or remote request based on if the url is external\n        const request = sendRequest(url, buildURL(apiUrl, action.url), {\n            ...action,\n            responseType: 'blob'\n        });\n\n        request.onload = (xhr) => {\n            \n            // get headers\n            const headers = xhr.getAllResponseHeaders();\n            \n            // get filename\n            const filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n            // create response\n            load(\n                createResponse(\n                    'load',\n                    xhr.status,\n                    action.method === 'HEAD' ? null : getFileFromBlob(onload(xhr.response), filename),\n                    headers\n                )\n            )\n        };\n\n        request.onerror = (xhr) => {\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n        };    \n\n        request.onheaders = (xhr) => {\n            headers(\n                createResponse(\n                    'headers',\n                    xhr.status,\n                    null,\n                    xhr.getAllResponseHeaders()\n                )\n            )\n        }\n\n        request.ontimeout = createTimeoutResponse(error);\n        request.onprogress = progress;\n        request.onabort = abort;\n\n        // should return request\n        return request;\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/createFileLoader.js",
    "content": "import { isBase64DataURI } from '../../utils/isBase64DataURI';\nimport { getFilenameFromURL } from '../../utils/getFilenameFromURL';\nimport { getFileFromBase64DataURI } from '../../utils/getFileFromBase64DataURI';\nimport { getFileFromBlob } from '../../utils/getFileFromBlob';\nimport { getFileInfoFromHeaders } from '../../utils/getFileInfoFromHeaders';\nimport { on } from '../utils/on';\n\nexport const createFileLoader = fetchFn => {\n    const state = {\n        source: null,\n        complete: false,\n        progress: 0,\n        size: null,\n        timestamp: null,\n        duration: 0,\n        request: null\n    };\n\n    const getProgress = () => state.progress;\n    const abort = () => {\n        if (state.request && state.request.abort) {\n            state.request.abort();\n        }\n    };\n\n    // load source\n    const load = () => {\n        // get quick reference\n        const source = state.source;\n\n        api.fire('init', source);\n\n        // Load Files\n        if (source instanceof File) {\n            api.fire('load', source);\n        } else if (source instanceof Blob) {\n            // Load blobs, set default name to current date\n            api.fire('load', getFileFromBlob(source, source.name));\n        } else if (isBase64DataURI(source)) {\n            // Load base 64, set default name to current date\n            api.fire('load', getFileFromBase64DataURI(source));\n        } else {\n            // Deal as if is external URL, let's load it!\n            loadURL(source);\n        }\n    };\n\n    // loads a url\n    const loadURL = url => {\n\n        // is remote url and no fetch method supplied\n        if (!fetchFn) {\n            api.fire('error', {\n                type: 'error',\n                body: 'Can\\'t load URL',\n                code: 400\n            });\n            return;\n        }\n\n        // set request start\n        state.timestamp = Date.now();\n\n        // load file\n        state.request = fetchFn(\n            url,\n            response => {\n\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // done!\n                state.complete = true;\n\n                // turn blob response into a file\n                if (response instanceof Blob) {\n                    response = getFileFromBlob(\n                        response, \n                        response.name || getFilenameFromURL(url)\n                    );\n                }\n\n                api.fire(\n                    'load',\n                    // if has received blob, we go with blob, if no response, we return null\n                    response instanceof Blob \n                        ? response \n                        : response \n                            ? response.body\n                            : null\n                );\n            },\n            error => {\n                api.fire(\n                    'error',\n                    typeof error === 'string'\n                        ? {\n                              type: 'error',\n                              code: 0,\n                              body: error\n                          }\n                        : error\n                );\n            },\n            (computable, current, total) => {\n                // collected some meta data already\n                if (total) {\n                    state.size = total;\n                }\n\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // if we can't compute progress, we're not going to fire progress events\n                if (!computable) {\n                    state.progress = null;\n                    return;\n                }\n\n                // update progress percentage\n                state.progress = current / total;\n\n                // expose\n                api.fire('progress', state.progress);\n            },\n            () => {\n                api.fire('abort');\n            },\n            response => {\n                const fileinfo = getFileInfoFromHeaders(typeof response === 'string' ? response : response.headers);\n                api.fire('meta', {\n                    size: state.size || fileinfo.size,\n                    filename: fileinfo.name,\n                    source: fileinfo.source\n                });\n            }\n        );\n    };\n\n    const api = {\n        ...on(),\n        setSource: source => state.source = source,\n        getProgress, // file load progress\n        abort, // abort file load\n        load // start load\n    };\n\n    return api;\n};\n"
  },
  {
    "path": "src/js/app/utils/createFileProcessor.js",
    "content": "import { createPerceivedPerformanceUpdater } from './createPerceivedPerformanceUpdater';\nimport { getRandomNumber } from '../../utils/getRandomNumber';\nimport { on } from '../utils/on';\nimport { isObject } from '../../utils/isObject';\n\nexport const createFileProcessor = (processFn, options) => {\n    const state = {\n        complete: false,\n        perceivedProgress: 0,\n        perceivedPerformanceUpdater: null,\n        progress: null,\n        timestamp: null,\n        perceivedDuration: 0,\n        duration: 0,\n        request: null,\n        response: null,\n    };\n\n    const { allowMinimumUploadDuration } = options;\n\n    const process = (file, metadata) => {\n        const progressFn = () => {\n            // we've not yet started the real download, stop here\n            // the request might not go through, for instance, there might be some server trouble\n            // if state.progress is null, the server does not allow computing progress and we show the spinner instead\n            if (state.duration === 0 || state.progress === null) return;\n\n            // as we're now processing, fire the progress event\n            api.fire('progress', api.getProgress());\n        };\n\n        const completeFn = () => {\n            state.complete = true;\n            api.fire('load-perceived', state.response.body);\n        };\n\n        // let's start processing\n        api.fire('start');\n\n        // set request start\n        state.timestamp = Date.now();\n\n        // create perceived performance progress indicator\n        state.perceivedPerformanceUpdater = createPerceivedPerformanceUpdater(\n            progress => {\n                state.perceivedProgress = progress;\n                state.perceivedDuration = Date.now() - state.timestamp;\n\n                progressFn();\n\n                // if fake progress is done, and a response has been received,\n                // and we've not yet called the complete method\n                if (state.response && state.perceivedProgress === 1 && !state.complete) {\n                    // we done!\n                    completeFn();\n                }\n            },\n            // random delay as in a list of files you start noticing\n            // files uploading at the exact same speed\n            allowMinimumUploadDuration ? getRandomNumber(750, 1500) : 0\n        );\n\n        // remember request so we can abort it later\n        state.request = processFn(\n            // the file to process\n            file,\n\n            // the metadata to send along\n            metadata,\n\n            // callbacks (load, error, progress, abort, transfer)\n            // load expects the body to be a server id if\n            // you want to make use of revert\n            response => {\n                // we put the response in state so we can access\n                // it outside of this method\n                state.response = isObject(response)\n                    ? response\n                    : {\n                          type: 'load',\n                          code: 200,\n                          body: `${response}`,\n                          headers: {},\n                      };\n\n                // update duration\n                state.duration = Date.now() - state.timestamp;\n\n                // force progress to 1 as we're now done\n                state.progress = 1;\n\n                // actual load is done let's share results\n                api.fire('load', state.response.body);\n\n                // we are really done\n                // if perceived progress is 1 ( wait for perceived progress to complete )\n                // or if server does not support progress ( null )\n                if (\n                    !allowMinimumUploadDuration ||\n                    (allowMinimumUploadDuration && state.perceivedProgress === 1)\n                ) {\n                    completeFn();\n                }\n            },\n\n            // error is expected to be an object with type, code, body\n            error => {\n                // cancel updater\n                state.perceivedPerformanceUpdater.clear();\n\n                // update others about this error\n                api.fire(\n                    'error',\n                    isObject(error)\n                        ? error\n                        : {\n                              type: 'error',\n                              code: 0,\n                              body: `${error}`,\n                          }\n                );\n            },\n\n            // actual processing progress\n            (computable, current, total) => {\n                // update actual duration\n                state.duration = Date.now() - state.timestamp;\n\n                // update actual progress\n                state.progress = computable ? current / total : null;\n\n                progressFn();\n            },\n\n            // abort does not expect a value\n            () => {\n                // stop updater\n                state.perceivedPerformanceUpdater.clear();\n\n                // fire the abort event so we can switch visuals\n                api.fire('abort', state.response ? state.response.body : null);\n            },\n\n            // register the id for this transfer\n            transferId => {\n                api.fire('transfer', transferId);\n            }\n        );\n    };\n\n    const abort = () => {\n        // no request running, can't abort\n        if (!state.request) return;\n\n        // stop updater\n        state.perceivedPerformanceUpdater.clear();\n\n        // abort actual request\n        if (state.request.abort) state.request.abort();\n\n        // if has response object, we've completed the request\n        state.complete = true;\n    };\n\n    const reset = () => {\n        abort();\n        state.complete = false;\n        state.perceivedProgress = 0;\n        state.progress = 0;\n        state.timestamp = null;\n        state.perceivedDuration = 0;\n        state.duration = 0;\n        state.request = null;\n        state.response = null;\n    };\n\n    const getProgress = allowMinimumUploadDuration\n        ? () => (state.progress ? Math.min(state.progress, state.perceivedProgress) : null)\n        : () => state.progress || null;\n\n    const getDuration = allowMinimumUploadDuration\n        ? () => Math.min(state.duration, state.perceivedDuration)\n        : () => state.duration;\n\n    const api = {\n        ...on(),\n        process, // start processing file\n        abort, // abort active process request\n        getProgress,\n        getDuration,\n        reset,\n    };\n\n    return api;\n};\n"
  },
  {
    "path": "src/js/app/utils/createFileProcessorFunction.js",
    "content": "import { sendRequest } from '../../utils/sendRequest';\nimport { createResponse } from '../../utils/createResponse';\nimport { createTimeoutResponse } from '../../utils/createDefaultResponse';\nimport { isObject } from '../../utils/isObject';\nimport { buildURL } from './buildURL';\n\nimport { processFileChunked } from './processFileChunked';\n\n/*\nfunction signature:\n  (file, metadata, load, error, progress, abort) => {\n    return {\n    abort:() => {}\n  }\n}\n*/\nexport const createFileProcessorFunction = (apiUrl, action, name, options) => (\n    file,\n    metadata,\n    load,\n    error,\n    progress,\n    abort,\n    transfer\n) => {\n    // no file received\n    if (!file) return;\n\n    // if was passed a file, and we can chunk it, exit here\n    const canChunkUpload = options.chunkUploads;\n    const shouldChunkUpload = canChunkUpload && file.size > options.chunkSize;\n    const willChunkUpload = canChunkUpload && (shouldChunkUpload || options.chunkForce);\n    if (file instanceof Blob && willChunkUpload)\n        return processFileChunked(\n            apiUrl,\n            action,\n            name,\n            file,\n            metadata,\n            load,\n            error,\n            progress,\n            abort,\n            transfer,\n            options\n        );\n\n    // set handlers\n    const ondata = action.ondata || (fd => fd);\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    const headers =\n        typeof action.headers === 'function'\n            ? action.headers(file, metadata) || {}\n            : {\n                  ...action.headers,\n              };\n\n    const requestParams = {\n        ...action,\n        headers,\n    };\n\n    // create formdata object\n    var formData = new FormData();\n\n    // add metadata under same name\n    if (isObject(metadata)) {\n        formData.append(name, JSON.stringify(metadata));\n    }\n\n    // Turn into an array of objects so no matter what the input, we can handle it the same way\n    (file instanceof Blob ? [{ name: null, file }] : file).forEach(item => {\n        formData.append(\n            name,\n            item.file,\n            item.name === null ? item.file.name : `${item.name}${item.file.name}`\n        );\n    });\n\n    // send request object\n    const request = sendRequest(ondata(formData), buildURL(apiUrl, action.url), requestParams);\n    request.onload = xhr => {\n        load(createResponse('load', xhr.status, onload(xhr.response), xhr.getAllResponseHeaders()));\n    };\n\n    request.onerror = xhr => {\n        error(\n            createResponse(\n                'error',\n                xhr.status,\n                onerror(xhr.response) || xhr.statusText,\n                xhr.getAllResponseHeaders()\n            )\n        );\n    };\n\n    request.ontimeout = createTimeoutResponse(error);\n    request.onprogress = progress;\n    request.onabort = abort;\n\n    // should return request\n    return request;\n};\n"
  },
  {
    "path": "src/js/app/utils/createFileStub.js",
    "content": "import { getMimeTypeFromBase64DataURI } from '../../utils/getMimeTypeFromBase64DataURI';\nimport { getFilenameFromURL } from '../../utils/getFilenameFromURL';\nimport { isBase64DataURI } from '../../utils/isBase64DataURI';\nimport { isString } from '../../utils/isString';\nimport { getDateString } from '../../utils/getDateString';\n\nexport const createFileStub = source => {\n    let data = [source.name, source.size, source.type];\n\n    // is blob or base64, then we need to set the name\n    if (source instanceof Blob || isBase64DataURI(source)) {\n        data[0] = source.name || getDateString();\n    } else if (isBase64DataURI(source)) {\n        // if is base64 data uri we need to determine the average size and type\n        data[1] = source.length;\n        data[2] = getMimeTypeFromBase64DataURI(source);\n    } else if (isString(source)) {\n        // url\n        data[0] = getFilenameFromURL(source);\n        data[1] = 0;\n        data[2] = 'application/octet-stream';\n    }\n\n    return {\n        name: data[0],\n        size: data[1],\n        type: data[2]\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/createHopper.js",
    "content": "import { createDragNDropClient } from '../utils/dnd';\n\nexport const createHopper = (scope, validateItems, options) => {\n    // is now hopper scope\n    scope.classList.add('filepond--hopper');\n\n    // shortcuts\n    const { catchesDropsOnPage, requiresDropOnElement, filterItems = items => items } = options;\n\n    // create a dnd client\n    const client = createDragNDropClient(\n        scope,\n        catchesDropsOnPage ? document.documentElement : scope,\n        requiresDropOnElement\n    );\n\n    // current client state\n    let lastState = '';\n    let currentState = '';\n\n    // determines if a file may be dropped\n    client.allowdrop = items => {\n        // TODO: if we can, throw error to indicate the items cannot by dropped\n\n        return validateItems(filterItems(items));\n    };\n\n    client.ondrop = (position, items) => {\n\n        const filteredItems = filterItems(items);\n\n        if (!validateItems(filteredItems)) {\n            api.ondragend(position);\n            return;\n        }\n\n        currentState = 'drag-drop';\n\n        api.onload(filteredItems, position);\n    };\n\n    client.ondrag = position => {\n        api.ondrag(position);\n    };\n\n    client.onenter = position => {\n        currentState = 'drag-over';\n\n        api.ondragstart(position);\n    };\n\n    client.onexit = position => {\n        currentState = 'drag-exit';\n\n        api.ondragend(position);\n    };\n\n    const api = {\n        updateHopperState: () => {\n            if (lastState !== currentState) {\n                scope.dataset.hopperState = currentState;\n                lastState = currentState;\n            }\n        },\n        onload: () => {},\n        ondragstart: () => {},\n        ondrag: () => {},\n        ondragend: () => {},\n        destroy: () => {\n            // destroy client\n            client.destroy();\n        }\n    };\n\n    return api;\n};\n"
  },
  {
    "path": "src/js/app/utils/createInitialState.js",
    "content": "import { createOptions } from './createOptions';\n\nexport const createInitialState = options => ({\n\n    // model\n    items: [],\n\n    // timeout used for calling update items\n    listUpdateTimeout: null,\n\n    // timeout used for stacking metadata updates\n    itemUpdateTimeout: null,\n    \n    // queue of items waiting to be processed\n    processingQueue: [],\n\n    // options\n    options: createOptions(options)\n});\n"
  },
  {
    "path": "src/js/app/utils/createItem.js",
    "content": "import { getUniqueId } from '../../utils/getUniqueId';\nimport { getFilenameWithoutExtension } from '../../utils/getFilenameWithoutExtension';\nimport { getExtensionFromFilename } from '../../utils/getExtensionFromFilename';\nimport { ItemStatus } from '../enum/ItemStatus';\nimport { on } from './on';\nimport { createFileStub } from './createFileStub';\nimport { createObject } from '../../utils/createObject';\nimport { FileOrigin } from '../../app/enum/FileOrigin';\nimport { isObject } from '../../utils/isObject';\nimport { isFile } from '../../utils/isFile';\nimport { deepCloneObject } from '../../utils/deepCloneObject';\n\nexport const createItem = (origin = null, serverFileReference = null, file = null) => {\n    // unique id for this item, is used to identify the item across views\n    const id = getUniqueId();\n\n    /**\n     * Internal item state\n     */\n    const state = {\n        // is archived\n        archived: false,\n\n        // if is frozen, no longer fires events\n        frozen: false,\n\n        // removed from view\n        released: false,\n\n        // original source\n        source: null,\n\n        // file model reference\n        file,\n\n        // id of file on server\n        serverFileReference,\n\n        // id of file transfer on server\n        transferId: null,\n\n        // is aborted\n        processingAborted: false,\n\n        // current item status\n        status: serverFileReference ? ItemStatus.PROCESSING_COMPLETE : ItemStatus.INIT,\n\n        // active processes\n        activeLoader: null,\n        activeProcessor: null,\n    };\n\n    // callback used when abort processing is called to link back to the resolve method\n    let abortProcessingRequestComplete = null;\n\n    /**\n     * Externally added item metadata\n     */\n    const metadata = {};\n\n    // item data\n    const setStatus = status => (state.status = status);\n\n    // fire event unless the item has been archived\n    const fire = (event, ...params) => {\n        if (state.released || state.frozen) return;\n        api.fire(event, ...params);\n    };\n\n    // file data\n    const getFileExtension = () => getExtensionFromFilename(state.file.name);\n    const getFileType = () => state.file.type;\n    const getFileSize = () => state.file.size;\n    const getFile = () => state.file;\n\n    //\n    // logic to load a file\n    //\n    const load = (source, loader, onload) => {\n        // remember the original item source\n        state.source = source;\n\n        // source is known\n        api.fireSync('init');\n\n        // file stub is already there\n        if (state.file) {\n            api.fireSync('load-skip');\n            return;\n        }\n\n        // set a stub file object while loading the actual data\n        state.file = createFileStub(source);\n\n        // starts loading\n        loader.on('init', () => {\n            fire('load-init');\n        });\n\n        // we'eve received a size indication, let's update the stub\n        loader.on('meta', meta => {\n            // set size of file stub\n            state.file.size = meta.size;\n\n            // set name of file stub\n            state.file.filename = meta.filename;\n\n            // if has received source, we done\n            if (meta.source) {\n                origin = FileOrigin.LIMBO;\n                state.serverFileReference = meta.source;\n                state.status = ItemStatus.PROCESSING_COMPLETE;\n            }\n\n            // size has been updated\n            fire('load-meta');\n        });\n\n        // the file is now loading we need to update the progress indicators\n        loader.on('progress', progress => {\n            setStatus(ItemStatus.LOADING);\n\n            fire('load-progress', progress);\n        });\n\n        // an error was thrown while loading the file, we need to switch to error state\n        loader.on('error', error => {\n            setStatus(ItemStatus.LOAD_ERROR);\n\n            fire('load-request-error', error);\n        });\n\n        // user or another process aborted the file load (cannot retry)\n        loader.on('abort', () => {\n            setStatus(ItemStatus.INIT);\n            fire('load-abort');\n        });\n\n        // done loading\n        loader.on('load', file => {\n            // as we've now loaded the file the loader is no longer required\n            state.activeLoader = null;\n\n            // called when file has loaded succesfully\n            const success = result => {\n                // set (possibly) transformed file\n                state.file = isFile(result) ? result : state.file;\n\n                // file received\n                if (origin === FileOrigin.LIMBO && state.serverFileReference) {\n                    setStatus(ItemStatus.PROCESSING_COMPLETE);\n                } else {\n                    setStatus(ItemStatus.IDLE);\n                }\n\n                fire('load');\n            };\n\n            const error = result => {\n                // set original file\n                state.file = file;\n                fire('load-meta');\n\n                setStatus(ItemStatus.LOAD_ERROR);\n                fire('load-file-error', result);\n            };\n\n            // if we already have a server file reference, we don't need to call the onload method\n            if (state.serverFileReference) {\n                success(file);\n                return;\n            }\n\n            // no server id, let's give this file the full treatment\n            onload(file, success, error);\n        });\n\n        // set loader source data\n        loader.setSource(source);\n\n        // set as active loader\n        state.activeLoader = loader;\n\n        // load the source data\n        loader.load();\n    };\n\n    const retryLoad = () => {\n        if (!state.activeLoader) {\n            return;\n        }\n        state.activeLoader.load();\n    };\n\n    const abortLoad = () => {\n        if (state.activeLoader) {\n            state.activeLoader.abort();\n            return;\n        }\n        setStatus(ItemStatus.INIT);\n        fire('load-abort');\n    };\n\n    //\n    // logic to process a file\n    //\n    const process = (processor, onprocess) => {\n        // processing was aborted\n        if (state.processingAborted) {\n            state.processingAborted = false;\n            return;\n        }\n\n        // now processing\n        setStatus(ItemStatus.PROCESSING);\n\n        // reset abort callback\n        abortProcessingRequestComplete = null;\n\n        // if no file loaded we'll wait for the load event\n        if (!(state.file instanceof Blob)) {\n            api.on('load', () => {\n                process(processor, onprocess);\n            });\n            return;\n        }\n\n        // setup processor\n        processor.on('load', serverFileReference => {\n            // need this id to be able to revert the upload\n            state.transferId = null;\n            state.serverFileReference = serverFileReference;\n        });\n\n        // register transfer id\n        processor.on('transfer', transferId => {\n            // need this id to be able to revert the upload\n            state.transferId = transferId;\n        });\n\n        processor.on('load-perceived', serverFileReference => {\n            // no longer required\n            state.activeProcessor = null;\n\n            // need this id to be able to rever the upload\n            state.transferId = null;\n            state.serverFileReference = serverFileReference;\n\n            setStatus(ItemStatus.PROCESSING_COMPLETE);\n            fire('process-complete', serverFileReference);\n        });\n\n        processor.on('start', () => {\n            fire('process-start');\n        });\n\n        processor.on('error', error => {\n            state.activeProcessor = null;\n            setStatus(ItemStatus.PROCESSING_ERROR);\n            fire('process-error', error);\n        });\n\n        processor.on('abort', serverFileReference => {\n            state.activeProcessor = null;\n\n            // if file was uploaded but processing was cancelled during perceived processor time store file reference\n            state.serverFileReference = serverFileReference;\n\n            setStatus(ItemStatus.IDLE);\n            fire('process-abort');\n\n            // has timeout so doesn't interfere with remove action\n            if (abortProcessingRequestComplete) {\n                abortProcessingRequestComplete();\n            }\n        });\n\n        processor.on('progress', progress => {\n            fire('process-progress', progress);\n        });\n\n        // when successfully transformed\n        const success = file => {\n            // if was archived in the mean time, don't process\n            if (state.archived) return;\n\n            // process file!\n            processor.process(file, { ...metadata });\n        };\n\n        // something went wrong during transform phase\n        const error = console.error;\n\n        // start processing the file\n        onprocess(state.file, success, error);\n\n        // set as active processor\n        state.activeProcessor = processor;\n    };\n\n    const requestProcessing = () => {\n        state.processingAborted = false;\n        setStatus(ItemStatus.PROCESSING_QUEUED);\n    };\n\n    const abortProcessing = () =>\n        new Promise(resolve => {\n            if (!state.activeProcessor) {\n                state.processingAborted = true;\n\n                setStatus(ItemStatus.IDLE);\n                fire('process-abort');\n\n                resolve();\n                return;\n            }\n\n            abortProcessingRequestComplete = () => {\n                resolve();\n            };\n\n            state.activeProcessor.abort();\n        });\n\n    //\n    // logic to revert a processed file\n    //\n    const revert = (revertFileUpload, forceRevert) =>\n        new Promise((resolve, reject) => {\n            // a completed upload will have a serverFileReference, a failed chunked upload where\n            // getting a serverId succeeded but >=0 chunks have been uploaded will have transferId set\n            const serverTransferId =\n                state.serverFileReference !== null ? state.serverFileReference : state.transferId;\n\n            // cannot revert without a server id for this process\n            if (serverTransferId === null) {\n                resolve();\n                return;\n            }\n\n            // revert the upload (fire and forget)\n            revertFileUpload(\n                serverTransferId,\n                () => {\n                    // reset file server id and transfer id as now it's not available on the server\n                    state.serverFileReference = null;\n                    state.transferId = null;\n                    resolve();\n                },\n                error => {\n                    // don't set error state when reverting is optional, it will always resolve\n                    if (!forceRevert) {\n                        resolve();\n                        return;\n                    }\n\n                    // oh no errors\n                    setStatus(ItemStatus.PROCESSING_REVERT_ERROR);\n                    fire('process-revert-error');\n                    reject(error);\n                }\n            );\n\n            // fire event\n            setStatus(ItemStatus.IDLE);\n            fire('process-revert');\n        });\n\n    // exposed methods\n    const setMetadata = (key, value, silent) => {\n        const keys = key.split('.');\n        const root = keys[0];\n        const last = keys.pop();\n        let data = metadata;\n        keys.forEach(key => (data = data[key]));\n\n        // compare old value against new value, if they're the same, we're not updating\n        if (JSON.stringify(data[last]) === JSON.stringify(value)) return;\n\n        // update value\n        data[last] = value;\n\n        // fire update\n        fire('metadata-update', {\n            key: root,\n            value: metadata[root],\n            silent,\n        });\n    };\n\n    const getMetadata = key => deepCloneObject(key ? metadata[key] : metadata);\n\n    const api = {\n        id: { get: () => id },\n        origin: { get: () => origin, set: value => (origin = value) },\n        serverId: { get: () => state.serverFileReference },\n        transferId: { get: () => state.transferId },\n        status: { get: () => state.status },\n        filename: { get: () => state.file.name },\n        filenameWithoutExtension: { get: () => getFilenameWithoutExtension(state.file.name) },\n        fileExtension: { get: getFileExtension },\n        fileType: { get: getFileType },\n        fileSize: { get: getFileSize },\n        file: { get: getFile },\n        relativePath: { get: () => state.file._relativePath },\n\n        source: { get: () => state.source },\n\n        getMetadata,\n        setMetadata: (key, value, silent) => {\n            if (isObject(key)) {\n                const data = key;\n                Object.keys(data).forEach(key => {\n                    setMetadata(key, data[key], value);\n                });\n                return key;\n            }\n            setMetadata(key, value, silent);\n            return value;\n        },\n\n        extend: (name, handler) => (itemAPI[name] = handler),\n\n        abortLoad,\n        retryLoad,\n        requestProcessing,\n        abortProcessing,\n\n        load,\n        process,\n        revert,\n\n        ...on(),\n\n        freeze: () => (state.frozen = true),\n\n        release: () => (state.released = true),\n        released: { get: () => state.released },\n\n        archive: () => (state.archived = true),\n        archived: { get: () => state.archived },\n\n        // replace source and file object\n        setFile: file => (state.file = file),\n    };\n\n    // create it here instead of returning it instantly so we can extend it later\n    const itemAPI = createObject(api);\n\n    return itemAPI;\n};\n"
  },
  {
    "path": "src/js/app/utils/createItemAPI.js",
    "content": "import { copyObjectPropertiesToObject } from '../../utils/copyObjectPropertiesToObject';\n\nconst PRIVATE = [\n    'fire',\n    'process',\n    'revert',\n    'load',\n    'on',\n    'off',\n    'onOnce',\n    'retryLoad',\n    'extend',\n    'archive',\n    'archived',\n    'release',\n    'released',\n    'requestProcessing',\n    'freeze'\n];\n\nexport const createItemAPI = item => {\n    const api = {};\n    copyObjectPropertiesToObject(item, api, PRIVATE);\n    return api;\n};"
  },
  {
    "path": "src/js/app/utils/createOption.js",
    "content": "import { getValueByType } from './getValueByType';\n\nexport const createOption = (defaultValue, valueType) => {\n    let currentValue = defaultValue;\n    return {\n        enumerable: true,\n        get: () => currentValue,\n        set: newValue => {\n            currentValue = getValueByType(newValue, defaultValue, valueType);\n        }\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/createOptionAPI.js",
    "content": "import { fromCamels } from '../../utils/fromCamels';\nimport { forin } from '../../utils/forin';\n\nexport const createOptionAPI = (store, options) => {\n    const obj = {};\n    forin(options, key => {\n        obj[key] = {\n            get: () => store.getState().options[key],\n            set: value => {\n                store.dispatch(`SET_${fromCamels(key, '_').toUpperCase()}`, {\n                    value\n                });\n            }\n        };\n    });\n    return obj;\n};\n"
  },
  {
    "path": "src/js/app/utils/createOptionActions.js",
    "content": "import { fromCamels } from '../../utils/fromCamels';\nimport { forin } from '../../utils/forin';\n\nexport const createOptionActions = options => (dispatch, query, state) => {\n    const obj = {};\n    forin(options, key => {\n        const name = fromCamels(key, '_').toUpperCase();\n        \n        obj[`SET_${name}`] = action => {\n            try {\n                state.options[key] = action.value;\n            } catch (e) {\n                // nope, failed\n            }\n\n            // we successfully set the value of this option\n            dispatch(`DID_SET_${name}`, { value: state.options[key] });\n        };\n    });\n    return obj;\n};\n"
  },
  {
    "path": "src/js/app/utils/createOptionQueries.js",
    "content": "import { fromCamels } from '../../utils/fromCamels';\nimport { forin } from '../../utils/forin';\n\nexport const createOptionQueries = options => state => {\n    const obj = {};\n    forin(options, key => {\n        obj[`GET_${fromCamels(key, '_').toUpperCase()}`] = action =>\n            state.options[key];\n    });\n    return obj;\n};\n"
  },
  {
    "path": "src/js/app/utils/createOptions.js",
    "content": "import { createObject } from '../../utils/createObject';\nimport { createOption } from './createOption';\nimport { forin } from '../../utils/forin';\n\nexport const createOptions = options => {\n    const obj = {};\n    forin(options, prop => {\n        const optionDefinition = options[prop];\n        obj[prop] = createOption(\n            optionDefinition[0],\n            optionDefinition[1]\n        );\n    });\n    return createObject(obj);\n};\n"
  },
  {
    "path": "src/js/app/utils/createPaster.js",
    "content": "import { arrayRemove } from '../../utils/arrayRemove';\nimport { requestDataTransferItems } from './requestDataTransferItems';\n\nlet listening = false;\nconst listeners = [];\n\nconst handlePaste = e => {\n    // if is pasting in input or textarea and the target is outside of a filepond scope, ignore\n    const activeEl = document.activeElement;\n    const isActiveElementEditable =\n        activeEl &&\n        (/textarea|input/i.test(activeEl.nodeName) ||\n            activeEl.getAttribute('contenteditable') === 'true' ||\n            activeEl.getAttribute('contenteditable') === '');\n\n    if (isActiveElementEditable) {\n        // test textarea or input is contained in filepond root\n        let inScope = false;\n        let element = activeEl;\n        while (element !== document.body) {\n            if (element.classList.contains('filepond--root')) {\n                inScope = true;\n                break;\n            }\n            element = element.parentNode;\n        }\n\n        if (!inScope) return;\n    }\n    \n    requestDataTransferItems(e.clipboardData).then(files => {\n        // no files received\n        if (!files.length) {\n            return;\n        }\n\n        // notify listeners of received files\n        listeners.forEach(listener => listener(files));\n    });\n};\n\nconst listen = cb => {\n    // can't add twice\n    if (listeners.includes(cb)) {\n        return;\n    }\n\n    // add initial listener\n    listeners.push(cb);\n\n    // setup paste listener for entire page\n    if (listening) {\n        return;\n    }\n\n    listening = true;\n    document.addEventListener('paste', handlePaste);\n};\n\nconst unlisten = listener => {\n    arrayRemove(listeners, listeners.indexOf(listener));\n\n    // clean up\n    if (listeners.length === 0) {\n        document.removeEventListener('paste', handlePaste);\n        listening = false;\n    }\n};\n\nexport const createPaster = () => {\n    const cb = files => {\n        api.onload(files);\n    };\n\n    const api = {\n        destroy: () => {\n            unlisten(cb);\n        },\n        onload: () => {}\n    };\n\n    listen(cb);\n\n    return api;\n};\n"
  },
  {
    "path": "src/js/app/utils/createPerceivedPerformanceUpdater.js",
    "content": "import { getRandomNumber } from '../../utils/getRandomNumber';\n\nexport const createPerceivedPerformanceUpdater = (\n    cb,\n    duration = 1000,\n    offset = 0,\n    tickMin = 25,\n    tickMax = 250\n) => {\n    let timeout = null;\n    const start = Date.now();\n\n    const tick = () => {\n        let runtime = Date.now() - start;\n        let delay = getRandomNumber(tickMin, tickMax);\n\n        if (runtime + delay > duration) {\n            delay = runtime + delay - duration;\n        }\n\n        let progress = runtime / duration;\n        if (progress >= 1 || document.hidden) {\n            cb(1);\n            return;\n        }\n\n        cb(progress);\n\n        timeout = setTimeout(tick, delay);\n    };\n\n    if (duration > 0) tick();\n\n    return {\n        clear: () => {\n            clearTimeout(timeout);\n        },\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/createProcessorFunction.js",
    "content": "import { isString } from '../../utils/isString';\nimport { createFileProcessorFunction } from './createFileProcessorFunction';\n\nexport const createProcessorFunction = (apiUrl = '', action, name, options) => {\n    \n    // custom handler (should also handle file, load, error, progress and abort)\n    if (typeof action === 'function') return (...params) => action(name, ...params, options);\n\n    // no action supplied\n    if (!action || !isString(action.url)) return null;\n\n    // internal handler\n    return createFileProcessorFunction(apiUrl, action, name, options);\n};"
  },
  {
    "path": "src/js/app/utils/createRevertFunction.js",
    "content": "import { sendRequest } from '../../utils/sendRequest';\nimport { createResponse } from '../../utils/createResponse';\nimport { createTimeoutResponse } from '../../utils/createDefaultResponse';\nimport { isString } from '../../utils/isString';\n\n/*\n function signature:\n (uniqueFileId, load, error) => { }\n */\nexport const createRevertFunction = (apiUrl = '', action) => {\n    // is custom implementation\n    if (typeof action === 'function') {\n        return action;\n    }\n\n    // no action supplied, return stub function, interface will work, but file won't be removed\n    if (!action || !isString(action.url)) {\n        return (uniqueFileId, load) => load();\n    }\n\n    // set onload hanlder\n    const onload = action.onload || (res => res);\n    const onerror = action.onerror || (res => null);\n\n    // internal implementation\n    return (uniqueFileId, load, error) => {\n        const request = sendRequest(\n            uniqueFileId,\n            apiUrl + action.url,\n            action // contains method, headers and withCredentials properties\n        );\n        request.onload = (xhr) => {\n            load(\n                createResponse(\n                    'load',\n                    xhr.status,\n                    onload(xhr.response),\n                    xhr.getAllResponseHeaders()\n                )\n            )    \n        };\n\n        request.onerror = (xhr) => {\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n        };    \n\n        request.ontimeout = createTimeoutResponse(error);\n\n        return request;\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/createServerAPI.js",
    "content": "import { isString } from '../../utils/isString';\nimport { toBoolean } from '../../utils/toBoolean';\nimport { forin } from '../../utils/forin';\n\nconst methods = {\n    process: 'POST',\n    patch: 'PATCH',\n    revert: 'DELETE',\n    fetch: 'GET',\n    restore: 'GET',\n    load: 'GET',\n};\n\nexport const createServerAPI = outline => {\n    const api = {};\n\n    api.url = isString(outline) ? outline : outline.url || '';\n    api.timeout = outline.timeout ? parseInt(outline.timeout, 10) : 0;\n    api.headers = outline.headers ? outline.headers : {};\n\n    forin(methods, key => {\n        api[key] = createAction(key, outline[key], methods[key], api.timeout, api.headers);\n    });\n\n    // remove process if no url or process on outline\n    api.process = outline.process || isString(outline) || outline.url ? api.process : null;\n\n    // special treatment for remove\n    api.remove = outline.remove || null;\n\n    // remove generic headers from api object\n    delete api.headers;\n\n    return api;\n};\n\nconst createAction = (name, outline, method, timeout, headers) => {\n    // is explicitely set to null so disable\n    if (outline === null) {\n        return null;\n    }\n\n    // if is custom function, done! Dev handles everything.\n    if (typeof outline === 'function') {\n        return outline;\n    }\n\n    // build action object\n    const action = {\n        url: method === 'GET' || method === 'PATCH' ? `?${name}=` : '',\n        method,\n        headers,\n        withCredentials: false,\n        timeout,\n        onload: null,\n        ondata: null,\n        onerror: null,\n    };\n\n    // is a single url\n    if (isString(outline)) {\n        action.url = outline;\n        return action;\n    }\n\n    // overwrite\n    Object.assign(action, outline);\n\n    // see if should reformat headers;\n    if (isString(action.headers)) {\n        const parts = action.headers.split(/:(.+)/);\n        action.headers = {\n            header: parts[0],\n            value: parts[1],\n        };\n    }\n\n    // if is bool withCredentials\n    action.withCredentials = toBoolean(action.withCredentials);\n\n    return action;\n};\n"
  },
  {
    "path": "src/js/app/utils/dnd.js",
    "content": "import { forin } from '../../utils/forin';\nimport { getRootNode } from '../../utils/getRootNode';\nimport { requestDataTransferItems } from './requestDataTransferItems';\n\nconst dragNDropObservers = [];\n\nconst eventPosition = e => ({\n    pageLeft: e.pageX,\n    pageTop: e.pageY,\n    scopeLeft: e.offsetX || e.layerX,\n    scopeTop: e.offsetY || e.layerY\n});\n\nexport const createDragNDropClient = (\n    element,\n    scopeToObserve,\n    filterElement\n) => {\n    const observer = getDragNDropObserver(scopeToObserve);\n\n    const client = {\n        element,\n        filterElement,\n        state: null,\n        ondrop: () => {},\n        onenter: () => {},\n        ondrag: () => {},\n        onexit: () => {},\n        onload: () => {},\n        allowdrop: () => {}\n    };\n\n    client.destroy = observer.addListener(client);\n\n    return client;\n};\n\nconst getDragNDropObserver = element => {\n    // see if already exists, if so, return\n    const observer = dragNDropObservers.find(item => item.element === element);\n    if (observer) {\n        return observer;\n    }\n\n    // create new observer, does not yet exist for this element\n    const newObserver = createDragNDropObserver(element);\n    dragNDropObservers.push(newObserver);\n    return newObserver;\n};\n\nconst createDragNDropObserver = element => {\n    const clients = [];\n\n    const routes = {\n        dragenter,\n        dragover,\n        dragleave,\n        drop\n    };\n\n    const handlers = {};\n\n    forin(routes, (event, createHandler) => {\n        handlers[event] = createHandler(element, clients);\n        element.addEventListener(event, handlers[event], false);\n    });\n\n    const observer = {\n        element,\n        addListener: client => {\n            // add as client\n            clients.push(client);\n\n            // return removeListener function\n            return () => {\n                // remove client\n                clients.splice(clients.indexOf(client), 1);\n\n                // if no more clients, clean up observer\n                if (clients.length === 0) {\n                    dragNDropObservers.splice(\n                        dragNDropObservers.indexOf(observer),\n                        1\n                    );\n\n                    forin(routes, event => {\n                        element.removeEventListener(\n                            event,\n                            handlers[event],\n                            false\n                        );\n                    });\n                }\n            };\n        }\n    };\n\n    return observer;\n};\n\nconst elementFromPoint = (root, point) => {\n    if (!('elementFromPoint' in root)) {\n        root = document;\n    }\n    return root.elementFromPoint(point.x, point.y);\n}\n\nconst isEventTarget = (e, target) => {\n    // get root\n    const root = getRootNode(target);\n\n    // get element at position\n    // if root is not actual shadow DOM and does not have elementFromPoint method, use the one on document\n    const elementAtPosition = elementFromPoint(root,{\n        x: e.pageX - window.pageXOffset,\n        y: e.pageY - window.pageYOffset\n    });\n\n    // test if target is the element or if one of its children is\n    return elementAtPosition === target || target.contains(elementAtPosition);\n};\n\nlet initialTarget = null;\n\nconst setDropEffect = (dataTransfer, effect) => {\n    // is in try catch as IE11 will throw error if not\n    try {\n        dataTransfer.dropEffect = effect;\n    } catch (e) {}\n};\n\nconst dragenter = (root, clients) => e => {\n    e.preventDefault();\n\n    initialTarget = e.target;\n\n    clients.forEach(client => {\n        const { element, onenter } = client;\n\n        if (isEventTarget(e, element)) {\n            client.state = 'enter';\n\n            // fire enter event\n            onenter(eventPosition(e));\n        }\n    });\n};\n\nconst dragover = (root, clients) => e => {\n    e.preventDefault();\n\n    const dataTransfer = e.dataTransfer;\n\n    requestDataTransferItems(dataTransfer).then(items => {\n\n        let overDropTarget = false;\n\n        clients.some(client => {\n            const {\n                filterElement,\n                element,\n                onenter,\n                onexit,\n                ondrag,\n                allowdrop\n            } = client;\n\n            // by default we can drop\n            setDropEffect(dataTransfer, 'copy');\n\n            // allow transfer of these items\n            const allowsTransfer = allowdrop(items);\n\n            // only used when can be dropped on page\n            if (!allowsTransfer) {\n                setDropEffect(dataTransfer, 'none');\n                return;\n            }\n\n            // targetting this client\n            if (isEventTarget(e, element)) {\n                \n                overDropTarget = true;\n\n                // had no previous state, means we are entering this client\n                if (client.state === null) {\n                    client.state = 'enter';\n                    onenter(eventPosition(e));\n                    return;\n                }\n\n                // now over element (no matter if it allows the drop or not)\n                client.state = 'over';\n\n                // needs to allow transfer\n                if (filterElement && !allowsTransfer) {\n                    setDropEffect(dataTransfer, 'none');\n                    return;\n                }\n\n                // dragging\n                ondrag(eventPosition(e));\n            } else {\n\n                // should be over an element to drop\n                if (filterElement && !overDropTarget) {\n                    setDropEffect(dataTransfer, 'none');\n                }\n\n                // might have just left this client?\n                if (client.state) {\n                    client.state = null;\n                    onexit(eventPosition(e));\n                }\n            }\n        });\n\n    });\n\n};\n\nconst drop = (root, clients) => e => {\n    e.preventDefault();\n\n    const dataTransfer = e.dataTransfer;\n\n    requestDataTransferItems(dataTransfer).then(items => {\n        clients.forEach(client => {\n            const {\n                filterElement,\n                element,\n                ondrop,\n                onexit,\n                allowdrop\n            } = client;\n\n            client.state = null;\n\n            // if we're filtering on element we need to be over the element to drop\n            if (filterElement && !isEventTarget(e, element)) return;\n\n            // no transfer for this client\n            if (!allowdrop(items)) return onexit(eventPosition(e));\n\n            // we can drop these items on this client\n            ondrop(eventPosition(e), items);\n        });\n    });\n};\n\nconst dragleave = (root, clients) => e => {\n    if (initialTarget !== e.target) {\n        return;\n    }\n\n    clients.forEach(client => {\n        const { onexit } = client;\n\n        client.state = null;\n\n        onexit(eventPosition(e));\n    });\n};\n"
  },
  {
    "path": "src/js/app/utils/dropAreaDimensions.js",
    "content": "export const dropAreaDimensions = {\n    height: 0,\n    width: 0,\n    get getHeight() {\n        return this.height;\n    },\n    set setHeight(val) {\n        if (this.height === 0 || val === 0) this.height = val;\n    },\n    get getWidth() {\n        return this.width;\n    },\n    set setWidth(val) {\n        if (this.width === 0 || val === 0) this.width = val;\n    },\n    setDimensions: function (height, width) {\n        if (this.height === 0 || height === 0) this.height = height;\n        if (this.width === 0 || width === 0) this.width = width;\n    }\n};"
  },
  {
    "path": "src/js/app/utils/dynamicLabel.js",
    "content": "import { isFunction } from '../../utils/isFunction';\n\nexport const dynamicLabel = (label) => (...params) => isFunction(label) ? label(...params) : label;"
  },
  {
    "path": "src/js/app/utils/fetchBlob.js",
    "content": "import { sendRequest } from '../../utils/sendRequest';\nimport { createResponse } from '../../utils/createResponse';\nimport { createTimeoutResponse } from '../../utils/createDefaultResponse';\nimport { getFileFromBlob } from '../../utils/getFileFromBlob';\nimport { getFileInfoFromHeaders } from '../../utils/getFileInfoFromHeaders';\nimport { getFilenameFromURL } from '../../utils/getFilenameFromURL';\n\nexport const fetchBlob = (url, load, error, progress, abort, headers) => {\n    const request = sendRequest(null, url, {\n        method: 'GET',\n        responseType: 'blob'\n    });\n\n    request.onload = (xhr) => {\n\n        // get headers\n        const headers = xhr.getAllResponseHeaders();\n\n        // get filename\n        const filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url);\n\n        // create response\n        load(\n            createResponse(\n                'load',\n                xhr.status,\n                getFileFromBlob(xhr.response, filename),\n                headers\n            )\n        )\n    };\n\n    request.onerror = (xhr) => {\n        error(\n            createResponse(\n                'error',\n                xhr.status,\n                xhr.statusText,\n                xhr.getAllResponseHeaders()\n            )\n        );\n    };\n\n    request.onheaders = (xhr) => {\n        headers(\n            createResponse(\n                'headers',\n                xhr.status,\n                null,\n                xhr.getAllResponseHeaders()\n            )\n        )\n    };\n\n    request.ontimeout = createTimeoutResponse(error);\n    request.onprogress = progress;\n    request.onabort = abort;\n\n\n    // should return request\n    return request;\n};\n"
  },
  {
    "path": "src/js/app/utils/getActiveItems.js",
    "content": "export const getActiveItems = (items) => items.filter(item => !item.archived);"
  },
  {
    "path": "src/js/app/utils/getItemById.js",
    "content": "import { getItemIndexByQuery } from './getItemIndexByQuery';\n\nexport const getItemById = (items, itemId) => {\n    const index = getItemIndexByQuery(items, itemId);\n    if (index < 0) {\n        return;\n    }\n    return items[index] || null;\n};\n"
  },
  {
    "path": "src/js/app/utils/getItemByQuery.js",
    "content": "import { isEmpty } from '../../utils/isEmpty';\nimport { isInt } from '../../utils/isInt';\n\nexport const getItemByQuery = (items, query) => {\n    // just return first index\n    if (isEmpty(query)) {\n        return items[0] || null;\n    }\n\n    // query is index\n    if (isInt(query)) {\n        return items[query] || null;\n    }\n\n    // if query is item, get the id\n    if (typeof query === 'object') {\n        query = query.id;\n    }\n\n    // assume query is a string and return item by id\n    return items.find(item => item.id === query) || null;\n};\n"
  },
  {
    "path": "src/js/app/utils/getItemIndexByPosition.js",
    "content": "import getItemsPerRow from './getItemsPerRow';\n\nexport const getItemIndexByPosition = (view, children, positionInView) => {\n    if (!positionInView) return;\n\n    const horizontalSpace = view.rect.element.width;\n    // const children = view.childViews;\n    const l = children.length;\n    let last = null;\n\n    // -1, don't move items to accomodate (either add to top or bottom)\n    if (l === 0 || positionInView.top < children[0].rect.element.top) return -1;\n\n    // let's get the item width\n    const item = children[0];\n    const itemRect = item.rect.element;\n    const itemHorizontalMargin = itemRect.marginLeft + itemRect.marginRight;\n    const itemWidth = itemRect.width + itemHorizontalMargin;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        for (let index = 0; index < l; index++) {\n            const child = children[index];\n            const childMid = child.rect.outer.top + child.rect.element.height * 0.5;\n            if (positionInView.top < childMid) {\n                return index;\n            }\n        }\n        return l;\n    }\n\n    // grid\n    const itemVerticalMargin = itemRect.marginTop + itemRect.marginBottom;\n    const itemHeight = itemRect.height + itemVerticalMargin;\n    for (let index = 0; index < l; index++) {\n        const indexX = index % itemsPerRow;\n        const indexY = Math.floor(index / itemsPerRow);\n\n        const offsetX = indexX * itemWidth;\n        const offsetY = indexY * itemHeight;\n\n        const itemTop = offsetY - itemRect.marginTop;\n        const itemRight = offsetX + itemWidth;\n        const itemBottom = offsetY + itemHeight + itemRect.marginBottom;\n\n        if (positionInView.top < itemBottom && positionInView.top > itemTop) {\n            if (positionInView.left < itemRight) {\n                return index;\n            } else if (index !== l - 1) {\n                last = index;\n            } else {\n                last = null;\n            }\n        }\n    }\n\n    if (last !== null) {\n        return last;\n    }\n\n    return l;\n};\n"
  },
  {
    "path": "src/js/app/utils/getItemIndexByQuery.js",
    "content": "import { isEmpty } from '../../utils/isEmpty';\nimport { isString } from '../../utils/isString';\n\nexport const getItemIndexByQuery = (items, query) => {\n    // just return first index\n    if (isEmpty(query)) {\n        return 0;\n    }\n\n    // invalid queries\n    if (!isString(query)) {\n        return -1;\n    }\n\n    // return item by id (or -1 if not found)\n    return items.findIndex(item => item.id === query);\n};\n"
  },
  {
    "path": "src/js/app/utils/getItemsPerRow.js",
    "content": "export default (horizontalSpace, itemWidth) => {\n    // add one pixel leeway, when using percentages for item width total items can be 1.99 per row\n\n    return Math.max(1, Math.floor((horizontalSpace + 1) / itemWidth));\n};\n"
  },
  {
    "path": "src/js/app/utils/getType.js",
    "content": "import { isArray } from '../../utils/isArray';\nimport { isInt } from '../../utils/isInt';\nimport { isNull } from '../../utils/isNull';\nimport { isAPI } from './isAPI';\n\nexport const getType = value => {\n    \n    if (isArray(value)) {\n        return 'array';\n    }\n\n    if (isNull(value)) {\n        return 'null';\n    }\n\n    if (isInt(value)) {\n        return 'int';\n    }\n\n    if (/^[0-9]+ ?(?:GB|MB|KB)$/gi.test(value)) {\n        return 'bytes';\n    }\n\n    if (isAPI(value)) {\n        return 'api';\n    }\n\n    return typeof value;\n};\n"
  },
  {
    "path": "src/js/app/utils/getValueByType.js",
    "content": "import { convertTo } from './convertTo';\nimport { getType } from './getType';\n\nexport const getValueByType = (newValue, defaultValue, valueType) => {\n\n    // can always assign default value\n    if (newValue === defaultValue) {\n        return newValue;\n    }\n\n    // get the type of the new value\n    let newValueType = getType(newValue);\n\n    // is valid type?\n    if (newValueType !== valueType) {\n        // is string input, let's attempt to convert\n        const convertedValue = convertTo(newValue, valueType);\n\n        // what is the type now\n        newValueType = getType(convertedValue);\n\n        // no valid conversions found\n        if (convertedValue === null) {\n            throw `Trying to assign value with incorrect type to \"${option}\", allowed type: \"${valueType}\"`;\n        } else {\n            newValue = convertedValue;\n        }\n    }\n\n    // assign new value\n    return newValue;\n}"
  },
  {
    "path": "src/js/app/utils/hasRoomForItem.js",
    "content": "import { getActiveItems } from './getActiveItems';\nexport const hasRoomForItem = state => {\n    const count = getActiveItems(state.items).length;\n\n    // if cannot have multiple items, to add one item it should currently not contain items\n    if (!state.options.allowMultiple) {\n        return count === 0;\n    }\n\n    // if allows multiple items, we check if a max item count has been set, if not, there's no limit\n    const maxFileCount = state.options.maxFiles;\n    if (maxFileCount === null) {\n        return true;\n    }\n\n    // we check if the current count is smaller than the max count, if so, another file can still be added\n    if (count < maxFileCount) {\n        return true;\n    }\n\n    // no more room for another file\n    return false;\n};\n"
  },
  {
    "path": "src/js/app/utils/insertItem.js",
    "content": "import { isEmpty } from '../../utils/isEmpty';\nimport { limit } from '../../utils/limit';\nimport { arrayInsert } from '../../utils/arrayInsert';\n\nexport const insertItem = (items, item, index) => {\n    if (isEmpty(item)) {\n        return null;\n    }\n\n    // if index is undefined, append\n    if (typeof index === 'undefined') {\n        items.push(item);\n        return item;\n    }\n\n    // limit the index to the size of the items array\n    index = limit(index, 0, items.length);\n\n    // add item to array\n    arrayInsert(items, index, item);\n\n    // expose\n    return item;\n};\n"
  },
  {
    "path": "src/js/app/utils/isAPI.js",
    "content": "import { isObject } from '../../utils/isObject';\nimport { isString } from '../../utils/isString';\n\nexport const isAPI = value => {\n    return (\n        isObject(value) &&\n        isString(value.url) &&\n        isObject(value.process) &&\n        isObject(value.revert) &&\n        isObject(value.restore) &&\n        isObject(value.fetch)\n    );\n};\n"
  },
  {
    "path": "src/js/app/utils/mergeOptionObject.js",
    "content": "import { forin } from '../../utils/forin';\nexport const mergeOptionObject = (originalObject, newObject) => {\n    const obj = {};\n    forin(originalObject, key => {\n        obj[key] = newObject[key] || originalObject[key];\n    });\n    return obj;\n};\n"
  },
  {
    "path": "src/js/app/utils/on.js",
    "content": "import { arrayRemove } from '../../utils/arrayRemove';\n\nconst run = (cb, sync) => {\n    if (sync) {\n        cb();\n    }\n    else if (document.hidden) {\n        Promise.resolve(1).then(cb);\n    }\n    else {\n        setTimeout(cb, 0);\n    }\n}\n\nexport const on = () => {\n    const listeners = [];\n    const off = (event, cb) => {\n        arrayRemove(\n            listeners,\n            listeners.findIndex(\n                listener => listener.event === event && (listener.cb === cb || !cb)\n            )\n        );\n    };\n    const fire = (event, args, sync) => {\n        listeners\n            .filter(listener => listener.event === event)\n            .map(listener => listener.cb)\n            .forEach(cb => run(() => cb(...args), sync));\n    }\n    return {\n        fireSync: (event, ...args) => {\n            fire(event, args, true);\n        },\n        fire: (event, ...args) => {\n            fire(event, args, false);\n        },\n        on: (event, cb) => {\n            listeners.push({ event, cb });\n        },\n        onOnce: (event, cb) => {\n            listeners.push({\n                event,\n                cb: (...args) => {\n                    off(event, cb);\n                    cb(...args);\n                }\n            });\n        },\n        off\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/processFileChunked.js",
    "content": "import { sendRequest } from '../../utils/sendRequest';\nimport { createResponse } from '../../utils/createResponse';\nimport { createTimeoutResponse } from '../../utils/createDefaultResponse';\nimport { isObject } from '../../utils/isObject';\nimport { buildURL } from './buildURL';\nimport { ChunkStatus } from '../enum/ChunkStatus';\n\n/*\nfunction signature:\n  (file, metadata, load, error, progress, abort, transfer, options) => {\n    return {\n    abort:() => {}\n  }\n}\n*/\n\n// apiUrl, action, name, file, metadata, load, error, progress, abort, transfer, options\nexport const processFileChunked = (\n    apiUrl,\n    action,\n    name,\n    file,\n    metadata,\n    load,\n    error,\n    progress,\n    abort,\n    transfer,\n    options\n) => {\n    // all chunks\n    const chunks = [];\n    const { chunkTransferId, chunkServer, chunkSize, chunkRetryDelays } = options;\n\n    // default state\n    const state = {\n        serverId: chunkTransferId,\n        aborted: false,\n    };\n\n    // set onload handlers\n    const ondata = action.ondata || (fd => fd);\n    const onload =\n        action.onload ||\n        ((xhr, method) =>\n            method === 'HEAD' ? xhr.getResponseHeader('Upload-Offset') : xhr.response);\n    const onerror = action.onerror || (res => null);\n\n    // create server hook\n    const requestTransferId = cb => {\n        const formData = new FormData();\n\n        // add metadata under same name\n        if (isObject(metadata)) formData.append(name, JSON.stringify(metadata));\n\n        const headers =\n            typeof action.headers === 'function'\n                ? action.headers(file, metadata)\n                : {\n                      ...action.headers,\n                      'Upload-Length': file.size,\n                  };\n\n        const requestParams = {\n            ...action,\n            headers,\n        };\n\n        // send request object\n        const request = sendRequest(ondata(formData), buildURL(apiUrl, action.url), requestParams);\n\n        request.onload = xhr => cb(onload(xhr, requestParams.method));\n\n        request.onerror = xhr =>\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n\n        request.ontimeout = createTimeoutResponse(error);\n    };\n\n    const requestTransferOffset = cb => {\n        const requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n        const headers =\n            typeof action.headers === 'function'\n                ? action.headers(state.serverId)\n                : {\n                      ...action.headers,\n                  };\n\n        const requestParams = {\n            headers,\n            method: 'HEAD',\n        };\n\n        const request = sendRequest(null, requestUrl, requestParams);\n\n        request.onload = xhr => cb(onload(xhr, requestParams.method));\n\n        request.onerror = xhr =>\n            error(\n                createResponse(\n                    'error',\n                    xhr.status,\n                    onerror(xhr.response) || xhr.statusText,\n                    xhr.getAllResponseHeaders()\n                )\n            );\n\n        request.ontimeout = createTimeoutResponse(error);\n    };\n\n    // create chunks\n    const lastChunkIndex = Math.floor(file.size / chunkSize);\n    for (let i = 0; i <= lastChunkIndex; i++) {\n        const offset = i * chunkSize;\n        const data = file.slice(offset, offset + chunkSize, 'application/offset+octet-stream');\n        chunks[i] = {\n            index: i,\n            size: data.size,\n            offset,\n            data,\n            file,\n            progress: 0,\n            retries: [...chunkRetryDelays],\n            status: ChunkStatus.QUEUED,\n            error: null,\n            request: null,\n            timeout: null,\n        };\n    }\n\n    const completeProcessingChunks = () => load(state.serverId);\n\n    const canProcessChunk = chunk =>\n        chunk.status === ChunkStatus.QUEUED || chunk.status === ChunkStatus.ERROR;\n\n    const processChunk = chunk => {\n        // processing is paused, wait here\n        if (state.aborted) return;\n\n        // get next chunk to process\n        chunk = chunk || chunks.find(canProcessChunk);\n\n        // no more chunks to process\n        if (!chunk) {\n            // all done?\n            if (chunks.every(chunk => chunk.status === ChunkStatus.COMPLETE)) {\n                completeProcessingChunks();\n            }\n\n            // no chunk to handle\n            return;\n        }\n\n        // now processing this chunk\n        chunk.status = ChunkStatus.PROCESSING;\n        chunk.progress = null;\n\n        // allow parsing of formdata\n        const ondata = chunkServer.ondata || (fd => fd);\n        const onerror = chunkServer.onerror || (res => null);\n        const onload = chunkServer.onload || (() => {});\n\n        // send request object\n        const requestUrl = buildURL(apiUrl, chunkServer.url, state.serverId);\n\n        const headers =\n            typeof chunkServer.headers === 'function'\n                ? chunkServer.headers(chunk)\n                : {\n                      ...chunkServer.headers,\n                      'Content-Type': 'application/offset+octet-stream',\n                      'Upload-Offset': chunk.offset,\n                      'Upload-Length': file.size,\n                      'Upload-Name': file.name,\n                  };\n\n        const request = (chunk.request = sendRequest(ondata(chunk.data), requestUrl, {\n            ...chunkServer,\n            headers,\n        }));\n\n        request.onload = xhr => {\n            // allow hooking into request result\n            onload(xhr, chunk.index, chunks.length);\n\n            // done!\n            chunk.status = ChunkStatus.COMPLETE;\n\n            // remove request reference\n            chunk.request = null;\n\n            // start processing more chunks\n            processChunks();\n        };\n\n        request.onprogress = (lengthComputable, loaded, total) => {\n            chunk.progress = lengthComputable ? loaded : null;\n            updateTotalProgress();\n        };\n\n        request.onerror = xhr => {\n            chunk.status = ChunkStatus.ERROR;\n            chunk.request = null;\n            chunk.error = onerror(xhr.response) || xhr.statusText;\n            if (!retryProcessChunk(chunk)) {\n                error(\n                    createResponse(\n                        'error',\n                        xhr.status,\n                        onerror(xhr.response) || xhr.statusText,\n                        xhr.getAllResponseHeaders()\n                    )\n                );\n            }\n        };\n\n        request.ontimeout = xhr => {\n            chunk.status = ChunkStatus.ERROR;\n            chunk.request = null;\n            if (!retryProcessChunk(chunk)) {\n                createTimeoutResponse(error)(xhr);\n            }\n        };\n\n        request.onabort = () => {\n            chunk.status = ChunkStatus.QUEUED;\n            chunk.request = null;\n            abort();\n        };\n    };\n\n    const retryProcessChunk = chunk => {\n        // no more retries left\n        if (chunk.retries.length === 0) return false;\n\n        // new retry\n        chunk.status = ChunkStatus.WAITING;\n        clearTimeout(chunk.timeout);\n        chunk.timeout = setTimeout(() => {\n            processChunk(chunk);\n        }, chunk.retries.shift());\n\n        // we're going to retry\n        return true;\n    };\n\n    const updateTotalProgress = () => {\n        // calculate total progress fraction\n        const totalBytesTransfered = chunks.reduce((p, chunk) => {\n            if (p === null || chunk.progress === null) return null;\n            return p + chunk.progress;\n        }, 0);\n\n        // can't compute progress\n        if (totalBytesTransfered === null) return progress(false, 0, 0);\n\n        // calculate progress values\n        const totalSize = chunks.reduce((total, chunk) => total + chunk.size, 0);\n\n        // can update progress indicator\n        progress(true, totalBytesTransfered, totalSize);\n    };\n\n    // process new chunks\n    const processChunks = () => {\n        const totalProcessing = chunks.filter(chunk => chunk.status === ChunkStatus.PROCESSING)\n            .length;\n        if (totalProcessing >= 1) return;\n        processChunk();\n    };\n\n    const abortChunks = () => {\n        chunks.forEach(chunk => {\n            clearTimeout(chunk.timeout);\n            if (chunk.request) {\n                chunk.request.abort();\n            }\n        });\n    };\n\n    // let's go!\n    if (!state.serverId) {\n        requestTransferId(serverId => {\n            // stop here if aborted, might have happened in between request and callback\n            if (state.aborted) return;\n\n            // pass back to item so we can use it if something goes wrong\n            transfer(serverId);\n\n            // store internally\n            state.serverId = serverId;\n            processChunks();\n        });\n    } else {\n        requestTransferOffset(offset => {\n            // stop here if aborted, might have happened in between request and callback\n            if (state.aborted) return;\n\n            // mark chunks with lower offset as complete\n            chunks\n                .filter(chunk => chunk.offset < offset)\n                .forEach(chunk => {\n                    chunk.status = ChunkStatus.COMPLETE;\n                    chunk.progress = chunk.size;\n                });\n\n            // continue processing\n            processChunks();\n        });\n    }\n\n    return {\n        abort: () => {\n            state.aborted = true;\n            abortChunks();\n        },\n    };\n};\n"
  },
  {
    "path": "src/js/app/utils/removeReleasedItems.js",
    "content": "import { arrayRemove } from '../../utils/arrayRemove';\n\nexport const removeReleasedItems = (items) => {\n    items.forEach((item, index) => {\n        if (item.released) {\n            arrayRemove(items, index);\n        }\n    });\n};"
  },
  {
    "path": "src/js/app/utils/requestDataTransferItems.js",
    "content": "import { guesstimateMimeType } from '../../utils/guesstimateMimeType';\nimport { getExtensionFromFilename } from '../../utils/getExtensionFromFilename';\n\nexport const requestDataTransferItems = dataTransfer =>\n    new Promise((resolve, reject) => {\n        // try to get links from transfer, if found we'll exit immediately (unless a file is in the dataTransfer as well, this is because Firefox could represent the file as a URL and a file object at the same time)\n        const links = getLinks(dataTransfer);\n        if (links.length && !hasFiles(dataTransfer)) {\n            return resolve(links);\n        }\n        // try to get files from the transfer\n        getFiles(dataTransfer).then(resolve);\n    });\n\n/**\n * Test if datatransfer has files\n */\nconst hasFiles = (dataTransfer) => {\n    if (dataTransfer.files) return dataTransfer.files.length > 0;\n    return false;\n}\n\n\n/**\n * Extracts files from a DataTransfer object\n */\nconst getFiles = dataTransfer =>\n    new Promise((resolve, reject) => {\n\n        // get the transfer items as promises\n        const promisedFiles = (dataTransfer.items\n            ? Array.from(dataTransfer.items)\n            : []\n        )\n\n            // only keep file system items (files and directories)\n            .filter(item => isFileSystemItem(item))\n\n            // map each item to promise\n            .map(item => getFilesFromItem(item));\n\n        // if is empty, see if we can extract some info from the files property as a fallback\n        if (!promisedFiles.length) {\n            \n            // TODO: test for directories (should not be allowed)\n            // Use FileReader, problem is that the files property gets lost in the process\n            resolve(dataTransfer.files ? Array.from(dataTransfer.files) : []);\n            return;\n        }\n\n        // done!\n        Promise.all(promisedFiles)\n            .then(returnedFileGroups => {\n\n                // flatten groups\n                const files = [];\n                returnedFileGroups.forEach(group => {\n                    files.push.apply(files, group);\n                });\n\n                // done (filter out empty files)!\n                resolve(files.filter(file => file).map(file => {\n                    if (!file._relativePath) file._relativePath = file.webkitRelativePath\n                    return file;\n                }));\n            })\n            .catch(console.error);\n    });\n\nconst isFileSystemItem = item => {\n    if (isEntry(item)) {\n        const entry = getAsEntry(item);\n        if (entry) {\n            return entry.isFile || entry.isDirectory;\n        }\n    }\n    return item.kind === 'file';\n};\n\nconst getFilesFromItem = item =>\n    new Promise((resolve, reject) => {\n\n        if (isDirectoryEntry(item)) {\n            getFilesInDirectory(getAsEntry(item))\n                .then(resolve)\n                .catch(reject)\n            return;\n        }\n\n        resolve([item.getAsFile()]);\n    });\n\nconst getFilesInDirectory = entry =>\n    new Promise((resolve, reject) => {\n\n        const files = [];\n\n        // the total entries to read\n        let dirCounter = 0;\n        let fileCounter = 0;\n\n        const resolveIfDone = () => {\n            if (fileCounter === 0 && dirCounter === 0) {\n                resolve(files);\n            }\n        }\n\n        // the recursive function\n        const readEntries = dirEntry => {\n\n            dirCounter++;\n\n            const directoryReader = dirEntry.createReader();\n\n            // directories are returned in batches, we need to process all batches before we're done\n            const readBatch = () => {\n\n                directoryReader.readEntries(entries => {\n\n                    if (entries.length === 0) {\n                        dirCounter--;\n                        resolveIfDone();\n                        return;\n                    }\n\n                    entries.forEach(entry => {\n    \n                        // recursively read more directories\n                        if (entry.isDirectory) {\n                            readEntries(entry);\n                        }\n                        else {\n\n                            // read as file\n                            fileCounter++;\n\n                            entry.file(file => {\n                                const correctedFile = correctMissingFileType(file);\n                                if (entry.fullPath) correctedFile._relativePath = entry.fullPath;\n                                files.push(correctedFile);\n                                fileCounter--;\n                                resolveIfDone();\n                            });\n\n                        }\n                    });\n\n                    // try to get next batch of files\n                    readBatch();\n\n                }, reject);\n\n            }\n\n            // read first batch of files\n            readBatch();\n        };\n\n        // go!\n        readEntries(entry);\n    });\n\nconst correctMissingFileType = (file) => {\n    if (file.type.length) return file;\n    const date = file.lastModifiedDate;\n    const name = file.name;\n    const type = guesstimateMimeType(getExtensionFromFilename(file.name));\n    if (!type.length) return file;\n    file = file.slice(0, file.size, type);\n    file.name = name;\n    file.lastModifiedDate = date;\n    return file;\n}\n\nconst isDirectoryEntry = item => isEntry(item) && (getAsEntry(item) || {}).isDirectory;\n\nconst isEntry = item => 'webkitGetAsEntry' in item;\n\nconst getAsEntry = item => item.webkitGetAsEntry();\n\n\n/**\n * Extracts links from a DataTransfer object\n */\nconst getLinks = dataTransfer => {\n    let links = [];\n    try {\n        // look in meta data property\n        links = getLinksFromTransferMetaData(dataTransfer);\n        if (links.length) {\n            return links;\n        }\n        links = getLinksFromTransferURLData(dataTransfer);\n    } catch (e) {\n        // nope nope nope (probably IE trouble)\n    }\n    return links;\n};\n\nconst getLinksFromTransferURLData = dataTransfer => {\n    let data = dataTransfer.getData('url');\n    if (typeof data === 'string' && data.length) {\n        return [data];\n    }\n    return [];\n};\n\nconst getLinksFromTransferMetaData = dataTransfer => {\n    let data = dataTransfer.getData('text/html');\n    if (typeof data === 'string' && data.length) {\n        const matches = data.match(/src\\s*=\\s*\"(.+?)\"/);\n        if (matches) {\n            return [matches[1]];\n        }\n    }\n    return [];\n};\n"
  },
  {
    "path": "src/js/app/utils/toServerAPI.js",
    "content": "import { createServerAPI } from './createServerAPI';\nexport const toServerAPI = value => createServerAPI(value);\n"
  },
  {
    "path": "src/js/app/view/assistant.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { attr } from '../../utils/attr';\n\n/**\n * Creates the file view\n */\nconst create = ({ root, props }) => {\n    root.element.id = `filepond--assistant-${props.id}`;\n    attr(root.element, 'role', 'alert');\n    attr(root.element, 'aria-live', 'polite');\n    attr(root.element, 'aria-relevant', 'additions');\n};\n\nlet addFilesNotificationTimeout = null;\nlet notificationClearTimeout = null;\n\nconst filenames = [];\n\nconst assist = (root, message) => {\n    root.element.textContent = message;\n};\n\nconst clear = root => {\n    root.element.textContent = '';\n};\n\nconst listModified = (root, filename, label) => {\n    const total = root.query('GET_TOTAL_ITEMS');\n    assist(\n        root,\n        `${label} ${filename}, ${total} ${\n            total === 1\n                ? root.query('GET_LABEL_FILE_COUNT_SINGULAR')\n                : root.query('GET_LABEL_FILE_COUNT_PLURAL')\n        }`\n    );\n\n    // clear group after set amount of time so the status is not read twice\n    clearTimeout(notificationClearTimeout);\n    notificationClearTimeout = setTimeout(() => {\n        clear(root);\n    }, 1500);\n};\n\nconst isUsingFilePond = root => root.element.parentNode.contains(document.activeElement);\n\nconst itemAdded = ({ root, action }) => {\n    if (!isUsingFilePond(root)) {\n        return;\n    }\n\n    root.element.textContent = '';\n    const item = root.query('GET_ITEM', action.id);\n    filenames.push(item.filename);\n\n    clearTimeout(addFilesNotificationTimeout);\n    addFilesNotificationTimeout = setTimeout(() => {\n        listModified(root, filenames.join(', '), root.query('GET_LABEL_FILE_ADDED'));\n        filenames.length = 0;\n    }, 750);\n};\n\nconst itemRemoved = ({ root, action }) => {\n    if (!isUsingFilePond(root)) {\n        return;\n    }\n\n    const item = action.item;\n    listModified(root, item.filename, root.query('GET_LABEL_FILE_REMOVED'));\n};\n\nconst itemProcessed = ({ root, action }) => {\n    // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n    const label = root.query('GET_LABEL_FILE_PROCESSING_COMPLETE');\n\n    assist(root, `${filename} ${label}`);\n};\n\nconst itemProcessedUndo = ({ root, action }) => {\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n    const label = root.query('GET_LABEL_FILE_PROCESSING_ABORTED');\n\n    assist(root, `${filename} ${label}`);\n};\n\nconst itemError = ({ root, action }) => {\n    const item = root.query('GET_ITEM', action.id);\n    const filename = item.filename;\n\n    // will also notify the user when FilePond is not being used, as the user might be occupied with other activities while uploading a file\n\n    assist(root, `${action.status.main} ${filename} ${action.status.sub}`);\n};\n\nexport const assistant = createView({\n    create,\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: itemAdded,\n        DID_REMOVE_ITEM: itemRemoved,\n        DID_COMPLETE_ITEM_PROCESSING: itemProcessed,\n\n        DID_ABORT_ITEM_PROCESSING: itemProcessedUndo,\n        DID_REVERT_ITEM_PROCESSING: itemProcessedUndo,\n\n        DID_THROW_ITEM_REMOVE_ERROR: itemError,\n        DID_THROW_ITEM_LOAD_ERROR: itemError,\n        DID_THROW_ITEM_INVALID: itemError,\n        DID_THROW_ITEM_PROCESSING_ERROR: itemError,\n    }),\n    tag: 'span',\n    name: 'assistant',\n});\n"
  },
  {
    "path": "src/js/app/view/blob.js",
    "content": "import { createView } from '../frame/index';\n\nexport const blob = createView({\n    name: 'drip-blob',\n    ignoreRect: true,\n    mixins: {\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            translateX: 'spring',\n            translateY: 'spring',\n            opacity: { type: 'tween', duration: 250 }\n        }\n    }\n});\n"
  },
  {
    "path": "src/js/app/view/browser.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { attrToggle } from '../../utils/attrToggle';\nimport { resetFileInput } from '../../utils/resetFileInput';\nimport { attr } from '../../utils/attr';\nimport { ItemStatus } from '../enum/ItemStatus';\n\nconst create = ({ root, props }) => {\n    // set id so can be referenced from outside labels\n    root.element.id = `filepond--browser-${props.id}`;\n\n    // set name of element (is removed when a value is set)\n    attr(root.element, 'name', root.query('GET_NAME'));\n\n    // we have to link this element to the status element\n    attr(root.element, 'aria-controls', `filepond--assistant-${props.id}`);\n\n    // set label, we use labelled by as otherwise the screenreader does not read the \"browse\" text in the label (as it has tabindex: 0)\n    attr(root.element, 'aria-labelledby', `filepond--drop-label-${props.id}`);\n\n    // set configurable props\n    setAcceptedFileTypes({ root, action: { value: root.query('GET_ACCEPTED_FILE_TYPES') } });\n    toggleAllowMultiple({ root, action: { value: root.query('GET_ALLOW_MULTIPLE') } });\n    toggleDirectoryFilter({ root, action: { value: root.query('GET_ALLOW_DIRECTORIES_ONLY') } });\n    toggleDisabled({ root });\n    toggleRequired({ root, action: { value: root.query('GET_REQUIRED') } });\n    setCaptureMethod({ root, action: { value: root.query('GET_CAPTURE_METHOD') } });\n\n    // handle changes to the input field\n    root.ref.handleChange = e => {\n        if (!root.element.value) {\n            return;\n        }\n\n        // extract files and move value of webkitRelativePath path to _relativePath\n        const files = Array.from(root.element.files).map(file => {\n            file._relativePath = file.webkitRelativePath;\n            return file;\n        });\n\n        // we add a little delay so the OS file select window can move out of the way before we add our file\n        setTimeout(() => {\n            // load files\n            props.onload(files);\n\n            // reset input, it's just for exposing a method to drop files, should not retain any state\n            resetFileInput(root.element);\n        }, 250);\n    };\n\n    root.element.addEventListener('change', root.ref.handleChange);\n};\n\nconst setAcceptedFileTypes = ({ root, action }) => {\n    if (!root.query('GET_ALLOW_SYNC_ACCEPT_ATTRIBUTE')) return;\n    attrToggle(root.element, 'accept', !!action.value, action.value ? action.value.join(',') : '');\n};\n\nconst toggleAllowMultiple = ({ root, action }) => {\n    attrToggle(root.element, 'multiple', action.value);\n};\n\nconst toggleDirectoryFilter = ({ root, action }) => {\n    attrToggle(root.element, 'webkitdirectory', action.value);\n};\n\nconst toggleDisabled = ({ root }) => {\n    const isDisabled = root.query('GET_DISABLED');\n    const doesAllowBrowse = root.query('GET_ALLOW_BROWSE');\n    const disableField = isDisabled || !doesAllowBrowse;\n    attrToggle(root.element, 'disabled', disableField);\n};\n\nconst toggleRequired = ({ root, action }) => {\n    // want to remove required, always possible\n    if (!action.value) {\n        attrToggle(root.element, 'required', false);\n    }\n    // if want to make required, only possible when zero items\n    else if (root.query('GET_TOTAL_ITEMS') === 0) {\n        attrToggle(root.element, 'required', true);\n    }\n};\n\nconst setCaptureMethod = ({ root, action }) => {\n    attrToggle(root.element, 'capture', !!action.value, action.value === true ? '' : action.value);\n};\n\nconst updateRequiredStatus = ({ root }) => {\n    const { element } = root;\n    // always remove the required attribute when more than zero items\n    if (root.query('GET_TOTAL_ITEMS') > 0) {\n        attrToggle(element, 'required', false);\n        attrToggle(element, 'name', false);\n\n        // still has items\n        const activeItems = root.query('GET_ACTIVE_ITEMS');\n        let hasInvalidField = false;\n        for (let i = 0; i < activeItems.length; i++) {\n            if (activeItems[i].status === ItemStatus.LOAD_ERROR) {\n                hasInvalidField = true;\n            }\n        }\n        // set validity status\n        root.element.setCustomValidity(\n            hasInvalidField ? root.query('GET_LABEL_INVALID_FIELD') : ''\n        );\n    } else {\n        // add name attribute\n        attrToggle(element, 'name', true, root.query('GET_NAME'));\n\n        // remove any validation messages\n        const shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n        if (shouldCheckValidity) {\n            element.setCustomValidity('');\n        }\n\n        // we only add required if the field has been deemed required\n        if (root.query('GET_REQUIRED')) {\n            attrToggle(element, 'required', true);\n        }\n    }\n};\n\nconst updateFieldValidityStatus = ({ root }) => {\n    const shouldCheckValidity = root.query('GET_CHECK_VALIDITY');\n    if (!shouldCheckValidity) return;\n    root.element.setCustomValidity(root.query('GET_LABEL_INVALID_FIELD'));\n};\n\nexport const browser = createView({\n    tag: 'input',\n    name: 'browser',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    attributes: {\n        type: 'file',\n    },\n    create,\n    destroy: ({ root }) => {\n        root.element.removeEventListener('change', root.ref.handleChange);\n    },\n    write: createRoute({\n        DID_LOAD_ITEM: updateRequiredStatus,\n        DID_REMOVE_ITEM: updateRequiredStatus,\n        DID_THROW_ITEM_INVALID: updateFieldValidityStatus,\n\n        DID_SET_DISABLED: toggleDisabled,\n        DID_SET_ALLOW_BROWSE: toggleDisabled,\n        DID_SET_ALLOW_DIRECTORIES_ONLY: toggleDirectoryFilter,\n        DID_SET_ALLOW_MULTIPLE: toggleAllowMultiple,\n        DID_SET_ACCEPTED_FILE_TYPES: setAcceptedFileTypes,\n        DID_SET_CAPTURE_METHOD: setCaptureMethod,\n        DID_SET_REQUIRED: toggleRequired,\n    }),\n});\n"
  },
  {
    "path": "src/js/app/view/data.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { createElement } from '../../utils/createElement';\nimport { setInputFiles } from '../../utils/setInputFiles';\nimport { FileOrigin } from '../enum/FileOrigin';\n\nconst create = ({ root }) => {\n    root.ref.fields = {};\n    const legend = document.createElement('legend');\n    legend.textContent = 'Files';\n    root.element.appendChild(legend);\n};\n\nconst getField = (root, id) => root.ref.fields[id];\n\nconst syncFieldPositionsWithItems = root => {\n    root.query('GET_ACTIVE_ITEMS').forEach(item => {\n        if (!root.ref.fields[item.id]) return;\n        root.element.appendChild(root.ref.fields[item.id]);\n    });\n};\n\nconst didReorderItems = ({ root }) => syncFieldPositionsWithItems(root);\n\nconst didAddItem = ({ root, action }) => {\n    const fileItem = root.query('GET_ITEM', action.id);\n    const isLocalFile = fileItem.origin === FileOrigin.LOCAL;\n    const shouldUseFileInput = !isLocalFile && root.query('SHOULD_UPDATE_FILE_INPUT');\n    const dataContainer = createElement('input');\n    dataContainer.type = shouldUseFileInput ? 'file' : 'hidden';\n    dataContainer.name = root.query('GET_NAME');\n    root.ref.fields[action.id] = dataContainer;\n    syncFieldPositionsWithItems(root);\n};\n\nconst didLoadItem = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n\n    // store server ref in hidden input\n    if (action.serverFileReference !== null) field.value = action.serverFileReference;\n\n    // store file item in file input\n    if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n\n    const fileItem = root.query('GET_ITEM', action.id);\n    setInputFiles(field, [fileItem.file]);\n};\n\nconst didPrepareOutput = ({ root, action }) => {\n    // this timeout pushes the handler after 'load'\n    if (!root.query('SHOULD_UPDATE_FILE_INPUT')) return;\n    setTimeout(() => {\n        const field = getField(root, action.id);\n        if (!field) return;\n        setInputFiles(field, [action.file]);\n    }, 0);\n};\n\nconst didSetDisabled = ({ root }) => {\n    root.element.disabled = root.query('GET_DISABLED');\n};\n\nconst didRemoveItem = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n    if (field.parentNode) field.parentNode.removeChild(field);\n    delete root.ref.fields[action.id];\n};\n\n// only runs for server files. will refuse to update the value if the field\n// is a file field\nconst didDefineValue = ({ root, action }) => {\n    const field = getField(root, action.id);\n    if (!field) return;\n    if (action.value === null) {\n        // clear field value\n        field.removeAttribute('value');\n    } else {\n        // set field value\n        if (field.type != 'file') {\n            field.value = action.value;\n        }\n    }\n    syncFieldPositionsWithItems(root);\n};\n\nconst write = createRoute({\n    DID_SET_DISABLED: didSetDisabled,\n    DID_ADD_ITEM: didAddItem,\n    DID_LOAD_ITEM: didLoadItem,\n    DID_REMOVE_ITEM: didRemoveItem,\n    DID_DEFINE_VALUE: didDefineValue,\n    DID_PREPARE_OUTPUT: didPrepareOutput,\n    DID_REORDER_ITEMS: didReorderItems,\n    DID_SORT_ITEMS: didReorderItems,\n});\n\nexport const data = createView({ tag: 'fieldset', name: 'data', create, write, ignoreRect: true });\n"
  },
  {
    "path": "src/js/app/view/drip.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { blob } from './blob';\n\nconst addBlob = ({ root }) => {\n    const centerX = root.rect.element.width * 0.5;\n    const centerY = root.rect.element.height * 0.5;\n\n    root.ref.blob = root.appendChildView(\n        root.createChildView(blob, {\n            opacity: 0,\n            scaleX: 2.5,\n            scaleY: 2.5,\n            translateX: centerX,\n            translateY: centerY\n        })\n    );\n};\n\nconst moveBlob = ({ root, action }) => {\n    if (!root.ref.blob) {\n        addBlob({ root });\n        return;\n    }\n\n    root.ref.blob.translateX = action.position.scopeLeft;\n    root.ref.blob.translateY = action.position.scopeTop;\n    root.ref.blob.scaleX = 1;\n    root.ref.blob.scaleY = 1;\n    root.ref.blob.opacity = 1;\n};\n\nconst hideBlob = ({ root }) => {\n    if (!root.ref.blob) {\n        return;\n    }\n    root.ref.blob.opacity = 0;\n};\n\nconst explodeBlob = ({ root }) => {\n    if (!root.ref.blob) {\n        return;\n    }\n    root.ref.blob.scaleX = 2.5;\n    root.ref.blob.scaleY = 2.5;\n    root.ref.blob.opacity = 0;\n};\n\nconst write = ({ root, props, actions }) => {\n    route({ root, props, actions });\n\n    const { blob } = root.ref;\n\n    if (actions.length === 0 && blob && blob.opacity === 0) {\n        root.removeChildView(blob);\n        root.ref.blob = null;\n    }\n};\n\nconst route = createRoute({\n    DID_DRAG: moveBlob,\n    DID_DROP: explodeBlob,\n    DID_END_DRAG: hideBlob\n});\n\nexport const drip = createView({\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    name: 'drip',\n    write\n});\n"
  },
  {
    "path": "src/js/app/view/dropLabel.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { attr } from '../../utils/attr';\nimport { createElement } from '../../utils/createElement';\nimport { Key } from '../enum/Key';\n\nconst create = ({ root, props }) => {\n    // create the label and link it to the file browser\n    const label = createElement('label');\n    attr(label, 'for', `filepond--browser-${props.id}`);\n\n    // use for labeling file input (aria-labelledby on file input)\n    attr(label, 'id', `filepond--drop-label-${props.id}`);\n\n    // handle keys\n    root.ref.handleKeyDown = e => {\n        const isActivationKey = e.keyCode === Key.ENTER || e.keyCode === Key.SPACE;\n        if (!isActivationKey) return;\n        // stops from triggering the element a second time\n        e.preventDefault();\n\n        // click link (will then in turn activate file input)\n        root.ref.label.click();\n    };\n\n    root.ref.handleClick = e => {\n        const isLabelClick = e.target === label || label.contains(e.target);\n\n        // don't want to click twice\n        if (isLabelClick) return;\n\n        // click link (will then in turn activate file input)\n        root.ref.label.click();\n    };\n\n    // attach events\n    label.addEventListener('keydown', root.ref.handleKeyDown);\n    root.element.addEventListener('click', root.ref.handleClick);\n\n    // update\n    updateLabelValue(label, props.caption);\n\n    // add!\n    root.appendChild(label);\n    root.ref.label = label;\n};\n\nconst updateLabelValue = (label, value) => {\n    label.innerHTML = value;\n    const clickable = label.querySelector('.filepond--label-action');\n    if (clickable) {\n        attr(clickable, 'tabindex', '0');\n    }\n    return value;\n};\n\nexport const dropLabel = createView({\n    name: 'drop-label',\n    ignoreRect: true,\n    create,\n    destroy: ({ root }) => {\n        root.ref.label.addEventListener('keydown', root.ref.handleKeyDown);\n        root.element.removeEventListener('click', root.ref.handleClick);\n    },\n    write: createRoute({\n        DID_SET_LABEL_IDLE: ({ root, action }) => {\n            updateLabelValue(root.ref.label, action.value);\n        },\n    }),\n    mixins: {\n        styles: ['opacity', 'translateX', 'translateY'],\n        animations: {\n            opacity: { type: 'tween', duration: 150 },\n            translateX: 'spring',\n            translateY: 'spring',\n        },\n    },\n});\n"
  },
  {
    "path": "src/js/app/view/file.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { progressIndicator } from './progressIndicator';\nimport { fileActionButton } from './fileActionButton';\nimport { fileInfo } from './fileInfo';\nimport { fileStatus } from './fileStatus';\nimport { forin } from '../../utils/forin';\nimport { applyFilters } from '../../filter';\n\n/**\n * Button definitions for the file view\n */\n\nconst Buttons = {\n    AbortItemLoad: {\n        label: 'GET_LABEL_BUTTON_ABORT_ITEM_LOAD',\n        action: 'ABORT_ITEM_LOAD',\n        className: 'filepond--action-abort-item-load',\n        align: 'LOAD_INDICATOR_POSITION', // right\n    },\n    RetryItemLoad: {\n        label: 'GET_LABEL_BUTTON_RETRY_ITEM_LOAD',\n        action: 'RETRY_ITEM_LOAD',\n        icon: 'GET_ICON_RETRY',\n        className: 'filepond--action-retry-item-load',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RemoveItem: {\n        label: 'GET_LABEL_BUTTON_REMOVE_ITEM',\n        action: 'REQUEST_REMOVE_ITEM',\n        icon: 'GET_ICON_REMOVE',\n        className: 'filepond--action-remove-item',\n        align: 'BUTTON_REMOVE_ITEM_POSITION', // left\n    },\n    ProcessItem: {\n        label: 'GET_LABEL_BUTTON_PROCESS_ITEM',\n        action: 'REQUEST_ITEM_PROCESSING',\n        icon: 'GET_ICON_PROCESS',\n        className: 'filepond--action-process-item',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    AbortItemProcessing: {\n        label: 'GET_LABEL_BUTTON_ABORT_ITEM_PROCESSING',\n        action: 'ABORT_ITEM_PROCESSING',\n        className: 'filepond--action-abort-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RetryItemProcessing: {\n        label: 'GET_LABEL_BUTTON_RETRY_ITEM_PROCESSING',\n        action: 'RETRY_ITEM_PROCESSING',\n        icon: 'GET_ICON_RETRY',\n        className: 'filepond--action-retry-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n    RevertItemProcessing: {\n        label: 'GET_LABEL_BUTTON_UNDO_ITEM_PROCESSING',\n        action: 'REQUEST_REVERT_ITEM_PROCESSING',\n        icon: 'GET_ICON_UNDO',\n        className: 'filepond--action-revert-item-processing',\n        align: 'BUTTON_PROCESS_ITEM_POSITION', // right\n    },\n};\n\n// make a list of buttons, we can then remove buttons from this list if they're disabled\nconst ButtonKeys = [];\nforin(Buttons, key => {\n    ButtonKeys.push(key);\n});\n\nconst calculateFileInfoOffset = root => {\n    if (getRemoveIndicatorAligment(root) === 'right') return 0;\n    const buttonRect = root.ref.buttonRemoveItem.rect.element;\n    return buttonRect.hidden ? null : buttonRect.width + buttonRect.left;\n};\n\nconst calculateButtonWidth = root => {\n    const buttonRect = root.ref.buttonAbortItemLoad.rect.element;\n    return buttonRect.width;\n};\n\n// Force on full pixels so text stays crips\nconst calculateFileVerticalCenterOffset = root =>\n    Math.floor(root.ref.buttonRemoveItem.rect.element.height / 4);\nconst calculateFileHorizontalCenterOffset = root =>\n    Math.floor(root.ref.buttonRemoveItem.rect.element.left / 2);\n\nconst getLoadIndicatorAlignment = root => root.query('GET_STYLE_LOAD_INDICATOR_POSITION');\nconst getProcessIndicatorAlignment = root => root.query('GET_STYLE_PROGRESS_INDICATOR_POSITION');\nconst getRemoveIndicatorAligment = root => root.query('GET_STYLE_BUTTON_REMOVE_ITEM_POSITION');\n\nconst DefaultStyle = {\n    buttonAbortItemLoad: { opacity: 0 },\n    buttonRetryItemLoad: { opacity: 0 },\n    buttonRemoveItem: { opacity: 0 },\n    buttonProcessItem: { opacity: 0 },\n    buttonAbortItemProcessing: { opacity: 0 },\n    buttonRetryItemProcessing: { opacity: 0 },\n    buttonRevertItemProcessing: { opacity: 0 },\n    loadProgressIndicator: { opacity: 0, align: getLoadIndicatorAlignment },\n    processProgressIndicator: { opacity: 0, align: getProcessIndicatorAlignment },\n    processingCompleteIndicator: { opacity: 0, scaleX: 0.75, scaleY: 0.75 },\n    info: { translateX: 0, translateY: 0, opacity: 0 },\n    status: { translateX: 0, translateY: 0, opacity: 0 },\n};\n\nconst IdleStyle = {\n    buttonRemoveItem: { opacity: 1 },\n    buttonProcessItem: { opacity: 1 },\n    info: { translateX: calculateFileInfoOffset },\n    status: { translateX: calculateFileInfoOffset },\n};\n\nconst ProcessingStyle = {\n    buttonAbortItemProcessing: { opacity: 1 },\n    processProgressIndicator: { opacity: 1 },\n    status: { opacity: 1 },\n};\n\nconst StyleMap = {\n    DID_THROW_ITEM_INVALID: {\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { translateX: calculateFileInfoOffset, opacity: 1 },\n    },\n    DID_START_ITEM_LOAD: {\n        buttonAbortItemLoad: { opacity: 1 },\n        loadProgressIndicator: { opacity: 1 },\n        status: { opacity: 1 },\n    },\n    DID_THROW_ITEM_LOAD_ERROR: {\n        buttonRetryItemLoad: { opacity: 1 },\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1 },\n    },\n    DID_START_ITEM_REMOVE: {\n        processProgressIndicator: { opacity: 1, align: getRemoveIndicatorAligment },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 0 },\n    },\n    DID_THROW_ITEM_REMOVE_ERROR: {\n        processProgressIndicator: { opacity: 0, align: getRemoveIndicatorAligment },\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1, translateX: calculateFileInfoOffset },\n    },\n    DID_LOAD_ITEM: IdleStyle,\n    DID_LOAD_LOCAL_ITEM: {\n        buttonRemoveItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { translateX: calculateFileInfoOffset },\n    },\n    DID_START_ITEM_PROCESSING: ProcessingStyle,\n    DID_REQUEST_ITEM_PROCESSING: ProcessingStyle,\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: ProcessingStyle,\n    DID_COMPLETE_ITEM_PROCESSING: {\n        buttonRevertItemProcessing: { opacity: 1 },\n        info: { opacity: 1 },\n        status: { opacity: 1 },\n    },\n    DID_THROW_ITEM_PROCESSING_ERROR: {\n        buttonRemoveItem: { opacity: 1 },\n        buttonRetryItemProcessing: { opacity: 1 },\n        status: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n    },\n    DID_THROW_ITEM_PROCESSING_REVERT_ERROR: {\n        buttonRevertItemProcessing: { opacity: 1 },\n        status: { opacity: 1 },\n        info: { opacity: 1 },\n    },\n    DID_ABORT_ITEM_PROCESSING: {\n        buttonRemoveItem: { opacity: 1 },\n        buttonProcessItem: { opacity: 1 },\n        info: { translateX: calculateFileInfoOffset },\n        status: { opacity: 1 },\n    },\n    DID_REVERT_ITEM_PROCESSING: IdleStyle,\n};\n\n// complete indicator view\nconst processingCompleteIndicatorView = createView({\n    create: ({ root }) => {\n        root.element.innerHTML = root.query('GET_ICON_DONE');\n    },\n    name: 'processing-complete-indicator',\n    ignoreRect: true,\n    mixins: {\n        styles: ['scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            opacity: { type: 'tween', duration: 250 },\n        },\n    },\n});\n\n/**\n * Creates the file view\n */\nconst create = ({ root, props }) => {\n    // copy Buttons object\n    const LocalButtons = Object.keys(Buttons).reduce((prev, curr) => {\n        prev[curr] = { ...Buttons[curr] };\n        return prev;\n    }, {});\n\n    const { id } = props;\n\n    // allow reverting upload\n    const allowRevert = root.query('GET_ALLOW_REVERT');\n\n    // allow remove file\n    const allowRemove = root.query('GET_ALLOW_REMOVE');\n\n    // allow processing upload\n    const allowProcess = root.query('GET_ALLOW_PROCESS');\n\n    // is instant uploading, need this to determine the icon of the undo button\n    const instantUpload = root.query('GET_INSTANT_UPLOAD');\n\n    // is async set up\n    const isAsync = root.query('IS_ASYNC');\n\n    // should align remove item buttons\n    const alignRemoveItemButton = root.query('GET_STYLE_BUTTON_REMOVE_ITEM_ALIGN');\n\n    // enabled buttons array\n    let buttonFilter;\n    if (isAsync) {\n        if (allowProcess && !allowRevert) {\n            // only remove revert button\n            buttonFilter = key => !/RevertItemProcessing/.test(key);\n        } else if (!allowProcess && allowRevert) {\n            // only remove process button\n            buttonFilter = key => !/ProcessItem|RetryItemProcessing|AbortItemProcessing/.test(key);\n        } else if (!allowProcess && !allowRevert) {\n            // remove all process buttons\n            buttonFilter = key => !/Process/.test(key);\n        }\n    } else {\n        // no process controls available\n        buttonFilter = key => !/Process/.test(key);\n    }\n\n    const enabledButtons = buttonFilter ? ButtonKeys.filter(buttonFilter) : ButtonKeys.concat();\n\n    // update icon and label for revert button when instant uploading\n    if (instantUpload && allowRevert) {\n        LocalButtons['RevertItemProcessing'].label = 'GET_LABEL_BUTTON_REMOVE_ITEM';\n        LocalButtons['RevertItemProcessing'].icon = 'GET_ICON_REMOVE';\n    }\n\n    // remove last button (revert) if not allowed\n    if (isAsync && !allowRevert) {\n        const map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n        map.info.translateX = calculateFileHorizontalCenterOffset;\n        map.info.translateY = calculateFileVerticalCenterOffset;\n        map.status.translateY = calculateFileVerticalCenterOffset;\n        map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n    }\n\n    // should align center\n    if (isAsync && !allowProcess) {\n        [\n            'DID_START_ITEM_PROCESSING',\n            'DID_REQUEST_ITEM_PROCESSING',\n            'DID_UPDATE_ITEM_PROCESS_PROGRESS',\n            'DID_THROW_ITEM_PROCESSING_ERROR',\n        ].forEach(key => {\n            StyleMap[key].status.translateY = calculateFileVerticalCenterOffset;\n        });\n        StyleMap['DID_THROW_ITEM_PROCESSING_ERROR'].status.translateX = calculateButtonWidth;\n    }\n\n    // move remove button to right\n    if (alignRemoveItemButton && allowRevert) {\n        LocalButtons['RevertItemProcessing'].align = 'BUTTON_REMOVE_ITEM_POSITION';\n        const map = StyleMap['DID_COMPLETE_ITEM_PROCESSING'];\n        map.info.translateX = calculateFileInfoOffset;\n        map.status.translateY = calculateFileVerticalCenterOffset;\n        map.processingCompleteIndicator = { opacity: 1, scaleX: 1, scaleY: 1 };\n    }\n\n    // show/hide RemoveItem button\n    if (!allowRemove) {\n        LocalButtons['RemoveItem'].disabled = true;\n    }\n\n    // create the button views\n    forin(LocalButtons, (key, definition) => {\n        // create button\n        const buttonView = root.createChildView(fileActionButton, {\n            label: root.query(definition.label),\n            icon: root.query(definition.icon),\n            opacity: 0,\n        });\n\n        // should be appended?\n        if (enabledButtons.includes(key)) {\n            root.appendChildView(buttonView);\n        }\n\n        // toggle\n        if (definition.disabled) {\n            buttonView.element.setAttribute('disabled', 'disabled');\n            buttonView.element.setAttribute('hidden', 'hidden');\n        }\n\n        // add position attribute\n        buttonView.element.dataset.align = root.query(`GET_STYLE_${definition.align}`);\n\n        // add class\n        buttonView.element.classList.add(definition.className);\n\n        // handle interactions\n        buttonView.on('click', e => {\n            e.stopPropagation();\n            if (definition.disabled) return;\n            root.dispatch(definition.action, { query: id });\n        });\n\n        // set reference\n        root.ref[`button${key}`] = buttonView;\n    });\n\n    // checkmark\n    root.ref.processingCompleteIndicator = root.appendChildView(\n        root.createChildView(processingCompleteIndicatorView)\n    );\n    root.ref.processingCompleteIndicator.element.dataset.align = root.query(\n        `GET_STYLE_BUTTON_PROCESS_ITEM_POSITION`\n    );\n\n    // create file info view\n    root.ref.info = root.appendChildView(root.createChildView(fileInfo, { id }));\n\n    // create file status view\n    root.ref.status = root.appendChildView(root.createChildView(fileStatus, { id }));\n\n    // add progress indicators\n    const loadIndicatorView = root.appendChildView(\n        root.createChildView(progressIndicator, {\n            opacity: 0,\n            align: root.query(`GET_STYLE_LOAD_INDICATOR_POSITION`),\n        })\n    );\n    loadIndicatorView.element.classList.add('filepond--load-indicator');\n    root.ref.loadProgressIndicator = loadIndicatorView;\n\n    const progressIndicatorView = root.appendChildView(\n        root.createChildView(progressIndicator, {\n            opacity: 0,\n            align: root.query(`GET_STYLE_PROGRESS_INDICATOR_POSITION`),\n        })\n    );\n    progressIndicatorView.element.classList.add('filepond--process-indicator');\n    root.ref.processProgressIndicator = progressIndicatorView;\n\n    // current active styles\n    root.ref.activeStyles = [];\n};\n\nconst write = ({ root, actions, props }) => {\n    // route actions\n    route({ root, actions, props });\n\n    // select last state change action\n    let action = actions\n        .concat()\n        .filter(action => /^DID_/.test(action.type))\n        .reverse()\n        .find(action => StyleMap[action.type]);\n\n    // a new action happened, let's get the matching styles\n    if (action) {\n        // define new active styles\n        root.ref.activeStyles = [];\n\n        const stylesToApply = StyleMap[action.type];\n        forin(DefaultStyle, (name, defaultStyles) => {\n            // get reference to control\n            const control = root.ref[name];\n\n            // loop over all styles for this control\n            forin(defaultStyles, (key, defaultValue) => {\n                const value =\n                    stylesToApply[name] && typeof stylesToApply[name][key] !== 'undefined'\n                        ? stylesToApply[name][key]\n                        : defaultValue;\n                root.ref.activeStyles.push({ control, key, value });\n            });\n        });\n    }\n\n    // apply active styles to element\n    root.ref.activeStyles.forEach(({ control, key, value }) => {\n        control[key] = typeof value === 'function' ? value(root) : value;\n    });\n};\n\nconst route = createRoute({\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_PROCESSING: ({ root, action }) => {\n        root.ref.buttonAbortItemProcessing.label = action.value;\n    },\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_LOAD: ({ root, action }) => {\n        root.ref.buttonAbortItemLoad.label = action.value;\n    },\n    DID_SET_LABEL_BUTTON_ABORT_ITEM_REMOVAL: ({ root, action }) => {\n        root.ref.buttonAbortItemRemoval.label = action.value;\n    },\n    DID_REQUEST_ITEM_PROCESSING: ({ root }) => {\n        root.ref.processProgressIndicator.spin = true;\n        root.ref.processProgressIndicator.progress = 0;\n    },\n    DID_START_ITEM_LOAD: ({ root }) => {\n        root.ref.loadProgressIndicator.spin = true;\n        root.ref.loadProgressIndicator.progress = 0;\n    },\n    DID_START_ITEM_REMOVE: ({ root }) => {\n        root.ref.processProgressIndicator.spin = true;\n        root.ref.processProgressIndicator.progress = 0;\n    },\n    DID_UPDATE_ITEM_LOAD_PROGRESS: ({ root, action }) => {\n        root.ref.loadProgressIndicator.spin = false;\n        root.ref.loadProgressIndicator.progress = action.progress;\n    },\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: ({ root, action }) => {\n        root.ref.processProgressIndicator.spin = false;\n        root.ref.processProgressIndicator.progress = action.progress;\n    },\n});\n\nexport const file = createView({\n    create,\n    write,\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    name: 'file',\n});\n"
  },
  {
    "path": "src/js/app/view/fileActionButton.js",
    "content": "import { createView } from '../frame/index';\nimport { attr } from '../../utils/attr';\n\nconst create = ({ root, props }) => {\n    root.element.innerHTML = (props.icon || '') + `<span>${props.label}</span>`;\n\n    props.isDisabled = false;\n};\n\nconst write = ({ root, props }) => {\n\n    const { isDisabled } = props;\n    const shouldDisable = root.query('GET_DISABLED') || props.opacity === 0;\n\n    if (shouldDisable && !isDisabled) {\n        props.isDisabled = true;\n        attr(root.element, 'disabled', 'disabled');\n    }\n    else if (!shouldDisable && isDisabled) {\n        props.isDisabled = false;\n        root.element.removeAttribute('disabled');\n    }\n};\n\nexport const fileActionButton = createView({\n    tag: 'button',\n    attributes: {\n        type: 'button'\n    },\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    name: 'file-action-button',\n    mixins: {\n        apis: ['label'],\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'],\n        animations: {\n            scaleX: 'spring',\n            scaleY: 'spring',\n            translateX: 'spring',\n            translateY: 'spring',\n            opacity: { type: 'tween', duration: 250 }\n        },\n        listeners: true\n    },\n    create,\n    write\n});\n"
  },
  {
    "path": "src/js/app/view/fileInfo.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { toNaturalFileSize } from '../../utils/toNaturalFileSize';\nimport { text } from '../../utils/text';\nimport { formatFilename } from '../../utils/formatFilename';\nimport { isInt } from '../../utils/isInt';\nimport { createElement } from '../../utils/createElement';\nimport { attr } from '../../utils/attr';\nimport { applyFilters } from '../../filter';\n\nconst create = ({ root, props }) => {\n    // filename\n    const fileName = createElement('span');\n    fileName.className = 'filepond--file-info-main';\n    // hide for screenreaders\n    // the file is contained in a fieldset with legend that contains the filename\n    // no need to read it twice\n    attr(fileName, 'aria-hidden', 'true');\n    root.appendChild(fileName);\n    root.ref.fileName = fileName;\n\n    // filesize\n    const fileSize = createElement('span');\n    fileSize.className = 'filepond--file-info-sub';\n    root.appendChild(fileSize);\n    root.ref.fileSize = fileSize;\n\n    // set initial values\n    text(fileSize, root.query('GET_LABEL_FILE_WAITING_FOR_SIZE'));\n    text(fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n};\n\nconst updateFile = ({ root, props }) => {\n    text(\n        root.ref.fileSize,\n        toNaturalFileSize(\n            root.query('GET_ITEM_SIZE', props.id),\n            '.',\n            root.query('GET_FILE_SIZE_BASE'),\n            root.query('GET_FILE_SIZE_LABELS', root.query)\n        )\n    );\n    text(root.ref.fileName, formatFilename(root.query('GET_ITEM_NAME', props.id)));\n};\n\nconst updateFileSizeOnError = ({ root, props }) => {\n    // if size is available don't fallback to unknown size message\n    if (isInt(root.query('GET_ITEM_SIZE', props.id))) {\n        updateFile({ root, props });\n        return;\n    }\n\n    text(root.ref.fileSize, root.query('GET_LABEL_FILE_SIZE_NOT_AVAILABLE'));\n};\n\nexport const fileInfo = createView({\n    name: 'file-info',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: updateFile,\n        DID_UPDATE_ITEM_META: updateFile,\n        DID_THROW_ITEM_LOAD_ERROR: updateFileSizeOnError,\n        DID_THROW_ITEM_INVALID: updateFileSizeOnError,\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    create,\n    mixins: {\n        styles: ['translateX', 'translateY'],\n        animations: {\n            translateX: 'spring',\n            translateY: 'spring',\n        },\n    },\n});\n"
  },
  {
    "path": "src/js/app/view/fileStatus.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { toPercentage } from '../../utils/toPercentage';\nimport { text } from '../../utils/text';\nimport { createElement } from '../../utils/createElement';\nimport { applyFilters } from '../../filter';\n\nconst create = ({ root }) => {\n\n    // main status\n    const main = createElement('span');\n    main.className = 'filepond--file-status-main';\n    root.appendChild(main);\n    root.ref.main = main;\n\n    // sub status\n    const sub = createElement('span');\n    sub.className = 'filepond--file-status-sub';\n    root.appendChild(sub);\n    root.ref.sub = sub;\n\n    didSetItemLoadProgress({ root, action: { progress: null } });\n};\n\nconst didSetItemLoadProgress = ({ root, action }) => {\n    const title =\n        action.progress === null\n            ? root.query('GET_LABEL_FILE_LOADING')\n            : `${root.query('GET_LABEL_FILE_LOADING')} ${toPercentage(\n                  action.progress\n              )}%`;\n    text(root.ref.main, title);\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didSetItemProcessProgress = ({ root, action }) => {\n    const title =\n        action.progress === null\n            ? root.query('GET_LABEL_FILE_PROCESSING')\n            : `${root.query('GET_LABEL_FILE_PROCESSING')} ${toPercentage(\n                  action.progress\n              )}%`;\n    text(root.ref.main, title);\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didRequestItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_CANCEL'));\n};\n\nconst didAbortItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_ABORTED'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_RETRY'));\n};\n\nconst didCompleteItemProcessing = ({ root }) => {\n    text(root.ref.main, root.query('GET_LABEL_FILE_PROCESSING_COMPLETE'));\n    text(root.ref.sub, root.query('GET_LABEL_TAP_TO_UNDO'));\n};\n\nconst clear = ({ root }) => {\n    text(root.ref.main, '');\n    text(root.ref.sub, '');\n};\n\nconst error = ({ root, action }) => {\n    text(root.ref.main, action.status.main);\n    text(root.ref.sub, action.status.sub);\n};\n\nexport const fileStatus = createView({\n    name: 'file-status',\n    ignoreRect: true,\n    ignoreRectUpdate: true,\n    write: createRoute({\n        DID_LOAD_ITEM: clear,\n        DID_REVERT_ITEM_PROCESSING: clear,\n        DID_REQUEST_ITEM_PROCESSING: didRequestItemProcessing,\n        DID_ABORT_ITEM_PROCESSING: didAbortItemProcessing,\n        DID_COMPLETE_ITEM_PROCESSING: didCompleteItemProcessing,\n        DID_UPDATE_ITEM_PROCESS_PROGRESS: didSetItemProcessProgress,\n        DID_UPDATE_ITEM_LOAD_PROGRESS: didSetItemLoadProgress,\n        DID_THROW_ITEM_LOAD_ERROR: error,\n        DID_THROW_ITEM_INVALID: error,\n        DID_THROW_ITEM_PROCESSING_ERROR: error,\n        DID_THROW_ITEM_PROCESSING_REVERT_ERROR: error,\n        DID_THROW_ITEM_REMOVE_ERROR: error\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    create,\n    mixins: {\n        styles: ['translateX', 'translateY', 'opacity'],\n        animations: {\n            opacity: { type: 'tween', duration: 250 },\n            translateX: 'spring',\n            translateY: 'spring'\n        }\n    }\n});\n"
  },
  {
    "path": "src/js/app/view/fileWrapper.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { formatFilename } from '../../utils/formatFilename';\nimport { createElement } from '../../utils/createElement';\nimport { text } from '../../utils/text';\nimport { file } from './file';\nimport { applyFilters } from '../../filter';\n\n/**\n * Creates the file view\n */\nconst create = ({ root, props }) => {\n\n    // filename\n    root.ref.fileName = createElement('legend');\n    root.appendChild(root.ref.fileName);\n\n    // file appended\n    root.ref.file = root.appendChildView(\n        root.createChildView(file, { id: props.id })\n    );\n\n    // data has moved to data.js\n    root.ref.data = false;\n};\n\n/**\n * Data storage\n */\nconst didLoadItem = ({ root, props }) => {\n    // updates the legend of the fieldset so screenreaders can better group buttons\n    text(\n        root.ref.fileName,\n        formatFilename(root.query('GET_ITEM_NAME', props.id))\n    );\n};\n\nexport const fileWrapper = createView({\n    create,\n    ignoreRect: true,\n    write: createRoute({\n        DID_LOAD_ITEM: didLoadItem\n    }),\n    didCreateView: root => {\n        applyFilters('CREATE_VIEW', { ...root, view: root });\n    },\n    tag: 'fieldset',\n    name: 'file-wrapper'\n});\n"
  },
  {
    "path": "src/js/app/view/item.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { fileWrapper } from './fileWrapper';\nimport { panel } from './panel';\nimport { createDragHelper } from '../utils/createDragHelper';\n\nconst ITEM_TRANSLATE_SPRING = {\n    type: 'spring',\n    stiffness: 0.75,\n    damping: 0.45,\n    mass: 10,\n};\n\nconst ITEM_SCALE_SPRING = 'spring';\n\nconst StateMap = {\n    DID_START_ITEM_LOAD: 'busy',\n    DID_UPDATE_ITEM_LOAD_PROGRESS: 'loading',\n    DID_THROW_ITEM_INVALID: 'load-invalid',\n    DID_THROW_ITEM_LOAD_ERROR: 'load-error',\n    DID_LOAD_ITEM: 'idle',\n    DID_THROW_ITEM_REMOVE_ERROR: 'remove-error',\n    DID_START_ITEM_REMOVE: 'busy',\n    DID_START_ITEM_PROCESSING: 'busy processing',\n    DID_REQUEST_ITEM_PROCESSING: 'busy processing',\n    DID_UPDATE_ITEM_PROCESS_PROGRESS: 'processing',\n    DID_COMPLETE_ITEM_PROCESSING: 'processing-complete',\n    DID_THROW_ITEM_PROCESSING_ERROR: 'processing-error',\n    DID_THROW_ITEM_PROCESSING_REVERT_ERROR: 'processing-revert-error',\n    DID_ABORT_ITEM_PROCESSING: 'cancelled',\n    DID_REVERT_ITEM_PROCESSING: 'idle',\n};\n\n/**\n * Creates the file view\n */\nconst create = ({ root, props }) => {\n    // select\n    root.ref.handleClick = e => root.dispatch('DID_ACTIVATE_ITEM', { id: props.id });\n\n    // set id\n    root.element.id = `filepond--item-${props.id}`;\n    root.element.addEventListener('click', root.ref.handleClick);\n\n    // file view\n    root.ref.container = root.appendChildView(root.createChildView(fileWrapper, { id: props.id }));\n\n    // file panel\n    root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'item-panel' }));\n\n    // default start height\n    root.ref.panel.height = null;\n\n    // by default not marked for removal\n    props.markedForRemoval = false;\n\n    // if not allowed to reorder file items, exit here\n    if (!root.query('GET_ALLOW_REORDER')) return;\n\n    // set to idle so shows grab cursor\n    root.element.dataset.dragState = 'idle';\n\n    const grab = e => {\n        if (!e.isPrimary) return;\n\n        let removedActivateListener = false;\n\n        const origin = {\n            x: e.pageX,\n            y: e.pageY,\n        };\n\n        props.dragOrigin = {\n            x: root.translateX,\n            y: root.translateY,\n        };\n\n        props.dragCenter = {\n            x: e.offsetX,\n            y: e.offsetY,\n        };\n\n        const dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));\n\n        root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });\n\n        const drag = e => {\n            if (!e.isPrimary) return;\n\n            e.stopPropagation();\n            e.preventDefault();\n\n            props.dragOffset = {\n                x: e.pageX - origin.x,\n                y: e.pageY - origin.y,\n            };\n\n            // if dragged stop listening to clicks, will re-add when done dragging\n            const dist =\n                props.dragOffset.x * props.dragOffset.x + props.dragOffset.y * props.dragOffset.y;\n            if (dist > 16 && !removedActivateListener) {\n                removedActivateListener = true;\n                root.element.removeEventListener('click', root.ref.handleClick);\n            }\n\n            root.dispatch('DID_DRAG_ITEM', { id: props.id, dragState });\n        };\n\n        const drop = e => {\n            if (!e.isPrimary) return;\n\n            props.dragOffset = {\n                x: e.pageX - origin.x,\n                y: e.pageY - origin.y,\n            };\n\n            reset();\n        };\n\n        const cancel = () => {\n            reset();\n        };\n\n        const reset = () => {\n            document.removeEventListener('pointercancel', cancel);\n            document.removeEventListener('pointermove', drag);\n            document.removeEventListener('pointerup', drop);\n\n            root.dispatch('DID_DROP_ITEM', { id: props.id, dragState });\n\n            // start listening to clicks again\n            if (removedActivateListener) {\n                setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);\n            }\n        };\n\n        document.addEventListener('pointercancel', cancel);\n        document.addEventListener('pointermove', drag);\n        document.addEventListener('pointerup', drop);\n    };\n\n    root.element.addEventListener('pointerdown', grab);\n};\n\nconst route = createRoute({\n    DID_UPDATE_PANEL_HEIGHT: ({ root, action }) => {\n        root.height = action.height;\n    },\n});\n\nconst write = createRoute(\n    {\n        DID_GRAB_ITEM: ({ root, props }) => {\n            props.dragOrigin = {\n                x: root.translateX,\n                y: root.translateY,\n            };\n        },\n        DID_DRAG_ITEM: ({ root }) => {\n            root.element.dataset.dragState = 'drag';\n        },\n        DID_DROP_ITEM: ({ root, props }) => {\n            props.dragOffset = null;\n            props.dragOrigin = null;\n            root.element.dataset.dragState = 'drop';\n        },\n    },\n    ({ root, actions, props, shouldOptimize }) => {\n        if (root.element.dataset.dragState === 'drop') {\n            if (root.scaleX <= 1) {\n                root.element.dataset.dragState = 'idle';\n            }\n        }\n\n        // select last state change action\n        let action = actions\n            .concat()\n            .filter(action => /^DID_/.test(action.type))\n            .reverse()\n            .find(action => StateMap[action.type]);\n\n        // no need to set same state twice\n        if (action && action.type !== props.currentState) {\n            // set current state\n            props.currentState = action.type;\n\n            // set state\n            root.element.dataset.filepondItemState = StateMap[props.currentState] || '';\n        }\n\n        // route actions\n        const aspectRatio =\n            root.query('GET_ITEM_PANEL_ASPECT_RATIO') || root.query('GET_PANEL_ASPECT_RATIO');\n        if (!aspectRatio) {\n            route({ root, actions, props });\n            if (!root.height && root.ref.container.rect.element.height > 0) {\n                root.height = root.ref.container.rect.element.height;\n            }\n        } else if (!shouldOptimize) {\n            root.height = root.rect.element.width * aspectRatio;\n        }\n\n        // sync panel height with item height\n        if (shouldOptimize) {\n            root.ref.panel.height = null;\n        }\n\n        root.ref.panel.height = root.height;\n    }\n);\n\nexport const item = createView({\n    create,\n    write,\n    destroy: ({ root, props }) => {\n        root.element.removeEventListener('click', root.ref.handleClick);\n        root.dispatch('RELEASE_ITEM', { query: props.id });\n    },\n    tag: 'li',\n    name: 'item',\n    mixins: {\n        apis: [\n            'id',\n            'interactionMethod',\n            'markedForRemoval',\n            'spawnDate',\n            'dragCenter',\n            'dragOrigin',\n            'dragOffset',\n        ],\n        styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity', 'height'],\n        animations: {\n            scaleX: ITEM_SCALE_SPRING,\n            scaleY: ITEM_SCALE_SPRING,\n            translateX: ITEM_TRANSLATE_SPRING,\n            translateY: ITEM_TRANSLATE_SPRING,\n            opacity: { type: 'tween', duration: 150 },\n        },\n    },\n});\n"
  },
  {
    "path": "src/js/app/view/list.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { InteractionMethod } from '../enum/InteractionMethod';\nimport { item } from './item';\nimport { attr } from '../../utils/attr';\nimport { getItemIndexByPosition } from '../utils/getItemIndexByPosition';\nimport { dropAreaDimensions } from '../utils/dropAreaDimensions';\nimport getItemsPerRow from '../utils/getItemsPerRow';\n\nconst create = ({ root }) => {\n    // need to set role to list as otherwise it won't be read as a list by VoiceOver\n    attr(root.element, 'role', 'list');\n\n    root.ref.lastItemSpanwDate = Date.now();\n};\n\n/**\n * Inserts a new item\n * @param root\n * @param action\n */\nconst addItemView = ({ root, action }) => {\n    const { id, index, interactionMethod } = action;\n\n    root.ref.addIndex = index;\n\n    const now = Date.now();\n    let spawnDate = now;\n    let opacity = 1;\n\n    if (interactionMethod !== InteractionMethod.NONE) {\n        opacity = 0;\n        const cooldown = root.query('GET_ITEM_INSERT_INTERVAL');\n        const dist = now - root.ref.lastItemSpanwDate;\n        spawnDate = dist < cooldown ? now + (cooldown - dist) : now;\n    }\n\n    root.ref.lastItemSpanwDate = spawnDate;\n\n    root.appendChildView(\n        root.createChildView(\n            // view type\n            item,\n\n            // props\n            {\n                spawnDate,\n                id,\n                opacity,\n                interactionMethod,\n            }\n        ),\n        index\n    );\n};\n\nconst moveItem = (item, x, y, vx = 0, vy = 1) => {\n    // set to null to remove animation while dragging\n    if (item.dragOffset) {\n        item.translateX = null;\n        item.translateY = null;\n        item.translateX = item.dragOrigin.x + item.dragOffset.x;\n        item.translateY = item.dragOrigin.y + item.dragOffset.y;\n        item.scaleX = 1.025;\n        item.scaleY = 1.025;\n    } else {\n        item.translateX = x;\n        item.translateY = y;\n\n        if (Date.now() > item.spawnDate) {\n            // reveal element\n            if (item.opacity === 0) {\n                introItemView(item, x, y, vx, vy);\n            }\n\n            // make sure is default scale every frame\n            item.scaleX = 1;\n            item.scaleY = 1;\n            item.opacity = 1;\n        }\n    }\n};\n\nconst introItemView = (item, x, y, vx, vy) => {\n    if (item.interactionMethod === InteractionMethod.NONE) {\n        item.translateX = null;\n        item.translateX = x;\n        item.translateY = null;\n        item.translateY = y;\n    } else if (item.interactionMethod === InteractionMethod.DROP) {\n        item.translateX = null;\n        item.translateX = x - vx * 20;\n\n        item.translateY = null;\n        item.translateY = y - vy * 10;\n\n        item.scaleX = 0.8;\n        item.scaleY = 0.8;\n    } else if (item.interactionMethod === InteractionMethod.BROWSE) {\n        item.translateY = null;\n        item.translateY = y - 30;\n    } else if (item.interactionMethod === InteractionMethod.API) {\n        item.translateX = null;\n        item.translateX = x - 30;\n        item.translateY = null;\n    }\n};\n\n/**\n * Removes an existing item\n * @param root\n * @param action\n */\nconst removeItemView = ({ root, action }) => {\n    const { id } = action;\n\n    // get the view matching the given id\n    const view = root.childViews.find(child => child.id === id);\n\n    // if no view found, exit\n    if (!view) {\n        return;\n    }\n\n    // animate view out of view\n    view.scaleX = 0.9;\n    view.scaleY = 0.9;\n    view.opacity = 0;\n\n    // mark for removal\n    view.markedForRemoval = true;\n};\n\nconst getItemHeight = child =>\n    child.rect.element.height +\n    child.rect.element.marginBottom +\n    child.rect.element.marginTop;\nconst getItemWidth = child =>\n    child.rect.element.width +\n    child.rect.element.marginLeft * 0.5 +\n    child.rect.element.marginRight * 0.5;\n\nconst dragItem = ({ root, action }) => {\n    const { id, dragState } = action;\n\n    // reference to item\n    const item = root.query('GET_ITEM', { id });\n\n    // get the view matching the given id\n    const view = root.childViews.find(child => child.id === id);\n\n    const numItems = root.childViews.length;\n    const oldIndex = dragState.getItemIndex(item);\n\n    // if no view found, exit\n    if (!view) return;\n\n    const dragPosition = {\n        x: view.dragOrigin.x + view.dragOffset.x + view.dragCenter.x,\n        y: view.dragOrigin.y + view.dragOffset.y + view.dragCenter.y,\n    };\n\n    // get drag area dimensions\n    const dragHeight = getItemHeight(view);\n    const dragWidth = getItemWidth(view);\n\n    // get rows and columns (There will always be at least one row and one column if a file is present)\n    let cols = Math.floor(root.rect.outer.width / dragWidth);\n    if (cols > numItems) cols = numItems;\n\n    // rows are used to find when we have left the preview area bounding box\n    const rows = Math.floor(numItems / cols + 1);\n\n    dropAreaDimensions.setHeight = dragHeight * rows;\n    dropAreaDimensions.setWidth = dragWidth * cols;\n\n    // get new index of dragged item\n    var location = {\n        y: Math.floor(dragPosition.y / dragHeight),\n        x: Math.floor(dragPosition.x / dragWidth),\n        getGridIndex: function getGridIndex() {\n            if (\n                dragPosition.y > dropAreaDimensions.getHeight ||\n                dragPosition.y < 0 ||\n                dragPosition.x > dropAreaDimensions.getWidth ||\n                dragPosition.x < 0\n            )\n                return oldIndex;\n            return this.y * cols + this.x;\n        },\n        getColIndex: function getColIndex() {\n            const items = root.query('GET_ACTIVE_ITEMS');\n            const visibleChildren = root.childViews.filter(child => child.rect.element.height);\n            const children = items.map(item =>\n                visibleChildren.find(childView => childView.id === item.id)\n            );\n            const currentIndex = children.findIndex(child => child === view);\n            const dragHeight = getItemHeight(view);\n            const l = children.length;\n            let idx = l;\n            let childHeight = 0;\n            let childBottom = 0;\n            let childTop = 0;\n            for (let i = 0; i < l; i++) {\n                childHeight = getItemHeight(children[i]);\n                childTop = childBottom;\n                childBottom = childTop + childHeight;\n                if (dragPosition.y < childBottom) {\n                    if (currentIndex > i) {\n                        if (dragPosition.y < childTop + dragHeight) {\n                            idx = i;\n                            break;\n                        }\n                        continue;\n                    }\n                    idx = i;\n                    break;\n                }\n            }\n            return idx;\n        },\n    };\n\n    // get new index\n    const index = cols > 1 ? location.getGridIndex() : location.getColIndex();\n    root.dispatch('MOVE_ITEM', { query: view, index });\n\n    // if the index of the item changed, dispatch reorder action\n    const currentIndex = dragState.getIndex();\n\n    if (currentIndex === undefined || currentIndex !== index) {\n        dragState.setIndex(index);\n\n        if (currentIndex === undefined) return;\n\n        root.dispatch('DID_REORDER_ITEMS', {\n            items: root.query('GET_ACTIVE_ITEMS'),\n            origin: oldIndex,\n            target: index,\n        });\n    }\n};\n\n/**\n * Setup action routes\n */\nconst route = createRoute({\n    DID_ADD_ITEM: addItemView,\n    DID_REMOVE_ITEM: removeItemView,\n    DID_DRAG_ITEM: dragItem,\n});\n\n/**\n * Write to view\n * @param root\n * @param actions\n * @param props\n */\nconst write = ({ root, props, actions, shouldOptimize }) => {\n    // route actions\n    route({ root, props, actions });\n\n    const { dragCoordinates } = props;\n\n    // available space on horizontal axis\n    const horizontalSpace = root.rect.element.width;\n\n    // only draw children that have dimensions\n    const visibleChildren = root.childViews.filter(child => child.rect.element.height);\n\n    // sort based on current active items\n    const children = root\n        .query('GET_ACTIVE_ITEMS')\n        .map(item => visibleChildren.find(child => child.id === item.id))\n        .filter(item => item);\n\n    // get index\n    const dragIndex = dragCoordinates\n        ? getItemIndexByPosition(root, children, dragCoordinates)\n        : null;\n\n    // add index is used to reserve the dropped/added item index till the actual item is rendered\n    const addIndex = root.ref.addIndex || null;\n\n    // add index no longer needed till possibly next draw\n    root.ref.addIndex = null;\n\n    let dragIndexOffset = 0;\n    let removeIndexOffset = 0;\n    let addIndexOffset = 0;\n\n    if (children.length === 0) return;\n\n    const childRect = children[0].rect.element;\n    const itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n    const itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n    const itemWidth = childRect.width + itemHorizontalMargin;\n    const itemHeight = childRect.height + itemVerticalMargin;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        let offsetY = 0;\n        let dragOffset = 0;\n\n        children.forEach((child, index) => {\n            if (dragIndex) {\n                let dist = index - dragIndex;\n                if (dist === -2) {\n                    dragOffset = -itemVerticalMargin * 0.25;\n                } else if (dist === -1) {\n                    dragOffset = -itemVerticalMargin * 0.75;\n                } else if (dist === 0) {\n                    dragOffset = itemVerticalMargin * 0.75;\n                } else if (dist === 1) {\n                    dragOffset = itemVerticalMargin * 0.25;\n                } else {\n                    dragOffset = 0;\n                }\n            }\n\n            if (shouldOptimize) {\n                child.translateX = null;\n                child.translateY = null;\n            }\n\n            if (!child.markedForRemoval) {\n                moveItem(child, 0, offsetY + dragOffset);\n            }\n\n            let itemHeight = child.rect.element.height + itemVerticalMargin;\n\n            let visualHeight = itemHeight * (child.markedForRemoval ? child.opacity : 1);\n\n            offsetY += visualHeight;\n        });\n    }\n    // grid\n    else {\n        let prevX = 0;\n        let prevY = 0;\n\n        children.forEach((child, index) => {\n            if (index === dragIndex) {\n                dragIndexOffset = 1;\n            }\n\n            if (index === addIndex) {\n                addIndexOffset += 1;\n            }\n\n            if (child.markedForRemoval && child.opacity < 0.5) {\n                removeIndexOffset -= 1;\n            }\n\n            const visualIndex = index + addIndexOffset + dragIndexOffset + removeIndexOffset;\n\n            const indexX = visualIndex % itemsPerRow;\n            const indexY = Math.floor(visualIndex / itemsPerRow);\n\n            const offsetX = indexX * itemWidth;\n            const offsetY = indexY * itemHeight;\n\n            const vectorX = Math.sign(offsetX - prevX);\n            const vectorY = Math.sign(offsetY - prevY);\n\n            prevX = offsetX;\n            prevY = offsetY;\n\n            if (child.markedForRemoval) return;\n\n            if (shouldOptimize) {\n                child.translateX = null;\n                child.translateY = null;\n            }\n\n            moveItem(child, offsetX, offsetY, vectorX, vectorY);\n        });\n    }\n};\n\n/**\n * Filters actions that are meant specifically for a certain child of the list\n * @param child\n * @param actions\n */\nconst filterSetItemActions = (child, actions) =>\n    actions.filter(action => {\n        // if action has an id, filter out actions that don't have this child id\n        if (action.data && action.data.id) {\n            return child.id === action.data.id;\n        }\n\n        // allow all other actions\n        return true;\n    });\n\nexport const list = createView({\n    create,\n    write,\n    tag: 'ul',\n    name: 'list',\n    didWriteView: ({ root }) => {\n        root.childViews\n            .filter(view => view.markedForRemoval && view.opacity === 0 && view.resting)\n            .forEach(view => {\n                view._destroy();\n                root.removeChildView(view);\n            });\n    },\n    filterFrameActionsForChild: filterSetItemActions,\n    mixins: {\n        apis: ['dragCoordinates'],\n    },\n});\n"
  },
  {
    "path": "src/js/app/view/listScroller.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { list } from './list';\n\nconst create = ({ root, props }) => {\n    root.ref.list = root.appendChildView(root.createChildView(list));\n    props.dragCoordinates = null;\n    props.overflowing = false;\n};\n\nconst storeDragCoordinates = ({ root, props, action }) => {\n    if (!root.query('GET_ITEM_INSERT_LOCATION_FREEDOM')) return;\n    props.dragCoordinates = {\n        left: action.position.scopeLeft - root.ref.list.rect.element.left,\n        top: action.position.scopeTop - (root.rect.outer.top + root.rect.element.marginTop + root.rect.element.scrollTop)\n    };\n};\n\nconst clearDragCoordinates = ({ props }) => {\n    props.dragCoordinates = null;\n};\n\nconst route = createRoute({\n    DID_DRAG: storeDragCoordinates,\n    DID_END_DRAG: clearDragCoordinates\n});\n\nconst write = ({ root, props, actions }) => {\n\n    // route actions\n    route({ root, props, actions });\n\n    // current drag position\n    root.ref.list.dragCoordinates = props.dragCoordinates;\n    \n    // if currently overflowing but no longer received overflow\n    if (props.overflowing && !props.overflow) {\n        props.overflowing = false;\n\n        // reset overflow state\n        root.element.dataset.state = '';\n        root.height = null;\n    }\n\n    // if is not overflowing currently but does receive overflow value\n    if (props.overflow) {\n        const newHeight = Math.round(props.overflow);\n        if (newHeight !== root.height) {\n            props.overflowing = true;\n            root.element.dataset.state = 'overflow';\n            root.height = newHeight;\n        }\n    }\n\n};\n\nexport const listScroller = createView({\n    create,\n    write,\n    name: 'list-scroller',\n    mixins: {\n        apis: ['overflow' , 'dragCoordinates'],\n        styles: ['height', 'translateY'],\n        animations: {\n            translateY: 'spring'\n        }\n    }\n});\n"
  },
  {
    "path": "src/js/app/view/panel.js",
    "content": "import { createView } from '../frame/index';\nimport { isBoolean } from '../../utils/isBoolean';\n\nconst PANEL_SPRING_PROPS = { type: 'spring', damping: 0.6, mass: 7 };\n\nconst create = ({ root, props }) => {\n    [\n        {\n            name: 'top'\n        },\n        {\n            name: 'center',\n            props: {\n                translateY: null,\n                scaleY: null\n            },\n            mixins: {\n                animations: {\n                    scaleY: PANEL_SPRING_PROPS\n                },\n                styles: ['translateY', 'scaleY']\n            }\n        },\n        {\n            name: 'bottom',\n            props: {\n                translateY: null\n            },\n            mixins: {\n                animations: {\n                    translateY: PANEL_SPRING_PROPS\n                },\n                styles: ['translateY']\n            }\n        }\n    ].forEach(section => {\n        createSection(root, section, props.name);\n    });\n\n    root.element.classList.add(`filepond--${props.name}`);\n\n    root.ref.scalable = null;\n};\n\nconst createSection = (root, section, className) => {\n\n    const viewConstructor = createView({\n        name: `panel-${section.name} filepond--${className}`,\n        mixins: section.mixins,\n        ignoreRectUpdate: true\n    });\n\n    const view = root.createChildView(viewConstructor, section.props);\n\n    root.ref[section.name] = root.appendChildView(view);\n};\n\nconst write = ({ root, props }) => {\n\n    // update scalable state\n    if (root.ref.scalable === null || props.scalable !== root.ref.scalable) {\n        root.ref.scalable = isBoolean(props.scalable)\n            ? props.scalable\n            : true;\n        root.element.dataset.scalable = root.ref.scalable;\n    }\n    \n    // no height, can't set\n    if (!props.height) return;\n\n    // get child rects\n    const topRect = root.ref.top.rect.element;\n    const bottomRect = root.ref.bottom.rect.element;\n\n    // make sure height never is smaller than bottom and top seciton heights combined (will probably never happen, but who knows)\n    const height = Math.max(topRect.height + bottomRect.height, props.height);\n\n    // offset center part\n    root.ref.center.translateY = topRect.height;\n\n    // scale center part\n    // use math ceil to prevent transparent lines because of rounding errors\n    root.ref.center.scaleY =\n        (height - topRect.height - bottomRect.height) / 100;\n\n    // offset bottom part\n    root.ref.bottom.translateY = height - bottomRect.height;\n};\n\nexport const panel = createView({\n    name: 'panel',\n    read: ({ root, props }) => props.heightCurrent = root.ref.bottom.translateY,\n    write,\n    create,\n    ignoreRect: true,\n    mixins: {\n        apis: ['height', 'heightCurrent', 'scalable']\n    }\n});\n"
  },
  {
    "path": "src/js/app/view/progressIndicator.js",
    "content": "import { createView } from '../frame/index';\nimport { createElement } from '../frame/utils/createElement';\nimport { attr } from '../../utils/attr';\nimport { percentageArc } from '../../utils/percentageArc';\n\nconst create = ({ root, props }) => {\n    // start at 0\n    props.spin = false;\n    props.progress = 0;\n    props.opacity = 0;\n\n    // svg\n    const svg = createElement('svg');\n    root.ref.path = createElement('path', {\n        'stroke-width': 2,\n        'stroke-linecap': 'round',\n    });\n    svg.appendChild(root.ref.path);\n\n    root.ref.svg = svg;\n\n    root.appendChild(svg);\n};\n\nconst write = ({ root, props }) => {\n    if (props.opacity === 0) {\n        return;\n    }\n\n    if (props.align) {\n        root.element.dataset.align = props.align;\n    }\n\n    // get width of stroke\n    const ringStrokeWidth = parseInt(attr(root.ref.path, 'stroke-width'), 10);\n\n    // calculate size of ring\n    const size = root.rect.element.width * 0.5;\n\n    // ring state\n    let ringFrom = 0;\n    let ringTo = 0;\n\n    // now in busy mode\n    if (props.spin) {\n        ringFrom = 0;\n        ringTo = 0.5;\n    } else {\n        ringFrom = 0;\n        ringTo = props.progress;\n    }\n\n    // get arc path\n    const coordinates = percentageArc(size, size, size - ringStrokeWidth, ringFrom, ringTo);\n\n    // update progress bar\n    attr(root.ref.path, 'd', coordinates);\n\n    // hide while contains 0 value\n    attr(root.ref.path, 'stroke-opacity', props.spin || props.progress > 0 ? 1 : 0);\n};\n\nexport const progressIndicator = createView({\n    tag: 'div',\n    name: 'progress-indicator',\n    ignoreRectUpdate: true,\n    ignoreRect: true,\n    create,\n    write,\n    mixins: {\n        apis: ['progress', 'spin', 'align'],\n        styles: ['opacity'],\n        animations: {\n            opacity: { type: 'tween', duration: 500 },\n            progress: {\n                type: 'spring',\n                stiffness: 0.95,\n                damping: 0.65,\n                mass: 10,\n            },\n        },\n    },\n});\n"
  },
  {
    "path": "src/js/app/view/root.js",
    "content": "import { createView, createRoute } from '../frame/index';\nimport { applyFilterChain, applyFilters } from '../../filter';\nimport { listScroller } from './listScroller';\nimport { panel } from './panel';\nimport { browser } from './browser';\nimport { dropLabel } from './dropLabel';\nimport { drip } from './drip';\nimport { data } from './data';\nimport { createHopper } from '../utils/createHopper';\nimport { createPaster } from '../utils/createPaster';\nimport { InteractionMethod } from '../enum/InteractionMethod';\nimport { getItemIndexByPosition } from '../utils/getItemIndexByPosition';\nimport { isInt } from '../../utils/isInt';\nimport { isEmpty } from '../../utils/isEmpty';\nimport { assistant } from './assistant';\nimport { toCamels } from '../../utils/toCamels';\nimport { createElement } from '../../utils/createElement';\nimport { createResponse } from '../../utils/createResponse';\nimport { debounce } from '../../utils/debounce';\nimport { isFile } from '../../utils/isFile';\nimport getItemsPerRow from '../utils/getItemsPerRow';\n\nconst MAX_FILES_LIMIT = 1000000;\n\nconst prevent = e => e.preventDefault();\n\nconst create = ({ root, props }) => {\n    // Add id\n    const id = root.query('GET_ID');\n    if (id) {\n        root.element.id = id;\n    }\n\n    // Add className\n    const className = root.query('GET_CLASS_NAME');\n    if (className) {\n        className\n            .split(' ')\n            .filter(name => name.length)\n            .forEach(name => {\n                root.element.classList.add(name);\n            });\n    }\n\n    // Field label\n    root.ref.label = root.appendChildView(\n        root.createChildView(dropLabel, {\n            ...props,\n            translateY: null,\n            caption: root.query('GET_LABEL_IDLE'),\n        })\n    );\n\n    // List of items\n    root.ref.list = root.appendChildView(root.createChildView(listScroller, { translateY: null }));\n\n    // Background panel\n    root.ref.panel = root.appendChildView(root.createChildView(panel, { name: 'panel-root' }));\n\n    // Assistant notifies assistive tech when content changes\n    root.ref.assistant = root.appendChildView(root.createChildView(assistant, { ...props }));\n\n    // Data\n    root.ref.data = root.appendChildView(root.createChildView(data, { ...props }));\n\n    // Measure (tests if fixed height was set)\n    // DOCTYPE needs to be set for this to work\n    root.ref.measure = createElement('div');\n    root.ref.measure.style.height = '100%';\n    root.element.appendChild(root.ref.measure);\n\n    // information on the root height or fixed height status\n    root.ref.bounds = null;\n\n    // apply initial style properties\n    root.query('GET_STYLES')\n        .filter(style => !isEmpty(style.value))\n        .map(({ name, value }) => {\n            root.element.dataset[name] = value;\n        });\n\n    // determine if width changed\n    root.ref.widthPrevious = null;\n    root.ref.widthUpdated = debounce(() => {\n        root.ref.updateHistory = [];\n        root.dispatch('DID_RESIZE_ROOT');\n    }, 250);\n\n    // history of updates\n    root.ref.previousAspectRatio = null;\n    root.ref.updateHistory = [];\n\n    // prevent scrolling and zooming on iOS (only if supports pointer events, for then we can enable reorder)\n    const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;\n    const hasPointerEvents = 'PointerEvent' in window;\n    if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {\n        root.element.addEventListener('touchmove', prevent, { passive: false });\n        root.element.addEventListener('gesturestart', prevent);\n    }\n\n    // add credits\n    const credits = root.query('GET_CREDITS');\n    const hasCredits = credits.length === 2;\n    if (hasCredits) {\n        const frag = document.createElement('a');\n        frag.className = 'filepond--credits';\n        frag.href = credits[0];\n        frag.tabIndex = -1;\n        frag.target = '_blank';\n        frag.rel = 'noopener noreferrer nofollow';\n        frag.textContent = credits[1];\n        root.element.appendChild(frag);\n        root.ref.credits = frag;\n    }\n};\n\nconst write = ({ root, props, actions }) => {\n    // route actions\n    route({ root, props, actions });\n\n    // apply style properties\n    actions\n        .filter(action => /^DID_SET_STYLE_/.test(action.type))\n        .filter(action => !isEmpty(action.data.value))\n        .map(({ type, data }) => {\n            const name = toCamels(type.substring(8).toLowerCase(), '_');\n            root.element.dataset[name] = data.value;\n            root.invalidateLayout();\n        });\n\n    if (root.rect.element.hidden) return;\n\n    if (root.rect.element.width !== root.ref.widthPrevious) {\n        root.ref.widthPrevious = root.rect.element.width;\n        root.ref.widthUpdated();\n    }\n\n    // get box bounds, we do this only once\n    let bounds = root.ref.bounds;\n    if (!bounds) {\n        bounds = root.ref.bounds = calculateRootBoundingBoxHeight(root);\n\n        // destroy measure element\n        root.element.removeChild(root.ref.measure);\n        root.ref.measure = null;\n    }\n\n    // get quick references to various high level parts of the upload tool\n    const { hopper, label, list, panel } = root.ref;\n\n    // sets correct state to hopper scope\n    if (hopper) {\n        hopper.updateHopperState();\n    }\n\n    // bool to indicate if we're full or not\n    const aspectRatio = root.query('GET_PANEL_ASPECT_RATIO');\n    const isMultiItem = root.query('GET_ALLOW_MULTIPLE');\n    const totalItems = root.query('GET_TOTAL_ITEMS');\n    const maxItems = isMultiItem ? root.query('GET_MAX_FILES') || MAX_FILES_LIMIT : 1;\n    const atMaxCapacity = totalItems === maxItems;\n\n    // action used to add item\n    const addAction = actions.find(action => action.type === 'DID_ADD_ITEM');\n\n    // if reached max capacity and we've just reached it\n    if (atMaxCapacity && addAction) {\n        // get interaction type\n        const interactionMethod = addAction.data.interactionMethod;\n\n        // hide label\n        label.opacity = 0;\n\n        if (isMultiItem) {\n            label.translateY = -40;\n        } else {\n            if (interactionMethod === InteractionMethod.API) {\n                label.translateX = 40;\n            } else if (interactionMethod === InteractionMethod.BROWSE) {\n                label.translateY = 40;\n            } else {\n                label.translateY = 30;\n            }\n        }\n    } else if (!atMaxCapacity) {\n        label.opacity = 1;\n        label.translateX = 0;\n        label.translateY = 0;\n    }\n\n    const listItemMargin = calculateListItemMargin(root);\n\n    const listHeight = calculateListHeight(root);\n\n    const labelHeight = label.rect.element.height;\n    const currentLabelHeight = !isMultiItem || atMaxCapacity ? 0 : labelHeight;\n\n    const listMarginTop = atMaxCapacity ? list.rect.element.marginTop : 0;\n    const listMarginBottom = totalItems === 0 ? 0 : list.rect.element.marginBottom;\n\n    const visualHeight = currentLabelHeight + listMarginTop + listHeight.visual + listMarginBottom;\n    const boundsHeight = currentLabelHeight + listMarginTop + listHeight.bounds + listMarginBottom;\n\n    // link list to label bottom position\n    list.translateY =\n        Math.max(0, currentLabelHeight - list.rect.element.marginTop) - listItemMargin.top;\n\n    if (aspectRatio) {\n        // fixed aspect ratio\n\n        // calculate height based on width\n        const width = root.rect.element.width;\n        const height = width * aspectRatio;\n\n        // clear history if aspect ratio has changed\n        if (aspectRatio !== root.ref.previousAspectRatio) {\n            root.ref.previousAspectRatio = aspectRatio;\n            root.ref.updateHistory = [];\n        }\n\n        // remember this width\n        const history = root.ref.updateHistory;\n        history.push(width);\n\n        const MAX_BOUNCES = 2;\n        if (history.length > MAX_BOUNCES * 2) {\n            const l = history.length;\n            const bottom = l - 10;\n            let bounces = 0;\n            for (let i = l; i >= bottom; i--) {\n                if (history[i] === history[i - 2]) {\n                    bounces++;\n                }\n\n                if (bounces >= MAX_BOUNCES) {\n                    // dont adjust height\n                    return;\n                }\n            }\n        }\n\n        // fix height of panel so it adheres to aspect ratio\n        panel.scalable = false;\n        panel.height = height;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            height -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        if (listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = height;\n    } else if (bounds.fixedHeight) {\n        // fixed height\n\n        // fix height of panel\n        panel.scalable = false;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            bounds.fixedHeight -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        // set list height\n        if (listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // no need to set container bounds as these are handles by CSS fixed height\n    } else if (bounds.cappedHeight) {\n        // max-height\n\n        // not a fixed height panel\n        const isCappedHeight = visualHeight >= bounds.cappedHeight;\n        const panelHeight = Math.min(bounds.cappedHeight, visualHeight);\n        panel.scalable = true;\n        panel.height = isCappedHeight\n            ? panelHeight\n            : panelHeight - listItemMargin.top - listItemMargin.bottom;\n\n        // available height for list\n        const listAvailableHeight =\n            // the height of the panel minus the label height\n            panelHeight -\n            currentLabelHeight -\n            // the room we leave open between the end of the list and the panel bottom\n            (listMarginBottom - listItemMargin.bottom) -\n            // if we're full we need to leave some room between the top of the panel and the list\n            (atMaxCapacity ? listMarginTop : 0);\n\n        // set list height (if is overflowing)\n        if (visualHeight > bounds.cappedHeight && listHeight.visual > listAvailableHeight) {\n            list.overflow = listAvailableHeight;\n        } else {\n            list.overflow = null;\n        }\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = Math.min(\n            bounds.cappedHeight,\n            boundsHeight - listItemMargin.top - listItemMargin.bottom\n        );\n    } else {\n        // flexible height\n\n        // not a fixed height panel\n        const itemMargin = totalItems > 0 ? listItemMargin.top + listItemMargin.bottom : 0;\n        panel.scalable = true;\n        panel.height = Math.max(labelHeight, visualHeight - itemMargin);\n\n        // set container bounds (so pushes siblings downwards)\n        root.height = Math.max(labelHeight, boundsHeight - itemMargin);\n    }\n\n    // move credits to bottom\n    if (root.ref.credits && panel.heightCurrent)\n        root.ref.credits.style.transform = `translateY(${panel.heightCurrent}px)`;\n};\n\nconst calculateListItemMargin = root => {\n    const item = root.ref.list.childViews[0].childViews[0];\n    return item\n        ? {\n              top: item.rect.element.marginTop,\n              bottom: item.rect.element.marginBottom,\n          }\n        : {\n              top: 0,\n              bottom: 0,\n          };\n};\n\nconst calculateListHeight = root => {\n    let visual = 0;\n    let bounds = 0;\n\n    // get file list reference\n    const scrollList = root.ref.list;\n    const itemList = scrollList.childViews[0];\n    const visibleChildren = itemList.childViews.filter(child => child.rect.element.height);\n    const children = root\n        .query('GET_ACTIVE_ITEMS')\n        .map(item => visibleChildren.find(child => child.id === item.id))\n        .filter(item => item);\n\n    // no children, done!\n    if (children.length === 0) return { visual, bounds };\n\n    const horizontalSpace = itemList.rect.element.width;\n    const dragIndex = getItemIndexByPosition(itemList, children, scrollList.dragCoordinates);\n\n    const childRect = children[0].rect.element;\n\n    const itemVerticalMargin = childRect.marginTop + childRect.marginBottom;\n    const itemHorizontalMargin = childRect.marginLeft + childRect.marginRight;\n\n    const itemWidth = childRect.width + itemHorizontalMargin;\n    const itemHeight = childRect.height + itemVerticalMargin;\n\n    const newItem = typeof dragIndex !== 'undefined' && dragIndex >= 0 ? 1 : 0;\n    const removedItem = children.find(child => child.markedForRemoval && child.opacity < 0.45)\n        ? -1\n        : 0;\n    const verticalItemCount = children.length + newItem + removedItem;\n    const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth);\n\n    // stack\n    if (itemsPerRow === 1) {\n        children.forEach(item => {\n            const height = item.rect.element.height + itemVerticalMargin;\n            bounds += height;\n            visual += height * item.opacity;\n        });\n    }\n    // grid\n    else {\n        bounds = Math.ceil(verticalItemCount / itemsPerRow) * itemHeight;\n        visual = bounds;\n    }\n\n    return { visual, bounds };\n};\n\nconst calculateRootBoundingBoxHeight = root => {\n    const height = root.ref.measureHeight || null;\n    const cappedHeight = parseInt(root.style.maxHeight, 10) || null;\n    const fixedHeight = height === 0 ? null : height;\n\n    return {\n        cappedHeight,\n        fixedHeight,\n    };\n};\n\nconst exceedsMaxFiles = (root, items) => {\n    const allowReplace = root.query('GET_ALLOW_REPLACE');\n    const allowMultiple = root.query('GET_ALLOW_MULTIPLE');\n    const totalItems = root.query('GET_TOTAL_ITEMS');\n    let maxItems = root.query('GET_MAX_FILES');\n\n    // total amount of items being dragged\n    const totalBrowseItems = items.length;\n\n    // if does not allow multiple items and dragging more than one item\n    if (!allowMultiple && totalBrowseItems > 1) {\n        root.dispatch('DID_THROW_MAX_FILES', {\n            source: items,\n            error: createResponse('warning', 0, 'Max files'),\n        });\n        return true;\n    }\n\n    // limit max items to one if not allowed to drop multiple items\n    maxItems = allowMultiple ? maxItems : 1;\n\n    if (!allowMultiple && allowReplace) {\n        // There is only one item, so there is room to replace or add an item\n        return false;\n    }\n\n    // no more room?\n    const hasMaxItems = isInt(maxItems);\n    if (hasMaxItems && totalItems + totalBrowseItems > maxItems) {\n        root.dispatch('DID_THROW_MAX_FILES', {\n            source: items,\n            error: createResponse('warning', 0, 'Max files'),\n        });\n        return true;\n    }\n\n    return false;\n};\n\nconst getDragIndex = (list, children, position) => {\n    const itemList = list.childViews[0];\n    return getItemIndexByPosition(itemList, children, {\n        left: position.scopeLeft - itemList.rect.element.left,\n        top:\n            position.scopeTop -\n            (list.rect.outer.top + list.rect.element.marginTop + list.rect.element.scrollTop),\n    });\n};\n\n/**\n * Enable or disable file drop functionality\n */\nconst toggleDrop = root => {\n    const isAllowed = root.query('GET_ALLOW_DROP');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.hopper) {\n        const hopper = createHopper(\n            root.element,\n            items => {\n                // allow quick validation of dropped items\n                const beforeDropFile = root.query('GET_BEFORE_DROP_FILE') || (() => true);\n\n                // all items should be validated by all filters as valid\n                const dropValidation = root.query('GET_DROP_VALIDATION');\n                return dropValidation\n                    ? items.every(\n                          item =>\n                              applyFilters('ALLOW_HOPPER_ITEM', item, {\n                                  query: root.query,\n                              }).every(result => result === true) && beforeDropFile(item)\n                      )\n                    : true;\n            },\n            {\n                filterItems: items => {\n                    const ignoredFiles = root.query('GET_IGNORED_FILES');\n                    return items.filter(item => {\n                        if (isFile(item)) {\n                            return !ignoredFiles.includes(item.name.toLowerCase());\n                        }\n                        return true;\n                    });\n                },\n                catchesDropsOnPage: root.query('GET_DROP_ON_PAGE'),\n                requiresDropOnElement: root.query('GET_DROP_ON_ELEMENT'),\n            }\n        );\n\n        hopper.onload = (items, position) => {\n            // get item children elements and sort based on list sort\n            const list = root.ref.list.childViews[0];\n            const visibleChildren = list.childViews.filter(child => child.rect.element.height);\n            const children = root\n                .query('GET_ACTIVE_ITEMS')\n                .map(item => visibleChildren.find(child => child.id === item.id))\n                .filter(item => item);\n\n            applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(queue => {\n                // these files don't fit so stop here\n                if (exceedsMaxFiles(root, queue)) return false;\n\n                // go\n                root.dispatch('ADD_ITEMS', {\n                    items: queue,\n                    index: getDragIndex(root.ref.list, children, position),\n                    interactionMethod: InteractionMethod.DROP,\n                });\n            });\n\n            root.dispatch('DID_DROP', { position });\n\n            root.dispatch('DID_END_DRAG', { position });\n        };\n\n        hopper.ondragstart = position => {\n            root.dispatch('DID_START_DRAG', { position });\n        };\n\n        hopper.ondrag = debounce(position => {\n            root.dispatch('DID_DRAG', { position });\n        });\n\n        hopper.ondragend = position => {\n            root.dispatch('DID_END_DRAG', { position });\n        };\n\n        root.ref.hopper = hopper;\n\n        root.ref.drip = root.appendChildView(root.createChildView(drip));\n    } else if (!enabled && root.ref.hopper) {\n        root.ref.hopper.destroy();\n        root.ref.hopper = null;\n        root.removeChildView(root.ref.drip);\n    }\n};\n\n/**\n * Enable or disable browse functionality\n */\nconst toggleBrowse = (root, props) => {\n    const isAllowed = root.query('GET_ALLOW_BROWSE');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.browser) {\n        root.ref.browser = root.appendChildView(\n            root.createChildView(browser, {\n                ...props,\n                onload: items => {\n                    applyFilterChain('ADD_ITEMS', items, {\n                        dispatch: root.dispatch,\n                    }).then(queue => {\n                        // these files don't fit so stop here\n                        if (exceedsMaxFiles(root, queue)) return false;\n\n                        // add items!\n                        root.dispatch('ADD_ITEMS', {\n                            items: queue,\n                            index: -1,\n                            interactionMethod: InteractionMethod.BROWSE,\n                        });\n                    });\n                },\n            }),\n            0\n        );\n    } else if (!enabled && root.ref.browser) {\n        root.removeChildView(root.ref.browser);\n        root.ref.browser = null;\n    }\n};\n\n/**\n * Enable or disable paste functionality\n */\nconst togglePaste = root => {\n    const isAllowed = root.query('GET_ALLOW_PASTE');\n    const isDisabled = root.query('GET_DISABLED');\n    const enabled = isAllowed && !isDisabled;\n    if (enabled && !root.ref.paster) {\n        root.ref.paster = createPaster();\n        root.ref.paster.onload = items => {\n            applyFilterChain('ADD_ITEMS', items, { dispatch: root.dispatch }).then(queue => {\n                // these files don't fit so stop here\n                if (exceedsMaxFiles(root, queue)) return false;\n\n                // add items!\n                root.dispatch('ADD_ITEMS', {\n                    items: queue,\n                    index: -1,\n                    interactionMethod: InteractionMethod.PASTE,\n                });\n            });\n        };\n    } else if (!enabled && root.ref.paster) {\n        root.ref.paster.destroy();\n        root.ref.paster = null;\n    }\n};\n\n/**\n * Route actions\n */\nconst route = createRoute({\n    DID_SET_ALLOW_BROWSE: ({ root, props }) => {\n        toggleBrowse(root, props);\n    },\n    DID_SET_ALLOW_DROP: ({ root }) => {\n        toggleDrop(root);\n    },\n    DID_SET_ALLOW_PASTE: ({ root }) => {\n        togglePaste(root);\n    },\n    DID_SET_DISABLED: ({ root, props }) => {\n        toggleDrop(root);\n        togglePaste(root);\n        toggleBrowse(root, props);\n        const isDisabled = root.query('GET_DISABLED');\n        if (isDisabled) {\n            root.element.dataset.disabled = 'disabled';\n        } else {\n            // delete root.element.dataset.disabled; <= this does not work on iOS 10\n            root.element.removeAttribute('data-disabled');\n        }\n    },\n});\n\nexport const root = createView({\n    name: 'root',\n    read: ({ root }) => {\n        if (root.ref.measure) {\n            root.ref.measureHeight = root.ref.measure.offsetHeight;\n        }\n    },\n    create,\n    write,\n    destroy: ({ root }) => {\n        if (root.ref.paster) {\n            root.ref.paster.destroy();\n        }\n        if (root.ref.hopper) {\n            root.ref.hopper.destroy();\n        }\n        root.element.removeEventListener('touchmove', prevent);\n        root.element.removeEventListener('gesturestart', prevent);\n    },\n    mixins: {\n        styles: ['height'],\n    },\n});\n"
  },
  {
    "path": "src/js/createApp.js",
    "content": "import { isNode } from './utils/isNode';\nimport { createAppObject } from './createAppObject';\nimport { createAppAtElement } from './createAppAtElement';\n\n// if an element is passed, we create the instance at that element, if not, we just create an up object\nexport const createApp = (...args) =>\n  isNode(args[0]) ? createAppAtElement(...args) : createAppObject(...args);\n"
  },
  {
    "path": "src/js/createAppAPI.js",
    "content": "import { copyObjectPropertiesToObject } from './utils/copyObjectPropertiesToObject';\nconst PRIVATE_METHODS = ['fire', '_read', '_write'];\n\nexport const createAppAPI = app => {\n  const api = {};\n\n  copyObjectPropertiesToObject(app, api, PRIVATE_METHODS);\n\n  return api;\n};\n"
  },
  {
    "path": "src/js/createAppAtElement.js",
    "content": "import { getAttributesAsObject } from './utils/getAttributesAsObject';\nimport { createAppObject } from './createAppObject';\nimport { applyFilters } from './filter';\nimport { isObject } from './utils/isObject';\n\nexport const createAppAtElement = (element, options = {}) => {\n\n    // how attributes of the input element are mapped to the options for the plugin\n    const attributeMapping = {\n        // translate to other name\n        '^class$': 'className',\n        '^multiple$': 'allowMultiple',\n        '^capture$': 'captureMethod',\n        '^webkitdirectory$': 'allowDirectoriesOnly',\n\n        // group under single property\n        '^server': {\n            group: 'server',\n            mapping: {\n                '^process': {\n                    group: 'process'\n                },\n                '^revert': {\n                    group: 'revert'\n                },\n                '^fetch': {\n                    group: 'fetch'\n                },\n                '^restore': {\n                    group: 'restore'\n                },\n                '^load': {\n                    group: 'load'\n                }\n            }\n        },\n\n        // don't include in object\n        '^type$': false,\n        '^files$': false\n    };\n\n    // add additional option translators\n    applyFilters('SET_ATTRIBUTE_TO_OPTION_MAP', attributeMapping);\n\n    // create final options object by setting options object and then overriding options supplied on element\n    const mergedOptions = {\n        ...options\n    };\n    \n    const attributeOptions = getAttributesAsObject(\n        element.nodeName === 'FIELDSET'\n            ? element.querySelector('input[type=file]')\n            : element,\n        attributeMapping\n    );\n    \n    // merge with options object\n    Object.keys(attributeOptions).forEach(key => {\n        if (isObject(attributeOptions[key])) {\n            if (!isObject(mergedOptions[key])) {\n                mergedOptions[key] = {};\n            }\n            Object.assign(mergedOptions[key], attributeOptions[key]);\n        }\n        else {\n            mergedOptions[key] = attributeOptions[key];\n        }\n    });\n    \n    // if parent is a fieldset, get files from parent by selecting all input fields that are not file upload fields\n    // these will then be automatically set to the initial files\n    mergedOptions.files = (options.files || []).concat(\n        Array.from(element.querySelectorAll('input:not([type=file])')).map(input => ({\n            source: input.value,\n            options: {\n                type: input.dataset.type\n            }\n        }))\n    );\n\n    // build plugin\n    const app = createAppObject(mergedOptions);\n\n    // add already selected files\n    if (element.files) {\n        Array.from(element.files).forEach(file => {\n            app.addFile(file);\n        });\n    }\n\n    // replace the target element\n    app.replaceElement(element);\n\n    // expose\n    return app;\n};\n"
  },
  {
    "path": "src/js/createAppObject.js",
    "content": "import { createApp } from './app/index';\nimport { getOptions } from './app/options';\nimport { forin } from './utils/forin';\n\nexport const createAppObject = (customOptions = {}) => {\n    // default options\n    const defaultOptions = {};\n    forin(getOptions(), (key, value) => {\n        defaultOptions[key] = value[0];\n    });\n\n    // set app options\n    const app = createApp({\n        // default options\n        ...defaultOptions,\n\n        // custom options\n        ...customOptions\n    });\n\n    // return the plugin instance\n    return app;\n};\n"
  },
  {
    "path": "src/js/createAppPlugin.js",
    "content": "import { Type } from './app/enum/Type';\nimport { addFilter } from './filter';\nimport { applyFilterChain } from './filter';\nimport { forin } from './utils/forin';\nimport { replaceInString } from './utils/replaceInString';\nimport { toNaturalFileSize } from './utils/toNaturalFileSize';\nimport { isString } from './utils/isString';\nimport { guesstimateMimeType } from './utils/guesstimateMimeType';\nimport { getExtensionFromFilename } from './utils/getExtensionFromFilename';\nimport { getFileFromBlob } from './utils/getFileFromBlob';\nimport { getFilenameFromURL } from './utils/getFilenameFromURL';\nimport { getFilenameWithoutExtension } from './utils/getFilenameWithoutExtension';\nimport { createRoute } from './app/frame/createRoute';\nimport { createWorker } from './utils/createWorker';\nimport { createView } from './app/frame/createView';\nimport { loadImage } from './utils/loadImage';\nimport { copyFile } from './utils/copyFile';\nimport { renameFile } from './utils/renameFile';\nimport { extendDefaultOptions } from './app/options';\nimport { fileActionButton } from './app/view/fileActionButton';\nimport { isFile } from './utils/isFile';\nimport { createBlob } from './utils/createBlob';\nimport { text } from './utils/text';\nimport { getNumericAspectRatioFromString } from './utils/getNumericAspectRatioFromString';\nimport { createItemAPI } from './app/utils/createItemAPI';\n\n// already registered plugins (can't register twice)\nconst registeredPlugins = [];\n\n// pass utils to plugin\nexport const createAppPlugin = plugin => {\n\n    // already registered\n    if (registeredPlugins.includes(plugin)) {\n        return;\n    }\n\n    // remember this plugin\n    registeredPlugins.push(plugin);\n\n    // setup!\n    const pluginOutline = plugin({\n        addFilter,\n        utils: {\n            Type,\n            forin,\n            isString,\n            isFile,\n            toNaturalFileSize,\n            replaceInString,\n            getExtensionFromFilename,\n            getFilenameWithoutExtension,\n            guesstimateMimeType,\n            getFileFromBlob,\n            getFilenameFromURL,\n            createRoute,\n            createWorker,\n            createView,\n            createItemAPI,\n            loadImage,\n            copyFile,\n            renameFile,\n            createBlob,\n            applyFilterChain,\n            text,\n            getNumericAspectRatioFromString\n        },\n        views: {\n            fileActionButton\n        }\n    });\n\n    // add plugin options to default options\n    extendDefaultOptions(pluginOutline.options);\n};\n"
  },
  {
    "path": "src/js/filter.js",
    "content": "// all registered filters\nconst filters = [];\n\n// loops over matching filters and passes options to each filter, returning the mapped results\nexport const applyFilterChain = (key, value, utils) =>\n    new Promise((resolve, reject) => {\n        // find matching filters for this key\n        const matchingFilters = filters\n            .filter(f => f.key === key)\n            .map(f => f.cb);\n\n        // resolve now\n        if (matchingFilters.length === 0) {\n            resolve(value);\n            return;\n        }\n\n        // first filter to kick things of\n        const initialFilter = matchingFilters.shift();\n\n        // chain filters\n        matchingFilters\n            .reduce(\n                // loop over promises passing value to next promise\n                (current, next) => current.then(value => next(value, utils)),\n\n                // call initial filter, will return a promise\n                initialFilter(value, utils)\n\n                // all executed\n            )\n            .then(value => resolve(value))\n            .catch(error => reject(error));\n    });\n\nexport const applyFilters = (key, value, utils) =>\n    filters.filter(f => f.key === key).map(f => f.cb(value, utils));\n\n// adds a new filter to the list\nexport const addFilter = (key, cb) => filters.push({ key, cb });\n"
  },
  {
    "path": "src/js/index.js",
    "content": "import { createApp } from './createApp';\nimport { createPainter } from './app/frame/index';\nimport { createAppAPI } from './createAppAPI';\nimport { createAppPlugin } from './createAppPlugin';\nimport { getOptions as getDefaultOptions, setOptions as setDefaultOptions } from './app/options';\nimport { isObject } from './utils/isObject';\nimport { forin } from './utils/forin';\nimport { ItemStatus } from './app/enum/ItemStatus';\nimport { Status as StatusEnum } from './app/enum/Status';\nimport { FileOrigin as FileOriginEnum } from './app/enum/FileOrigin';\nimport { isBrowser } from './utils/isBrowser';\n\n// feature detection used by supported() method\nconst isOperaMini = () => Object.prototype.toString.call(window.operamini) === '[object OperaMini]';\nconst hasPromises = () => 'Promise' in window;\nconst hasBlobSlice = () => 'slice' in Blob.prototype;\nconst hasCreateObjectURL = () => 'URL' in window && 'createObjectURL' in window.URL;\nconst hasVisibility = () => 'visibilityState' in document;\nconst hasTiming = () => 'performance' in window; // iOS 8.x\nconst hasCSSSupports = () => 'supports' in (window.CSS || {}); // use to detect Safari 9+\nconst isIE11 = () => /MSIE|Trident/.test(window.navigator.userAgent);\n\nexport const supported = (() => {\n\n    // Runs immediately and then remembers result for subsequent calls\n    const isSupported = \n\n        // Has to be a browser\n        isBrowser() &&\n\n        // Can't run on Opera Mini due to lack of everything\n        !isOperaMini() &&\n\n        // Require these APIs to feature detect a modern browser\n        hasVisibility() &&\n        hasPromises() &&\n        hasBlobSlice() &&\n        hasCreateObjectURL() &&\n        hasTiming() &&\n\n        // doesn't need CSSSupports but is a good way to detect Safari 9+ (we do want to support IE11 though)\n        (hasCSSSupports() || isIE11());\n\n    return () => isSupported;\n})();\n\n\n/**\n * Plugin internal state (over all instances)\n */\nconst state = {\n    // active app instances, used to redraw the apps and to find the later\n    apps: []\n};\n\n// plugin name\nconst name = 'filepond';\n\n/**\n * Public Plugin methods\n */\nconst fn = () => {};\nexport let Status = {};\nexport let FileStatus = {};\nexport let FileOrigin = {};\nexport let OptionTypes = {};\nexport let create = fn;\nexport let destroy = fn;\nexport let parse = fn;\nexport let find = fn;\nexport let registerPlugin = fn;\nexport let getOptions = fn;\nexport let setOptions = fn;\n\n// if not supported, no API\nif (supported()) {\n\n    // start painter and fire load event\n    createPainter(\n        () => {\n            state.apps.forEach(app => app._read());\n        },\n        (ts) => {\n            state.apps.forEach(app => app._write(ts));\n        }\n    );\n\n    // fire loaded event so we know when FilePond is available\n    const dispatch = () => {\n        // let others know we have area ready\n        document.dispatchEvent(\n            new CustomEvent('FilePond:loaded', {\n                detail: {\n                    supported,\n                    create,\n                    destroy,\n                    parse,\n                    find,\n                    registerPlugin,\n                    setOptions\n                }\n            })\n        );\n\n        // clean up event\n        document.removeEventListener('DOMContentLoaded', dispatch);\n    };\n\n    if (document.readyState !== 'loading') {\n        // move to back of execution queue, FilePond should have been exported by then\n        setTimeout(() => dispatch(), 0);\n    } else {\n        document.addEventListener('DOMContentLoaded', dispatch);\n    }\n\n    // updates the OptionTypes object based on the current options\n    const updateOptionTypes = () => forin(getDefaultOptions(), (key, value) => {\n        OptionTypes[key] = value[1];\n    });\n\n    Status = { ...StatusEnum };\n    FileOrigin = { ...FileOriginEnum };\n    FileStatus = { ...ItemStatus };\n\n    OptionTypes = {};\n    updateOptionTypes();\n\n\n    // create method, creates apps and adds them to the app array\n    create = (...args) => {\n        const app = createApp(...args);\n        app.on('destroy', destroy);\n        state.apps.push(app);\n        return createAppAPI(app);\n    };\n\n    // destroys apps and removes them from the app array\n    destroy = hook => {\n        // returns true if the app was destroyed successfully\n        const indexToRemove = state.apps.findIndex(app => app.isAttachedTo(hook));\n        if (indexToRemove >= 0) {\n            \n            // remove from apps\n            const app = state.apps.splice(indexToRemove, 1)[0];\n\n            // restore original dom element\n            app.restoreElement();\n\n            return true;\n        }\n\n        return false;\n    };\n\n    // parses the given context for plugins (does not include the context element itself)\n    parse = context => {\n        // get all possible hooks\n        const matchedHooks = Array.from(context.querySelectorAll(`.${name}`));\n\n        // filter out already active hooks\n        const newHooks = matchedHooks.filter(\n            newHook => !state.apps.find(app => app.isAttachedTo(newHook))\n        );\n\n        // create new instance for each hook\n        return newHooks.map(hook => create(hook));\n    };\n\n    // returns an app based on the given element hook\n    find = hook => {\n        const app = state.apps.find(app => app.isAttachedTo(hook));\n        if (!app) {\n            return null;\n        }\n        return createAppAPI(app);\n    };\n\n    // adds a plugin extension\n    registerPlugin = (...plugins) => {\n\n        // register plugins\n        plugins.forEach(createAppPlugin);\n\n        // update OptionTypes, each plugin might have extended the default options\n        updateOptionTypes();\n    }\n\n    getOptions = () => {\n        const opts = {};\n        forin(getDefaultOptions(), (key, value) => {\n            opts[key] = value[0];\n        });\n        return opts;\n    }\n\n    setOptions = opts => {\n\n        if (isObject(opts)) {\n            // update existing plugins\n            state.apps.forEach(app => {\n                app.setOptions(opts);\n            });\n\n            // override defaults\n            setDefaultOptions(opts);\n        }\n\n        // return new options\n        return getOptions();\n    };\n}\n"
  },
  {
    "path": "src/js/utils/arrayInsert.js",
    "content": "export const arrayInsert = (arr, index, item) => arr.splice(index, 0, item);\n"
  },
  {
    "path": "src/js/utils/arrayRemove.js",
    "content": "export const arrayRemove = (arr, index) => arr.splice(index, 1);\n"
  },
  {
    "path": "src/js/utils/arrayReverse.js",
    "content": "export const arrayReverse = arr => arr.reverse();\n"
  },
  {
    "path": "src/js/utils/attr.js",
    "content": "export const attr = (node, name, value = null) => {\n    if (value === null) {\n        return node.getAttribute(name) || node.hasAttribute(name);\n    }\n    node.setAttribute(name, value);\n};\n"
  },
  {
    "path": "src/js/utils/attrToggle.js",
    "content": "import { attr } from './attr';\nexport const attrToggle = (element, name, state, enabledValue = '') => {\n    if (state) {\n        attr(element, name, enabledValue);\n    } else {\n        element.removeAttribute(name);\n    }\n};\n"
  },
  {
    "path": "src/js/utils/canUpdateFileInput.js",
    "content": "let res = null;\nexport const canUpdateFileInput = () => {\n    if (res === null) {\n        try {\n            const dataTransfer = new DataTransfer();\n            dataTransfer.items.add(new File(['hello world'], 'This_Works.txt'));\n            const el = document.createElement('input');\n            el.setAttribute('type', 'file');\n            el.files = dataTransfer.files;\n            res = el.files.length === 1;\n        } catch (err) {\n            res = false;\n        }\n    }\n    return res;\n};\n"
  },
  {
    "path": "src/js/utils/capitalizeFirstLetter.js",
    "content": "export const capitalizeFirstLetter = string =>\n    string.charAt(0).toUpperCase() + string.slice(1);\n"
  },
  {
    "path": "src/js/utils/composeObject.js",
    "content": "export const composeObject = (...objects) => {\n    return Object.assign({}, ...objects);\n};\n"
  },
  {
    "path": "src/js/utils/copyFile.js",
    "content": "import { renameFile } from './renameFile';\nexport const copyFile = file => renameFile(file, file.name);\n"
  },
  {
    "path": "src/js/utils/copyObjectPropertiesToObject.js",
    "content": "export const copyObjectPropertiesToObject = (src, target, excluded) => {\n    Object.getOwnPropertyNames(src)\n        .filter(property => !excluded.includes(property))\n        .forEach(key =>\n            Object.defineProperty(\n                target,\n                key,\n                Object.getOwnPropertyDescriptor(src, key)\n            )\n        );\n};\n"
  },
  {
    "path": "src/js/utils/createBlob.js",
    "content": "import { getBlobBuilder } from './getBlobBuilder';\n\nexport const createBlob = (arrayBuffer, mimeType) => {\n    const BB = getBlobBuilder();\n\n    if (BB) {\n        const bb = new BB();\n        bb.append(arrayBuffer);\n        return bb.getBlob(mimeType);\n    }\n\n    return new Blob([arrayBuffer], {\n        type: mimeType\n    });\n};\n"
  },
  {
    "path": "src/js/utils/createDefaultResponse.js",
    "content": "import { createResponse } from './createResponse';\n\nexport const createTimeoutResponse = (cb) => (xhr) => {\n    cb(\n        createResponse(\n            'error',\n            0,\n            'Timeout',\n            xhr.getAllResponseHeaders()\n        )\n    )\n}"
  },
  {
    "path": "src/js/utils/createElement.js",
    "content": "export const createElement = tagName => {\n    return document.createElement(tagName);\n};\n"
  },
  {
    "path": "src/js/utils/createObject.js",
    "content": "import { defineProperty } from './defineProperty';\nimport { forin } from './forin';\n\nexport const createObject = definition => {\n    const obj = {};\n    forin(definition, property => {\n        defineProperty(obj, property, definition[property]);\n    });\n    return obj;\n};\n"
  },
  {
    "path": "src/js/utils/createResponse.js",
    "content": "export const createResponse = (type, code, body, headers) => ({\n    type,\n    code,\n    body,\n    headers\n});"
  },
  {
    "path": "src/js/utils/createWorker.js",
    "content": "import { getUniqueId } from './getUniqueId';\n\nexport const createWorker = fn => {\n    const workerBlob = new Blob(['(', fn.toString(), ')()'], {\n        type: 'application/javascript'\n    });\n    const workerURL = URL.createObjectURL(workerBlob);\n    const worker = new Worker(workerURL);\n\n    return {\n        transfer: (message, cb) => {},\n        post: (message, cb, transferList) => {\n            const id = getUniqueId();\n\n            worker.onmessage = e => {\n                if (e.data.id === id) {\n                    cb(e.data.message);\n                }\n            };\n\n            worker.postMessage(\n                {\n                    id,\n                    message\n                },\n                transferList\n            );\n        },\n        terminate: () => {\n            worker.terminate();\n            URL.revokeObjectURL(workerURL);\n        }\n    };\n};\n"
  },
  {
    "path": "src/js/utils/debounce.js",
    "content": "export const debounce = (func, interval = 16, immidiateOnly = true) => {\n    let last = Date.now();\n    let timeout = null;\n\n    return (...args) => {\n        clearTimeout(timeout);\n\n        const dist = Date.now() - last;\n\n        const fn = () => {\n            last = Date.now();\n            func(...args);\n        };\n\n        if (dist < interval) {\n            // we need to delay by the difference between interval and dist\n            // for example: if distance is 10 ms and interval is 16 ms,\n            // we need to wait an additional 6ms before calling the function)\n            if (!immidiateOnly) {\n                timeout = setTimeout(fn, interval - dist);\n            }\n        } else {\n            // go!\n            fn();\n        }\n    };\n};\n"
  },
  {
    "path": "src/js/utils/deepCloneObject.js",
    "content": "import { isObject } from './isObject';\nimport { isArray } from './isArray';\n\nexport const deepCloneObject = (src) => {\n    if (!isObject(src)) return src;\n    const target = isArray(src) ? [] : {};\n    for (const key in src) {\n        if (!src.hasOwnProperty(key)) continue;\n        const v = src[key];\n        target[key] = v && isObject(v) ? deepCloneObject(v) : v;\n    }\n    return target;\n}"
  },
  {
    "path": "src/js/utils/defineProperty.js",
    "content": "export const defineProperty = (obj, property, definition) => {\n    if (typeof definition === 'function') {\n        obj[property] = definition;\n        return;\n    }\n    Object.defineProperty(obj, property, { ...definition });\n};\n"
  },
  {
    "path": "src/js/utils/describeArc.js",
    "content": "import { polarToCartesian } from './polarToCartesian';\n\nexport const describeArc = (x, y, radius, startAngle, endAngle, arcSweep) => {\n    const start = polarToCartesian(x, y, radius, endAngle);\n    const end = polarToCartesian(x, y, radius, startAngle);\n    return [\n        'M',\n        start.x,\n        start.y,\n        'A',\n        radius,\n        radius,\n        0,\n        arcSweep,\n        0,\n        end.x,\n        end.y\n    ].join(' ');\n};\n"
  },
  {
    "path": "src/js/utils/forEachDelayed.js",
    "content": "export const forEachDelayed = (items, cb, delay = 75) =>\n    items.map(\n        (item, index) =>\n            new Promise((resolve, reject) => {\n                setTimeout(() => {\n                    cb(item);\n                    resolve();\n                }, delay * index);\n            })\n    );\n"
  },
  {
    "path": "src/js/utils/forin.js",
    "content": "export const forin = (obj, cb) => {\n    for (const key in obj) {\n        if (!obj.hasOwnProperty(key)) {\n            continue;\n        }\n\n        cb(key, obj[key]);\n    }\n};\n"
  },
  {
    "path": "src/js/utils/formatFilename.js",
    "content": "export const formatFilename = name => name;\n"
  },
  {
    "path": "src/js/utils/fromCamels.js",
    "content": "export const fromCamels = (string, separator = '-') =>\n    string\n        .split(/(?=[A-Z])/)\n        .map(part => part.toLowerCase())\n        .join(separator);\n"
  },
  {
    "path": "src/js/utils/getAttributesAsObject.js",
    "content": "import { toCamels } from './toCamels';\nimport { attr } from './attr';\nimport { forin } from './forin';\nimport { lowerCaseFirstLetter } from './lowerCaseFirstLetter';\nimport { isString } from './isString';\nimport { isObject } from './isObject';\n\nconst attributeNameToPropertyName = attributeName =>\n    toCamels(attributeName.replace(/^data-/, ''));\n\nconst mapObject = (object, propertyMap) => {\n    // remove unwanted\n    forin(propertyMap, (selector, mapping) => {\n        forin(object, (property, value) => {\n            // create regexp shortcut\n            const selectorRegExp = new RegExp(selector);\n\n            // tests if\n            const matches = selectorRegExp.test(property);\n\n            // no match, skip\n            if (!matches) {\n                return;\n            }\n\n            // if there's a mapping, the original property is always removed\n            delete object[property];\n\n            // should only remove, we done!\n            if (mapping === false) {\n                return;\n            }\n\n            // move value to new property\n            if (isString(mapping)) {\n                object[mapping] = value\n                return;\n            }\n\n            // move to group\n            const group = mapping.group;\n            if (isObject(mapping) && !object[group]) {\n                object[group] = {};\n            }\n            \n            object[group][\n                lowerCaseFirstLetter(property.replace(selectorRegExp, ''))\n            ] = value;\n        });\n\n        // do submapping\n        if (mapping.mapping) {\n            mapObject(object[mapping.group], mapping.mapping);\n        }\n    });\n};\n\nexport const getAttributesAsObject = (node, attributeMapping = {}) => {\n    // turn attributes into object\n    const attributes = [];\n    forin(node.attributes, index => {\n        attributes.push(node.attributes[index]);\n    });\n    \n    const output = attributes\n        .filter(attribute => attribute.name)\n        .reduce((obj, attribute) => {\n        \n        const value = attr(\n            node,\n            attribute.name\n        );\n\n        obj[attributeNameToPropertyName(attribute.name)] = value === attribute.name ? true : value;\n        return obj;\n    }, {});\n\n    // do mapping of object properties\n    mapObject(output, attributeMapping);\n\n    return output;\n};"
  },
  {
    "path": "src/js/utils/getBase64DataFromBase64DataURI.js",
    "content": "export const getBase64DataFromBase64DataURI = dataURI => {\n    // get data part of string (remove data:image/jpeg...,)\n    const data = dataURI.split(',')[1];\n\n    // remove any whitespace as that causes InvalidCharacterError in IE\n    return data.replace(/\\s/g, '');\n};\n"
  },
  {
    "path": "src/js/utils/getBlobBuilder.js",
    "content": "export const getBlobBuilder = () => {\n    return (window.BlobBuilder =\n        window.BlobBuilder ||\n        window.WebKitBlobBuilder ||\n        window.MozBlobBuilder ||\n        window.MSBlobBuilder);\n};\n"
  },
  {
    "path": "src/js/utils/getBlobFromBase64DataURI.js",
    "content": "import { getBlobFromByteStringWithMimeType } from './getBlobFromByteStringWithMimeType';\nimport { getMimeTypeFromBase64DataURI } from './getMimeTypeFromBase64DataURI';\nimport { getByteStringFromBase64DataURI } from './getByteStringFromBase64DataURI';\n\nexport const getBlobFromBase64DataURI = dataURI => {\n    const mimeType = getMimeTypeFromBase64DataURI(dataURI);\n    const byteString = getByteStringFromBase64DataURI(dataURI);\n\n    return getBlobFromByteStringWithMimeType(byteString, mimeType);\n};\n"
  },
  {
    "path": "src/js/utils/getBlobFromByteStringWithMimeType.js",
    "content": "import { createBlob } from './createBlob';\n\nexport const getBlobFromByteStringWithMimeType = (byteString, mimeType) => {\n    const ab = new ArrayBuffer(byteString.length);\n    const ia = new Uint8Array(ab);\n\n    for (let i = 0; i < byteString.length; i++) {\n        ia[i] = byteString.charCodeAt(i);\n    }\n\n    return createBlob(ab, mimeType);\n};\n"
  },
  {
    "path": "src/js/utils/getByteStringFromBase64DataURI.js",
    "content": "import { getBase64DataFromBase64DataURI } from './getBase64DataFromBase64DataURI';\n\nexport const getByteStringFromBase64DataURI = dataURI => {\n    return atob(getBase64DataFromBase64DataURI(dataURI));\n};\n"
  },
  {
    "path": "src/js/utils/getDateString.js",
    "content": "import { leftPad } from './leftPad';\nexport const getDateString = (date = new Date()) =>\n    `${date.getFullYear()}-${leftPad(date.getMonth() + 1, '00')}-${leftPad(\n        date.getDate(),\n        '00'\n    )}_${leftPad(date.getHours(), '00')}-${leftPad(\n        date.getMinutes(),\n        '00'\n    )}-${leftPad(date.getSeconds(), '00')}`;\n"
  },
  {
    "path": "src/js/utils/getDecimalSeparator.js",
    "content": "import { getNonNumeric } from './getNonNumeric';\n\nexport const getDecimalSeparator = () =>\n    getNonNumeric((1.1).toLocaleString())[0];\n"
  },
  {
    "path": "src/js/utils/getDomainFromURL.js",
    "content": "export const getDomainFromURL = url => {\n    if (url.indexOf('//') === 0) {\n        url = location.protocol + url;\n    }\n    return url\n        .toLowerCase()\n        .replace('blob:', '')\n        .replace(/([a-z])?:\\/\\//, '$1')\n        .split('/')[0];\n};\n"
  },
  {
    "path": "src/js/utils/getExtensionFromFilename.js",
    "content": "export const getExtensionFromFilename = name => name.split('.').pop();\n"
  },
  {
    "path": "src/js/utils/getFileFromBase64DataURI.js",
    "content": "import { getFileFromBlob } from './getFileFromBlob';\nimport { getBlobFromBase64DataURI } from './getBlobFromBase64DataURI';\n\nexport const getFileFromBase64DataURI = (dataURI, filename, extension) => {\n    return getFileFromBlob(\n        getBlobFromBase64DataURI(dataURI),\n        filename,\n        null,\n        extension\n    );\n};\n"
  },
  {
    "path": "src/js/utils/getFileFromBlob.js",
    "content": "import { getExtensionFromFilename } from './getExtensionFromFilename';\nimport { guesstimateExtension } from './guesstimateExtension';\nimport { isString } from './isString';\nimport { getDateString } from './getDateString';\n\nexport const getFileFromBlob = (\n    blob,\n    filename,\n    type = null,\n    extension = null\n) => {\n    const file =\n        typeof type === 'string'\n            ? blob.slice(0, blob.size, type)\n            : blob.slice(0, blob.size, blob.type);\n    file.lastModifiedDate = new Date();\n    \n    // copy relative path\n    if (blob._relativePath) file._relativePath = blob._relativePath;\n\n    // if blob has name property, use as filename if no filename supplied\n    if (!isString(filename)) {\n        filename = getDateString();\n    }\n\n    // if filename supplied but no extension and filename has extension\n    if (filename && extension === null && getExtensionFromFilename(filename)) {\n        file.name = filename;\n    }\n    else {\n        extension = extension || guesstimateExtension(file.type);\n        file.name = filename + (extension ? '.' + extension : '');\n    }\n\n    return file;\n};\n"
  },
  {
    "path": "src/js/utils/getFileInfoFromHeaders.js",
    "content": "export const getFileNameFromHeader = header => {\n\n    // test if is content disposition header, if not exit\n    if (!/^content-disposition:/i.test(header)) return null;\n\n    // get filename parts\n    const matches = header.split(/filename=|filename\\*=.+''/)\n        .splice(1)\n        .map(name => name.trim().replace(/^[\"']|[;\"']{0,2}$/g, ''))\n        .filter(name => name.length)\n    \n    return matches.length ? decodeURI(matches[matches.length-1]) : null;\n}\n\nconst getFileSizeFromHeader = header => {\n    if (/content-length:/i.test(header)) {\n        const size = header.match(/[0-9]+/)[0];\n        return size ? parseInt(size, 10) : null;\n    }\n    return null;\n}\n\nconst getTranfserIdFromHeader = header => {\n    if (/x-content-transfer-id:/i.test(header)) {\n        const id = (header.split(':')[1] || '').trim();\n        return id || null;\n    }\n    return null;\n}\n\nexport const getFileInfoFromHeaders = headers => {\n    \n    const info = {\n        source: null,\n        name: null,\n        size: null\n    };\n\n    const rows = headers.split('\\n');\n    for (let header of rows) {\n\n        const name = getFileNameFromHeader(header);\n        if (name) {\n            info.name = name;\n            continue;\n        }\n\n        const size = getFileSizeFromHeader(header);\n        if (size) {\n            info.size = size;\n            continue;\n        }\n\n        const source = getTranfserIdFromHeader(header);\n        if (source) {\n            info.source = source;\n            continue;\n        }\n\n    }\n    \n    return info;\n}"
  },
  {
    "path": "src/js/utils/getFilenameFromURL.js",
    "content": "export const getFilenameFromURL = url =>\n    `${url}`\n        .split('/')\n        .pop()\n        .split('?')\n        .shift();\n"
  },
  {
    "path": "src/js/utils/getFilenameWithoutExtension.js",
    "content": "export const getFilenameWithoutExtension = name =>\n    name.substring(0, name.lastIndexOf('.')) || name;\n"
  },
  {
    "path": "src/js/utils/getMimeTypeFromBase64DataURI.js",
    "content": "export const getMimeTypeFromBase64DataURI = dataURI => {\n    return (/^data:(.+);/.exec(dataURI) || [])[1] || null;\n};\n"
  },
  {
    "path": "src/js/utils/getNonNumeric.js",
    "content": "export const getNonNumeric = str => /[^0-9]+/.exec(str);\n"
  },
  {
    "path": "src/js/utils/getNumericAspectRatioFromString.js",
    "content": "import { isEmpty } from './isEmpty';\n\nexport const getNumericAspectRatioFromString = aspectRatio => {\n    if (isEmpty(aspectRatio)) {\n        return aspectRatio;\n    }\n    if(/:/.test(aspectRatio)) {\n        const parts = aspectRatio.split(':');\n        return parts[1] / parts[0];\n    }\n    return parseFloat(aspectRatio);\n};"
  },
  {
    "path": "src/js/utils/getParameters.js",
    "content": "export const getParameters = (args, filters) => {\n    return Object.keys(filters).reduce((acc, name) => {\n        acc[name] = args.find(arg => typeof arg === filters[name]);\n        return acc;\n    }, {});\n};\n"
  },
  {
    "path": "src/js/utils/getRandomNumber.js",
    "content": "export const getRandomNumber = (min = 0, max = 1) =>\n    min + Math.random() * (max - min);\n"
  },
  {
    "path": "src/js/utils/getRootNode.js",
    "content": "export const getRootNode = element =>\n    'getRootNode' in element ? element.getRootNode() : document;\n"
  },
  {
    "path": "src/js/utils/getThousandsSeparator.js",
    "content": "import { getNonNumeric } from './getNonNumeric';\nimport { getDecimalSeparator } from './getDecimalSeparator';\n\nexport const getThousandsSeparator = () => {\n    // Added for browsers that do not return the thousands separator (happend on native browser Android 4.4.4)\n    // We check against the normal toString output and if they're the same return a comma when decimal separator is a dot\n    const decimalSeparator = getDecimalSeparator();\n    const thousandsStringWithSeparator = (1000.0).toLocaleString();\n    const thousandsStringWithoutSeparator = (1000.0).toString();\n    if (thousandsStringWithSeparator !== thousandsStringWithoutSeparator) {\n        return getNonNumeric(thousandsStringWithSeparator)[0];\n    }\n    return decimalSeparator === '.' ? ',' : '.';\n};\n"
  },
  {
    "path": "src/js/utils/getUniqueId.js",
    "content": "export const getUniqueId = () =>\n    Math.random()\n        .toString(36)\n        .substring(2, 11);\n"
  },
  {
    "path": "src/js/utils/guesstimateExtension.js",
    "content": "export const guesstimateExtension = type => {\n    // if no extension supplied, exit here\n    if (typeof type !== 'string') {\n        return '';\n    }\n\n    // get subtype\n    const subtype = type.split('/').pop();\n\n    // is svg subtype\n    if (/svg/.test(subtype)) {\n        return 'svg';\n    }\n\n    if (/zip|compressed/.test(subtype)) {\n        return 'zip';\n    }\n\n    if (/plain/.test(subtype)) {\n        return 'txt';\n    }\n\n    if (/msword/.test(subtype)) {\n        return 'doc';\n    }\n\n    // if is valid subtype\n    if (/[a-z]+/.test(subtype)) {\n        // always use jpg extension\n        if (subtype === 'jpeg') {\n            return 'jpg';\n        }\n\n        // return subtype\n        return subtype;\n    }\n\n    return '';\n};\n"
  },
  {
    "path": "src/js/utils/guesstimateMimeType.js",
    "content": "const images = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff'];\nconst text = ['css', 'csv', 'html', 'txt'];\nconst map = {\n    zip: 'zip|compressed',\n    epub: 'application/epub+zip'\n};\n\nexport const guesstimateMimeType = (extension = '') => {\n    extension = extension.toLowerCase();\n    if (images.includes(extension)) {\n        return (\n            'image/' +\n            (extension === 'jpg'\n                ? 'jpeg'\n                : extension === 'svg' ? 'svg+xml' : extension)\n        );\n    }\n    if (text.includes(extension)) {\n        return 'text/' + extension;\n    }\n\n    return map[extension] || '';\n};\n"
  },
  {
    "path": "src/js/utils/hasQueryString.js",
    "content": "export const hasQueryString = url => /[?&]/.test(url);\n"
  },
  {
    "path": "src/js/utils/insertAfter.js",
    "content": "export const insertAfter = (newNode, referenceNode) => {\n    return referenceNode.parentNode.insertBefore(\n        newNode,\n        referenceNode.nextSibling\n    );\n};\n"
  },
  {
    "path": "src/js/utils/insertBefore.js",
    "content": "export const insertBefore = (newNode, referenceNode) => referenceNode.parentNode.insertBefore(newNode, referenceNode);\n"
  },
  {
    "path": "src/js/utils/isArray.js",
    "content": "export const isArray = value => Array.isArray(value);\n"
  },
  {
    "path": "src/js/utils/isBase64DataURI.js",
    "content": "export const isBase64DataURI = str =>\n    /^\\s*data:([a-z]+\\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\\-._~:@\\/?%\\s]*)\\s*$/i.test(\n        str\n    );\n"
  },
  {
    "path": "src/js/utils/isBoolean.js",
    "content": "export const isBoolean = value => typeof value === 'boolean';\n"
  },
  {
    "path": "src/js/utils/isBrowser.js",
    "content": "const IS_BROWSER = (() => typeof window !== 'undefined' && typeof window.document !== 'undefined')();\nexport const isBrowser = () => IS_BROWSER;"
  },
  {
    "path": "src/js/utils/isDefined.js",
    "content": "export const isDefined = value => value != null;\n"
  },
  {
    "path": "src/js/utils/isEmpty.js",
    "content": "export const isEmpty = value => value == null;\n"
  },
  {
    "path": "src/js/utils/isExternalURL.js",
    "content": "import { getDomainFromURL } from './getDomainFromURL';\nexport const isExternalURL = url =>\n    (url.indexOf(':') > -1 || url.indexOf('//') > -1) &&\n    getDomainFromURL(location.href) !== getDomainFromURL(url);\n"
  },
  {
    "path": "src/js/utils/isFile.js",
    "content": "export const isFile = value => !!(value instanceof File || (value instanceof Blob && value.name));\n"
  },
  {
    "path": "src/js/utils/isFunction.js",
    "content": "export const isFunction = value => typeof value === 'function';\n"
  },
  {
    "path": "src/js/utils/isIOS.js",
    "content": "let testResult = null;\nexport const isIOS = () => {\n    if (testResult === null) {\n        testResult = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n    }\n    return testResult;\n}"
  },
  {
    "path": "src/js/utils/isInt.js",
    "content": "import { isNumber } from './isNumber';\nexport const isInt = value =>\n    isNumber(value) && isFinite(value) && Math.floor(value) === value;\n"
  },
  {
    "path": "src/js/utils/isNode.js",
    "content": "export const isNode = value => value instanceof HTMLElement;\n"
  },
  {
    "path": "src/js/utils/isNull.js",
    "content": "export const isNull = value => value === null;\n"
  },
  {
    "path": "src/js/utils/isNumber.js",
    "content": "export const isNumber = value => typeof value === 'number';\n"
  },
  {
    "path": "src/js/utils/isObject.js",
    "content": "export const isObject = value => typeof value === 'object' && value !== null;"
  },
  {
    "path": "src/js/utils/isString.js",
    "content": "export const isString = value => typeof value === 'string';\n"
  },
  {
    "path": "src/js/utils/leftPad.js",
    "content": "export const leftPad = (value, padding = '') =>\n    (padding + value).slice(-padding.length);\n"
  },
  {
    "path": "src/js/utils/limit.js",
    "content": "export const limit = (value, min, max) => Math.max(Math.min(max, value), min);\n"
  },
  {
    "path": "src/js/utils/loadImage.js",
    "content": "export const loadImage = (url) =>\n    new Promise((resolve, reject) => {\n        const img = new Image();\n        img.onload = () => {\n            resolve(img);\n        };\n        img.onerror = e => {\n            reject(e);\n        };\n        img.src = url;\n    });\n"
  },
  {
    "path": "src/js/utils/lowerCaseFirstLetter.js",
    "content": "export const lowerCaseFirstLetter = string =>\n    string.charAt(0).toLowerCase() + string.slice(1);\n"
  },
  {
    "path": "src/js/utils/percentageArc.js",
    "content": "import { describeArc } from './describeArc';\n\nexport const percentageArc = (x, y, radius, from, to) => {\n    let arcSweep = 1;\n    if (to > from && to - from <= 0.5) {\n        arcSweep = 0;\n    }\n    if (from > to && from - to >= 0.5) {\n        arcSweep = 0;\n    }\n    return describeArc(\n        x,\n        y,\n        radius,\n        Math.min(0.9999, from) * 360,\n        Math.min(0.9999, to) * 360,\n        arcSweep\n    );\n};\n"
  },
  {
    "path": "src/js/utils/polarToCartesian.js",
    "content": "export const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {\n    const angleInRadians = (angleInDegrees % 360 - 90) * Math.PI / 180.0;\n    return {\n        x: centerX + radius * Math.cos(angleInRadians),\n        y: centerY + radius * Math.sin(angleInRadians)\n    };\n};\n"
  },
  {
    "path": "src/js/utils/renameFile.js",
    "content": "export const renameFile = (file, name) => {\n    const renamedFile = file.slice(0, file.size, file.type);\n    renamedFile.lastModifiedDate = file.lastModifiedDate;\n    renamedFile.name = name;\n    return renamedFile;\n};\n"
  },
  {
    "path": "src/js/utils/replaceInString.js",
    "content": "/**\n * Replaces placeholders in given string with replacements\n * @param string - \"Foo {bar}\"\"\n * @param replacements - { \"bar\": 10 }\n */\nexport const replaceInString = (string, replacements) =>\n    string.replace(/(?:{([a-zA-Z]+)})/g, (match, group) => replacements[group]);\n"
  },
  {
    "path": "src/js/utils/resetFileInput.js",
    "content": "import { createElement } from './createElement';\n\nexport const resetFileInput = input => {\n    // no value, no need to reset\n    if (!input || input.value === '') {\n        return;\n    }\n\n    try {\n        // for modern browsers\n        input.value = '';\n    } catch (err) {}\n\n    // for IE10\n    if (input.value) {\n        // quickly append input to temp form and reset form\n        const form = createElement('form');\n        const parentNode = input.parentNode;\n        const ref = input.nextSibling;\n        form.appendChild(input);\n        form.reset();\n\n        // re-inject input where it originally was\n        if (ref) {\n            parentNode.insertBefore(input, ref);\n        } else {\n            parentNode.appendChild(input);\n        }\n    }\n};\n"
  },
  {
    "path": "src/js/utils/sendRequest.js",
    "content": "import { isInt } from './isInt';\n\nconst isGet = method => /GET|HEAD/.test(method);\n\nexport const sendRequest = (data, url, options) => {\n    const api = {\n        onheaders: () => {},\n        onprogress: () => {},\n        onload: () => {},\n        ontimeout: () => {},\n        onerror: () => {},\n        onabort: () => {},\n        abort: () => {\n            aborted = true;\n            xhr.abort();\n        }\n    };\n\n    // timeout identifier, only used when timeout is defined\n    let aborted = false;\n    let headersReceived = false;\n\n    // set default options\n    options = {\n        method: 'POST',\n        headers: {},\n        withCredentials: false,\n        ...options\n    };\n\n    // encode url\n    url = encodeURI(url);\n\n    // if method is GET, add any received data to url\n    \n    if (isGet(options.method) && data) {\n        url = `${url}${encodeURIComponent(\n            typeof data === 'string' ? data : JSON.stringify(data)\n        )}`;\n    }\n\n    // create request\n    const xhr = new XMLHttpRequest();\n\n    // progress of load\n    const process = isGet(options.method) ? xhr : xhr.upload;\n    process.onprogress = e => {\n        \n        // no progress event when aborted ( onprogress is called once after abort() )\n        if (aborted) {\n            return;\n        }\n\n        api.onprogress(e.lengthComputable, e.loaded, e.total);\n    };\n\n    // tries to get header info to the app as fast as possible\n    xhr.onreadystatechange = () => {\n        // not interesting in these states ('unsent' and 'openend' as they don't give us any additional info)\n        if (xhr.readyState < 2) {\n            return;\n        }\n\n        // no server response\n        if (xhr.readyState === 4 && xhr.status === 0) {\n            return;\n        }\n\n        if (headersReceived) {\n            return;\n        }\n\n        headersReceived = true;\n\n        // we've probably received some useful data in response headers\n        api.onheaders(xhr);\n    };\n\n    // load successful\n    xhr.onload = () => {\n        \n        // is classified as valid response\n        if (xhr.status >= 200 && xhr.status < 300) {\n            api.onload(xhr);\n        } else {\n            api.onerror(xhr);\n        }\n    };\n\n    // error during load\n    xhr.onerror = () => api.onerror(xhr);\n\n    // request aborted\n    xhr.onabort = () => {\n        aborted = true;\n        api.onabort();\n    };\n\n    // request timeout\n    xhr.ontimeout = () => api.ontimeout(xhr);\n\n    // open up open up!\n    xhr.open(options.method, url, true);\n\n    // set timeout if defined (do it after open so IE11 plays ball)\n    if (isInt(options.timeout)) {\n        xhr.timeout = options.timeout;\n    }\n\n    // add headers\n    Object.keys(options.headers).forEach(key => {\n        const value = unescape(encodeURIComponent(options.headers[key]));\n        xhr.setRequestHeader(key, value);\n    });\n\n    // set type of response\n    if (options.responseType) {\n        xhr.responseType = options.responseType;\n    }\n\n    // set credentials\n    if (options.withCredentials) {\n        xhr.withCredentials = true;\n    }\n\n    // let's send our data\n    xhr.send(data);\n\n    return api;\n};"
  },
  {
    "path": "src/js/utils/setInputFiles.js",
    "content": "export const setInputFiles = (element, files) => {\n    try {\n        // Create a DataTransfer instance and add a newly created file\n        const dataTransfer = new DataTransfer();\n        files.forEach(file => {\n            if (file instanceof File) {\n                dataTransfer.items.add(file);\n            } else {\n                dataTransfer.items.add(\n                    new File([file], file.name, {\n                        type: file.type,\n                    })\n                );\n            }\n        });\n\n        // Assign the DataTransfer files list to the file input\n        element.files = dataTransfer.files;\n    } catch (err) {\n        return false;\n    }\n    return true;\n};\n"
  },
  {
    "path": "src/js/utils/text.js",
    "content": "export const text = (node, value) => {\n    let textNode = node.childNodes[0];\n    if (!textNode) {\n        textNode = document.createTextNode(value);\n        node.appendChild(textNode);\n    } else if (value !== textNode.nodeValue) {\n        textNode.nodeValue = value;\n    }\n};\n"
  },
  {
    "path": "src/js/utils/toArray.js",
    "content": "import { isArray } from './isArray';\nimport { isEmpty } from './isEmpty';\nimport { trim } from './trim';\nimport { toString } from './toString';\n\nexport const toArray = (value, splitter = ',') => {\n    if (isEmpty(value)) {\n        return [];\n    }\n    if (isArray(value)) {\n        return value;\n    }\n    return toString(value)\n        .split(splitter)\n        .map(trim)\n        .filter(str => str.length);\n};\n"
  },
  {
    "path": "src/js/utils/toBoolean.js",
    "content": "import { isBoolean } from './isBoolean';\nexport const toBoolean = value => (isBoolean(value) ? value : value === 'true');\n"
  },
  {
    "path": "src/js/utils/toBytes.js",
    "content": "import { toString } from './toString';\nimport { isInt } from './isInt';\nimport { toInt } from './toInt';\n\nexport const toBytes = (value, base = 1000) => {\n    // is in bytes\n    if (isInt(value)) {\n        return value;\n    }\n\n    // is natural file size\n    let naturalFileSize = toString(value).trim();\n\n    // if is value in megabytes\n    if (/MB$/i.test(naturalFileSize)) {\n        naturalFileSize = naturalFileSize.replace(/MB$i/, '').trim();\n        return toInt(naturalFileSize) * base * base;\n    }\n\n    // if is value in kilobytes\n    if (/KB/i.test(naturalFileSize)) {\n        naturalFileSize = naturalFileSize.replace(/KB$i/, '').trim();\n        return toInt(naturalFileSize) * base;\n    }\n\n    return toInt(naturalFileSize);\n};\n"
  },
  {
    "path": "src/js/utils/toCamels.js",
    "content": "export const toCamels = (string, separator = '-') =>\n    string.replace(new RegExp(`${separator}.`, 'g'), sub =>\n        sub.charAt(1).toUpperCase()\n    );\n"
  },
  {
    "path": "src/js/utils/toFloat.js",
    "content": "import { toNumber } from './toNumber';\nexport const toFloat = value => parseFloat(toNumber(value));\n"
  },
  {
    "path": "src/js/utils/toFunctionReference.js",
    "content": "export const toFunctionReference = string => {\n    let ref = self;\n    let levels = string.split('.');\n    let level = null;\n    while ((level = levels.shift())) {\n        ref = ref[level];\n        if (!ref) {\n            return null;\n        }\n    }\n    return ref;\n};\n"
  },
  {
    "path": "src/js/utils/toInt.js",
    "content": "import { toNumber } from './toNumber';\nexport const toInt = value => parseInt(toNumber(value), 10);\n"
  },
  {
    "path": "src/js/utils/toNaturalFileSize.js",
    "content": "export const toNaturalFileSize = (bytes, decimalSeparator = '.', base = 1000, options = {}) => {\n    const {\n        labelBytes = 'bytes',\n        labelKilobytes = 'KB',\n        labelMegabytes = 'MB',\n        labelGigabytes = 'GB',\n    } = options;\n\n    // no negative byte sizes\n    bytes = Math.round(Math.abs(bytes));\n\n    const KB = base;\n    const MB = base * base;\n    const GB = base * base * base;\n\n    // just bytes\n    if (bytes < KB) {\n        return `${bytes} ${labelBytes}`;\n    }\n\n    // kilobytes\n    if (bytes < MB) {\n        return `${Math.floor(bytes / KB)} ${labelKilobytes}`;\n    }\n\n    // megabytes\n    if (bytes < GB) {\n        return `${removeDecimalsWhenZero(bytes / MB, 1, decimalSeparator)} ${labelMegabytes}`;\n    }\n\n    // gigabytes\n    return `${removeDecimalsWhenZero(bytes / GB, 2, decimalSeparator)} ${labelGigabytes}`;\n};\n\nconst removeDecimalsWhenZero = (value, decimalCount, separator) => {\n    return value\n        .toFixed(decimalCount)\n        .split('.')\n        .filter(part => part !== '0')\n        .join(separator);\n};\n"
  },
  {
    "path": "src/js/utils/toNumber.js",
    "content": "import { isNumber } from './isNumber';\nimport { isString } from './isString';\nimport { toString } from './toString';\nexport const toNumber = value =>\n    isNumber(value)\n        ? value\n        : isString(value) ? toString(value).replace(/[a-z]+/gi, '') : 0;\n"
  },
  {
    "path": "src/js/utils/toPercentage.js",
    "content": "export const toPercentage = value => Math.round(value * 100);\n"
  },
  {
    "path": "src/js/utils/toString.js",
    "content": "export const toString = value => '' + value;\n"
  },
  {
    "path": "src/js/utils/trim.js",
    "content": "export const trim = str => str.trim();\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "// Based on definitions by Zach Posten for React-Filepond <https://github.com/zposten>\n// Updated by FilePond Contributors\n\n/* Disable no-redundant-jsdoc since @default statements are NOT redundant */\n/* tslint:disable:no-redundant-jsdoc */\n\nexport {};\n\nexport enum FileStatus {\n    INIT = 1,\n    IDLE = 2,\n    PROCESSING_QUEUED = 9,\n    PROCESSING = 3,\n    PROCESSING_COMPLETE = 5,\n    PROCESSING_ERROR = 6,\n    PROCESSING_REVERT_ERROR = 10,\n    LOADING = 7,\n    LOAD_ERROR = 8,\n}\n\nexport enum Status {\n    EMPTY = 0,\n    IDLE = 1,\n    ERROR = 2,\n    BUSY = 3,\n    READY = 4,\n}\n\nexport enum FileOrigin {\n    INPUT = 1,\n    LIMBO = 2,\n    LOCAL = 3,\n}\n\n// TODO replace all references to `ActualFileObject` with native `File`\n/**\n * @deprecated Don't use this type explicitly within your code. It'll be replaced with the native `File` type in a future release.\n */\nexport type ActualFileObject = Blob & { readonly lastModified: number; readonly name: string };\n\n/**\n * A custom FilePond File.\n */\nexport class FilePondFile {\n    /** Returns the ID of the file. */\n    id: string;\n    /** Returns the server id of the file. */\n    serverId: string;\n    /** Returns the source of the file. */\n    source: ActualFileObject | string;\n    /** Returns the origin of the file. */\n    origin: FileOrigin;\n    /** Returns the current status of the file. */\n    status: FileStatus;\n    /** Returns the File object. */\n    file: ActualFileObject;\n    /** Returns the file extensions. */\n    fileExtension: string;\n    /** Returns the size of the file. */\n    fileSize: number;\n    /** Returns the type of the file. */\n    fileType: string;\n    /** Returns the full name of the file. */\n    filename: string;\n    /** Returns the name of the file without extension. */\n    filenameWithoutExtension: string;\n\n    /** Aborts loading of this file */\n    abortLoad: () => void;\n    /** Aborts processing of this file */\n    abortProcessing: () => void;\n    /**\n     * Retrieve metadata saved to the file, pass a key to retrieve\n     * a specific part of the metadata (e.g. 'crop' or 'resize').\n     * If no key is passed, the entire metadata object is returned.\n     */\n    getMetadata: (key?: string) => any;\n    /** Add additional metadata to the file */\n    setMetadata: (key: string, value: any, silent?: boolean) => void;\n}\n\n// TODO delete\n/**\n * A custom FilePond File. Don't confuse this with the native `File` type.\n *\n * @deprecated use `FilePondFile` instead. This type will be removed in a future release.\n */\nexport class File extends FilePondFile {}\n\nexport interface ServerUrl {\n    url: string;\n    method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n    withCredentials?: boolean;\n    headers?: { [key: string]: string | boolean | number };\n    timeout?: number;\n\n    /**\n     * Called when server response is received, useful for getting\n     * the unique file id from the server response.\n     */\n    onload?: (response: any) => number | string;\n    /**\n     * Called when server error is received, receives the response\n     * body, useful to select the relevant error data.\n     */\n    onerror?: (responseBody: any) => any;\n    /**\n     * Called with the formdata object right before it is sent,\n     * return extended formdata object to make changes.\n     */\n    ondata?: (data: FormData) => FormData;\n}\n\nexport type ProgressServerConfigFunction = (\n    /**\n     * Flag indicating if the resource has a length that can be calculated.\n     * If not, the totalDataAmount has no significant value.  Setting this to\n     * false switches the FilePond loading indicator to infinite mode.\n     */\n    isLengthComputable: boolean,\n    /** The amount of data currently transferred. */\n    loadedDataAmount: number,\n    /** The total amount of data to be transferred. */\n    totalDataAmount: number\n) => void;\n\nexport interface ProcessServerChunkTransferOptions {\n    chunkTransferId: string;\n    chunkServer: ServerUrl;\n    /**\n     * Chunk uploads enabled\n     */\n    chunkUploads: boolean;\n    /**\n     * Forcing use of chunk uploads even for files smaller than chunk size\n     */\n    chunkForce: boolean;\n    /**\n     * Size of chunks\n     */\n    chunkSize: number;\n    /**\n     * Amount of times to retry upload of a chunk when it fails\n     */\n    chunkRetryDelays: number[];\n}\n\nexport type ProcessServerConfigFunction = (\n    /** The name of the input field. */\n    fieldName: string,\n    /** The actual file object to send. */\n    file: ActualFileObject,\n    metadata: { [key: string]: any },\n    /**\n     * Should call the load method when done and pass the returned server file id.\n     * This server file id is then used later on when reverting or restoring a file\n     * so that your server knows which file to return without exposing that info\n     * to the client.\n     */\n    load: (p: string | { [key: string]: any }) => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void,\n    /**\n     * Should call the progress method to update the progress to 100% before calling load().\n     * Setting computable to false switches the loading indicator to infinite mode.\n     */\n    progress: ProgressServerConfigFunction,\n    /** Let FilePond know the request has been cancelled. */\n    abort: () => void,\n    /**\n     * Let Filepond know and store the current file chunk transfer id so it can track the\n     * progress of the whole file upload\n     */\n    transfer: (transferId: string) => void,\n\n    options: ProcessServerChunkTransferOptions\n) => void;\n\nexport type RevertServerConfigFunction = (\n    /** Server file id of the file to restore. */\n    uniqueFieldId: any,\n    /** Should call the load method when done. */\n    load: () => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void\n) => void;\n\nexport type RestoreServerConfigFunction = (\n    /** Server file id of the file to restore. */\n    uniqueFileId: any,\n    /** Should call the load method with a file object or blob when done. */\n    load: (file: ActualFileObject) => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void,\n    /**\n     * Should call the progress method to update the progress to 100% before calling load().\n     * Setting computable to false switches the loading indicator to infinite mode.\n     */\n    progress: ProgressServerConfigFunction,\n    /** Let FilePond know the request has been cancelled. */\n    abort: () => void,\n    /**\n     * Can call the headers method to supply FilePond with early response header string.\n     * https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders\n     */\n    headers: (headersString: string) => void\n) => void;\n\nexport type LoadServerConfigFunction = (\n    source: any,\n    /** Should call the load method with a file object or blob when done. */\n    load: (file: ActualFileObject | Blob) => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void,\n    /**\n     * Should call the progress method to update the progress to 100% before calling load().\n     * Setting computable to false switches the loading indicator to infinite mode.\n     */\n    progress: ProgressServerConfigFunction,\n    /** Let FilePond know the request has been cancelled. */\n    abort: () => void,\n    /**\n     * Can call the headers method to supply FilePond with early response header string.\n     * https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders>\n     */\n    headers: (headersString: string) => void\n) => void;\n\nexport type FetchServerConfigFunction = (\n    url: string,\n    /** Should call the load method with a file object or blob when done. */\n    load: (file: ActualFileObject | Blob) => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void,\n    /**\n     * Should call the progress method to update the progress to 100% before calling load().\n     * Setting computable to false switches the loading indicator to infinite mode.\n     */\n    progress: ProgressServerConfigFunction,\n    /** Let FilePond know the request has been cancelled. */\n    abort: () => void,\n    /**\n     * Can call the headers method to supply FilePond with early response header string.\n     * https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders\n     */\n    headers: (headersString: string) => void\n) => void;\n\nexport type RemoveServerConfigFunction = (\n    /** Local file source */\n    source: any,\n    /** Call when done */\n    load: () => void,\n    /** Call if something goes wrong, will exit after. */\n    error: (errorText: string) => void\n) => void;\n\nexport interface FilePondInitialFile {\n    /** The server file reference. */\n    source: string;\n    options: {\n        /** Origin of file being added. */\n        type: 'input' | 'limbo' | 'local';\n        /** Mock file information. */\n        file?: {\n            name?: string;\n            size?: number;\n            type?: string;\n        };\n        /** File initial metadata. */\n        metadata?: { [key: string]: any };\n    };\n}\n\nexport interface FilePondServerConfigProps {\n    /**\n     * Immediately upload new files to the server.\n     * @default true\n     */\n    instantUpload?: boolean;\n    /**\n     * The maximum number of files that can be uploaded in parallel.\n     * @default 2\n     */\n    maxParallelUploads?: number;\n\n    /**\n     * Server API Configuration.\n     * See: https://pqina.nl/filepond/docs/patterns/api/server\n     * @default null\n     */\n    server?:\n        | string\n        | {\n              url?: string;\n              timeout?: number;\n              headers?: { [key: string]: string | boolean | number };\n              process?: string | ServerUrl | ProcessServerConfigFunction | null;\n              revert?: string | ServerUrl | RevertServerConfigFunction | null;\n              restore?: string | ServerUrl | RestoreServerConfigFunction | null;\n              load?: string | ServerUrl | LoadServerConfigFunction | null;\n              fetch?: string | ServerUrl | FetchServerConfigFunction | null;\n              patch?: string | ServerUrl | null;\n              remove?: RemoveServerConfigFunction | null;\n          }\n        | null;\n\n    /**\n     * Enable chunk uploads\n     * @default false\n     */\n    chunkUploads?: boolean;\n    /**\n     * Force use of chunk uploads even for files smaller than chunk size\n     * @default false\n     */\n    chunkForce?: boolean;\n    /**\n     * Size of chunks (5MB default)\n     * @default 5000000\n     */\n    chunkSize?: number;\n    /**\n     * Amount of times to retry upload of a chunk when it fails\n     * @default [500, 1000, 3000]\n     */\n    chunkRetryDelays?: number[];\n\n    /**\n     * A list of file locations that should be loaded immediately.\n     * See: https://pqina.nl/filepond/docs/patterns/api/filepond-object/#setting-initial-files\n     * @default []\n     */\n    files?: Array<FilePondInitialFile | ActualFileObject | Blob | string>;\n}\n\nexport interface FilePondDragDropProps {\n    /**\n     * FilePond will catch all files dropped on the webpage.\n     * @default false\n     */\n    dropOnPage?: boolean;\n    /**\n     * Require drop on the FilePond element itself to catch the file.\n     * @default true\n     */\n    dropOnElement?: boolean;\n    /**\n     * When enabled, files are validated before they are dropped.\n     * A file is not added when it’s invalid.\n     * @default false\n     */\n    dropValidation?: boolean;\n    /**\n     * Ignored file names when handling dropped directories.\n     * Dropping directories is not supported on all browsers.\n     * @default ['.ds_store', 'thumbs.db', 'desktop.ini']\n     */\n    ignoredFiles?: string[];\n}\n\nexport interface FilePondLabelProps {\n    /**\n     * The decimal separator used to render numbers.\n     * By default this is determined automatically.\n     * @default 'auto'\n     */\n    labelDecimalSeparator?: string;\n    /**\n     * The thousands separator used to render numbers.\n     * By default this is determined automatically.\n     * @default 'auto'\n     */\n    labelThousandsSeparator?: string;\n    /**\n     * Default label shown to indicate this is a drop area.\n     * FilePond will automatically bind browse file events to\n     * the element with CSS class .filepond--label-action.\n     * @default 'Drag & Drop your files or <span class=\"filepond--label-action\"> Browse </span>'\n     */\n    labelIdle?: string;\n    /**\n     * Label shown when the field contains invalid files and is validated by the parent form.\n     * @default 'Field contains invalid files'\n     */\n    labelInvalidField?: string;\n    /**\n     * Label used while waiting for file size information.\n     * @default 'Waiting for size'\n     */\n    labelFileWaitingForSize?: string;\n    /**\n     * Label used when no file size information was received.\n     * @default 'Size not available'\n     */\n    labelFileSizeNotAvailable?: string;\n\n    /**\n     * Label used to indicate bytes\n     * @default 'Bytes'\n     */\n    labelFileSizeBytes?: string;\n\n    /**\n     * Label used to indicate kilobytes\n     * @default 'KB'\n     */\n    labelFileSizeKilobytes?: string;\n\n    /**\n     * Label used to indicate megabytes\n     * @default 'MB'\n     */\n    labelFileSizeMegabytes?: string;\n\n    /**\n     * Label used to indicate gigabytes\n     * @default 'GB'\n     */\n    labelFileSizeGigabytes?: string;\n\n    /**\n     * Label used when showing the number of files and there is only one.\n     * @default 'file in list'\n     */\n    labelFileCountSingular?: string;\n    /**\n     * Label used when showing the number of files and there is more than one.\n     * @default 'files in list'\n     */\n    labelFileCountPlural?: string;\n    /**\n     * Label used while loading a file.\n     * @default 'Loading'\n     */\n    labelFileLoading?: string;\n    /**\n     * Label used when file is added (assistive only).\n     * @default 'Added'\n     */\n    labelFileAdded?: string;\n    /**\n     * Label used when file load failed.\n     * @default 'Error during load'\n     */\n    labelFileLoadError?: ((error: any) => string) | string;\n    /**\n     * Label used when file is removed (assistive only).\n     * @default 'Removed'\n     */\n    labelFileRemoved?: string;\n    /**\n     * Label used when something went during during removing the file upload.\n     * @default 'Error during remove'\n     */\n    labelFileRemoveError?: ((error: any) => string) | string;\n    /**\n     * Label used when uploading a file.\n     * @default 'Uploading'\n     */\n    labelFileProcessing?: string;\n    /**\n     * Label used when file upload has completed.\n     * @default 'Upload complete'\n     */\n    labelFileProcessingComplete?: string;\n    /**\n     * Label used when upload was cancelled.\n     * @default 'Upload cancelled'\n     */\n    labelFileProcessingAborted?: string;\n    /**\n     * Label used when something went wrong during file upload.\n     * @default 'Error during upload'\n     */\n    labelFileProcessingError?: ((error: any) => string) | string;\n    /**\n     * Label used when something went wrong during reverting the file upload.\n     * @default 'Error during revert'\n     */\n    labelFileProcessingRevertError?: ((error: any) => string) | string;\n    /**\n     * Label used to indicate to the user that an action can be cancelled.\n     * @default 'tap to cancel'\n     */\n    labelTapToCancel?: string;\n    /**\n     * Label used to indicate to the user that an action can be retried.\n     * @default 'tap to retry'\n     */\n    labelTapToRetry?: string;\n    /**\n     * Label used to indicate to the user that an action can be undone.\n     * @default 'tap to undo'\n     */\n    labelTapToUndo?: string;\n    /**\n     * Label used for remove button.\n     * @default 'Remove'\n     */\n    labelButtonRemoveItem?: string;\n    /**\n     * Label used for abort load button.\n     * @default 'Abort'\n     */\n    labelButtonAbortItemLoad?: string;\n    /**\n     * Label used for retry load.\n     * @default 'Retry'\n     */\n    labelButtonRetryItemLoad?: string;\n    /**\n     * Label used for abort upload button.\n     * @default 'Cancel'\n     */\n    labelButtonAbortItemProcessing?: string;\n    /**\n     * Label used for undo upload button.\n     * @default 'Undo'\n     */\n    labelButtonUndoItemProcessing?: string;\n    /**\n     * Label used for retry upload button.\n     * @default 'Retry'\n     */\n    labelButtonRetryItemProcessing?: string;\n    /**\n     * Label used for upload button.\n     * @default 'Upload'\n     */\n    labelButtonProcessItem?: string;\n}\n\nexport interface FilePondSvgIconProps {\n    /**\n     * The icon used for remove actions.\n     * @default '<svg></svg>'\n     */\n    iconRemove?: string;\n    /**\n     * The icon used for process actions.\n     * @default '<svg></svg>'\n     */\n    iconProcess?: string;\n    /**\n     * The icon used for retry actions.\n     * @default '<svg></svg>'\n     */\n    iconRetry?: string;\n    /**\n     * The icon used for undo actions.\n     * @default '<svg></svg>'\n     */\n    iconUndo?: string;\n    /**\n     * The icon used for done.\n     * @default '<svg></svg>'\n     */\n    iconDone?: string;\n}\n\nexport interface FilePondErrorDescription {\n    type: string;\n    code: number;\n    body: string;\n}\n\nexport interface FilePondCallbackProps {\n    /** FilePond instance has been created and is ready. */\n    oninit?: () => void;\n    /**\n     * FilePond instance throws a warning. For instance\n     * when the maximum amount of files has been reached.\n     * Optionally receives file if error is related to a\n     * file object.\n     */\n    onwarning?: (error: any, file?: FilePondFile, status?: any) => void;\n    /**\n     * FilePond instance throws an error. Optionally receives\n     * file if error is related to a file object.\n     */\n    onerror?: (error: FilePondErrorDescription, file?: FilePondFile, status?: any) => void;\n    /** Started file load. */\n    onaddfilestart?: (file: FilePondFile) => void;\n    /** Made progress loading a file. */\n    onaddfileprogress?: (file: FilePondFile, progress: number) => void;\n    /** If no error, file has been successfully loaded. */\n    onaddfile?: (error: FilePondErrorDescription | null, file: FilePondFile) => void;\n    /** Started processing a file. */\n    onprocessfilestart?: (file: FilePondFile) => void;\n    /** Made progress processing a file. */\n    onprocessfileprogress?: (file: FilePondFile, progress: number) => void;\n    /** Aborted processing of a file. */\n    onprocessfileabort?: (file: FilePondFile) => void;\n    /** Processing of a file has been reverted. */\n    onprocessfilerevert?: (file: FilePondFile) => void;\n    /** If no error, Processing of a file has been completed. */\n    onprocessfile?: (error: FilePondErrorDescription | null, file: FilePondFile) => void;\n    /** Called when all files in the list have been processed. */\n    onprocessfiles?: () => void;\n    /** File has been removed. */\n    onremovefile?: (error: FilePondErrorDescription | null, file: FilePondFile) => void;\n    /**\n     * File has been transformed by the transform plugin or\n     * another plugin subscribing to the prepare_output filter.\n     * It receives the file item and the output data.\n     */\n    onpreparefile?: (file: FilePondFile, output: any) => void;\n    /** A file has been added or removed, receives a list of file items. */\n    onupdatefiles?: (files: FilePondFile[]) => void;\n    /* Called when a file is clicked or tapped. **/\n    onactivatefile?: (file: FilePondFile) => void;\n    /** Called when the files have been reordered */\n    onreorderfiles?: (files: FilePondFile[]) => void;\n}\n\nexport interface FilePondHookProps {\n    /**\n     * FilePond is about to allow this item to be dropped, it can be a URL or a File object.\n     *\n     * Return `true` or `false` depending on if you want to allow the item to be dropped.\n     */\n    beforeDropFile?: (file: FilePondFile | string) => boolean;\n    /**\n     * FilePond is about to add this file.\n     *\n     * Return `false` to prevent adding it, or return a `Promise` and resolve with `true` or `false`.\n     */\n    beforeAddFile?: (item: FilePondFile) => boolean | Promise<boolean>;\n    /**\n     * FilePond is about to remove this file.\n     *\n     * Return `false` to prevent adding it, or return a `Promise` and resolve with `true` or `false`.\n     */\n    beforeRemoveFile?: (item: FilePondFile) => boolean | Promise<boolean>;\n}\n\nexport interface FilePondStyleProps {\n    /**\n     * Set a different layout render mode.\n     * @default null\n     */\n    stylePanelLayout?:\n        | 'integrated'\n        | 'compact'\n        | 'circle'\n        | 'integrated circle'\n        | 'compact circle'\n        | null;\n    /**\n     * Set a forced aspect ratio for the FilePond drop area.\n     *\n     * Accepts human readable aspect ratios like `1:1` or numeric aspect ratios like `0.75`.\n     * @default null\n     */\n    stylePanelAspectRatio?: string | null;\n    /**\n     * Set a forced aspect ratio for the file items.\n     *\n     * Useful when rendering cropped or fixed aspect ratio images in grid view.\n     * @default null\n     */\n    styleItemPanelAspectRatio?: string | null;\n    /**\n     * The position of the remove item button.\n     * @default 'left'\n     */\n    styleButtonRemoveItemPosition?: string;\n    /**\n     * The position of the remove item button.\n     * @default 'right'\n     */\n    styleButtonProcessItemPosition?: string;\n    /**\n     * The position of the load indicator.\n     * @default 'right'\n     */\n    styleLoadIndicatorPosition?: string;\n    /**\n     * The position of the progress indicator.\n     * @default 'right'\n     */\n    styleProgressIndicatorPosition?: string;\n    /**\n     * Enable to align the remove button to the left side of the file item.\n     * @default false\n     */\n    styleButtonRemoveItemAlign?: boolean;\n}\n\nexport type CaptureAttribute = 'camera' | 'microphone' | 'camcorder';\n\nexport interface FilePondBaseProps {\n    /**\n     * The ID to add to the root element.\n     * @default null\n     */\n    id?: string | null;\n    /**\n     * The input field name to use.\n     * @default 'filepond'\n     */\n    name?: string;\n    /**\n     * Class Name to put on wrapper.\n     * @default null\n     */\n    className?: string | null;\n    /**\n     * Sets the required attribute to the output field.\n     * @default false\n     */\n    required?: boolean;\n    /**\n     * Sets the disabled attribute to the output field.\n     * @default false\n     */\n    disabled?: boolean;\n    /**\n     * Sets the given value to the capture attribute.\n     * @default null\n     */\n    captureMethod?: CaptureAttribute | null;\n    /**\n     * Set to false to prevent FilePond from setting the file input field `accept` attribute to the value of the `acceptedFileTypes`.\n     */\n    allowSyncAcceptAttribute?: boolean;\n    /**\n     * Enable or disable drag n’ drop.\n     * @default true\n     */\n    allowDrop?: boolean;\n    /**\n     * Enable or disable file browser.\n     * @default true\n     */\n    allowBrowse?: boolean;\n    /**\n     * Enable or disable pasting of files. Pasting files is not\n     * supported on all browsers.\n     * @default true\n     */\n    allowPaste?: boolean;\n    /**\n     * Enable or disable adding multiple files.\n     * @default false\n     */\n    allowMultiple?: boolean;\n    /**\n     * Allow drop to replace a file, only works when allowMultiple is false.\n     * @default true\n     */\n    allowReplace?: boolean;\n    /**\n     * Allows the user to revert file upload.\n     * @default true\n     */\n    allowRevert?: boolean;\n    /**\n     * When set to false the remove button is hidden and disabled.\n     * @default true\n     */\n    allowRemove?: boolean;\n    /**\n     * Allows user to process a file. When set to false, this removes the file upload button.\n     * @default true\n     */\n    allowProcess?: boolean;\n    /**\n     * Allows the user to reorder the file items\n     * @default false\n     */\n    allowReorder?: boolean;\n    /**\n     * Allow only selecting directories with browse (no support for filtering dnd at this point)\n     * @default false\n     */\n    allowDirectoriesOnly?: boolean;\n\n    /**\n     * Require the file to be successfully reverted before continuing.\n     * @default false\n     */\n    forceRevert?: boolean;\n\n    /**\n     * The maximum number of files that filepond pond can handle.\n     * @default null\n     */\n    maxFiles?: number | null;\n    /**\n     * Enables custom validity messages.\n     * @default false\n     */\n    checkValidity?: boolean;\n\n    /**\n     * Set to false to always add items to beginning or end of list.\n     * @default true\n     */\n    itemInsertLocationFreedom?: boolean;\n    /**\n     * Default index in list to add items that have been dropped at the top of the list.\n     * @default 'before'\n     */\n    itemInsertLocation?: 'before' | 'after' | ((a: FilePondFile, b: FilePondFile) => number);\n    /**\n     * The interval to use before showing each item being added to the list.\n     * @default 75\n     */\n    itemInsertInterval?: number;\n    /**\n     * The base value used to calculate file size\n     * @default 1000\n     */\n    fileSizeBase?: number;\n\n    /**\n     * Tells FilePond to store files in hidden file input elements so they can be posted along with\n     * normal form post. This only works if the browser supports the DataTransfer constructor,\n     * this is the case on Firefox, Chrome, Chromium powered browsers and Safari version 14.1\n     * and higher.\n     * @default false\n     */\n    storeAsFile?: boolean;\n\n    /**\n     * Shows Powered by PQINA in footer. Can be disabled by setting to false, but please do\n     * link to https://pqina.nl somewhere else on your website, or otherwise donate to help\n     * keep the project alive.\n     * @default \"Powered by PQINA\"\n     */\n    credits?: false;\n}\n\n// TODO delete\n/**\n * @deprecated use `FilePondOptions`. This will be removed in a future release.\n */\nexport interface FilePondOptionProps\n    extends FilePondDragDropProps,\n        FilePondServerConfigProps,\n        FilePondLabelProps,\n        FilePondSvgIconProps,\n        FilePondCallbackProps,\n        FilePondHookProps,\n        FilePondStyleProps,\n        FilePondBaseProps {}\n\nexport interface FilePondOptions\n    extends FilePondDragDropProps,\n        FilePondServerConfigProps,\n        FilePondLabelProps,\n        FilePondSvgIconProps,\n        FilePondCallbackProps,\n        FilePondHookProps,\n        FilePondStyleProps,\n        FilePondBaseProps {}\n\nexport type FilePondEventPrefixed =\n    | 'FilePond:init'\n    | 'FilePond:warning'\n    | 'FilePond:error'\n    | 'FilePond:addfilestart'\n    | 'FilePond:addfileprogress'\n    | 'FilePond:addfile'\n    | 'FilePond:processfilestart'\n    | 'FilePond:processfileprogress'\n    | 'FilePond:processfileabort'\n    | 'FilePond:processfilerevert'\n    | 'FilePond:processfile'\n    | 'FilePond:processfiles'\n    | 'FilePond:removefile'\n    | 'FilePond:updatefiles'\n    | 'FilePond:reorderfiles';\n\nexport type FilePondEvent =\n    | 'init'\n    | 'warning'\n    | 'error'\n    | 'addfilestart'\n    | 'addfileprogress'\n    | 'addfile'\n    | 'processfilestart'\n    | 'processfileprogress'\n    | 'processfileabort'\n    | 'processfilerevert'\n    | 'processfile'\n    | 'processfiles'\n    | 'removefile'\n    | 'updatefiles'\n    | 'reorderfiles';\n\nexport interface RemoveFileOptions {\n    remove?: boolean;\n    revert?: boolean;\n}\n\nexport interface FilePond extends Required<FilePondOptions> {}\n\nexport class FilePond {\n    /**\n     * The root element of the Filepond instance.\n     */\n    readonly element: Element | null;\n    /**\n     * Returns the current status of the FilePond instance.\n     * @default Status.EMPTY\n     */\n    readonly status: Status;\n\n    /** Override multiple options at once. */\n    setOptions(options: FilePondOptions): void;\n    /**\n     * Adds a file.\n     * @param options.index The index that the file should be added at.\n     */\n    addFile(\n        source: ActualFileObject | Blob | string,\n        options?: { index?: number } & Partial<FilePondInitialFile['options']>\n    ): Promise<FilePondFile>;\n    /**\n     * Adds multiple files.\n     * @param options.index The index that the files should be added at.\n     */\n    addFiles(\n        source: ActualFileObject[] | Blob[] | string[],\n        options?: { index: number }\n    ): Promise<FilePondFile[]>;\n    /**\n     * Moves a file. Select file with query and supply target index.\n     * @param query The file reference, id, or index.\n     * @param index The index to move the file to.\n     */\n    moveFile(query: FilePondFile | string | number, index: number): void;\n    /**\n     * Removes a file.\n     * @param query The file reference, id, or index. If no query is provided, removes the first file in the list.\n     * @param options Options for removal\n     */\n    removeFile(query?: FilePondFile | string | number, options?: RemoveFileOptions): void;\n    /**\n     * Removes the first file in the list.\n     * @param options Options for removal\n     */\n    removeFile(options: RemoveFileOptions): void;\n\n    /**\n     * Removes files matching the query.\n     * @param query Array containing file references, ids, and/or indexes. If no array is provided, all files are removed\n     * @param options Options for removal\n     */\n    removeFiles(query?: Array<FilePondFile | string | number>, options?: RemoveFileOptions): void;\n    /**\n     * Removes all files.\n     * @param options Options for removal\n     */\n    removeFiles(options: RemoveFileOptions): void;\n\n    /**\n     * Processes a file. If no parameter is provided, processes the first file in the list.\n     * @param query The file reference, id, or index\n     */\n    processFile(query?: FilePondFile | string | number): Promise<FilePondFile>;\n    /**\n     * Processes multiple files. If no parameter is provided, processes all files.\n     * @param query The file reference(s), id(s), or index(es)\n     */\n    processFiles(query?: FilePondFile[] | string[] | number[]): Promise<FilePondFile[]>;\n\n    /**\n     * Starts preparing the file matching the given query, returns a Promise, the Promise is resolved with the file item and the output file { file, output }\n     * @param query The file reference, id, or index\n     */\n    prepareFile(\n        query?: FilePondFile | string | number\n    ): Promise<{ file: FilePondFile; output: any }>;\n    /**\n     * Processes multiple files. If no parameter is provided, processes all files.\n     * @param query Array containing file reference(s), id(s), or index(es)\n     */\n    prepareFiles(\n        query?: FilePondFile[] | string[] | number[]\n    ): Promise<Array<{ file: FilePondFile; output: any }>>;\n\n    /**\n     * Returns a file. If no parameter is provided, returns the first file in the list.\n     * @param query The file id, or index\n     */\n    getFile(query?: string | number): FilePondFile;\n    /** Returns all files. */\n    getFiles(): FilePondFile[];\n    /**\n     * Manually trigger the browse files panel.\n     *\n     * Only works if the call originates from the user.\n     */\n    browse(): void;\n    /**\n     * Sort the items in the files list.\n     * @param compare The comparison function\n     */\n    sort(compare: (a: FilePondFile, b: FilePondFile) => number): void;\n    /** Destroys this FilePond instance. */\n    destroy(): void;\n\n    /** Inserts the FilePond instance after the supplied element. */\n    insertAfter(element: Element): void;\n    /** Inserts the FilePond instance before the supplied element. */\n    insertBefore(element: Element): void;\n    /** Appends FilePond to the given element.  */\n    appendTo(element: Element): void;\n    /** Returns true if the current instance is attached to the supplied element. */\n    isAttachedTo(element: Element): void;\n    /** Replaces the supplied element with FilePond. */\n    replaceElement(element: Element): void;\n    /** If FilePond replaced the original element, this restores the original element to its original glory. */\n    restoreElement(element: Element): void;\n\n    /**\n     * Adds an event listener to the given event.\n     * @param event Name of the event, prefixed with `Filepond:`\n     * @param fn Event handler\n     */\n    addEventListener(event: FilePondEventPrefixed, fn: (e: any) => void): void;\n    /**\n     * Listen to an event.\n     * @param event Name of the event\n     * @param fn Event handler, signature is identical to the callback method\n     */\n    on(event: FilePondEvent, fn: (...args: any[]) => void): void;\n    /**\n     * Listen to an event once and remove the handler.\n     * @param event Name of the event\n     * @param fn Event handler, signature is identical to the callback method\n     */\n    onOnce(event: FilePondEvent, fn: (...args: any[]) => void): void;\n    /**\n     * Stop listening to an event.\n     * @param event Name of the event\n     * @param fn Event handler, signature is identical to the callback method\n     */\n    off(event: FilePondEvent, fn: (...args: any[]) => void): void;\n}\n\n/** Creates a new FilePond instance. */\nexport function create(element?: Element, options?: FilePondOptions): FilePond;\n/** Destroys the FilePond instance attached to the supplied element. */\nexport function destroy(element: Element): void;\n/** Returns the FilePond instance attached to the supplied element. */\nexport function find(element: Element): FilePond;\n/**\n * Parses a given section of the DOM tree for elements with class\n * .filepond and turns them into FilePond elements.\n */\nexport function parse(context: Element): void;\n/** Registers a FilePond plugin for later use. */\nexport function registerPlugin(...plugins: any[]): void;\n/** Sets page level default options for all FilePond instances. */\nexport function setOptions(options: FilePondOptions): void;\n/** Returns the current default options. */\nexport function getOptions(): FilePondOptions;\n/** Determines whether or not the browser supports FilePond. */\nexport function supported(): boolean;\n/** Returns an object describing all the available options and their types, useful for writing FilePond adapters. */\nexport const OptionTypes: object;\n"
  },
  {
    "path": "types/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"lib\": [\"es6\", \"dom\"],\n        \"noImplicitAny\": true,\n        \"noImplicitThis\": true,\n        \"strictNullChecks\": true,\n        \"strictFunctionTypes\": true,\n        \"noEmit\": true,\n\n        // If the library is an external module (uses `export`), this allows your test file to import \"mylib\" instead of \"./index\".\n        // If the library is global (cannot be imported via `import` or `require`), leave this out.\n        \"baseUrl\": \".\",\n        \"paths\": { \"filepond\": [\".\"] }\n    }   \n}"
  }
]