{ "version": 3, "sources": ["../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/adapters.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/logger.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/connection_monitor.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/internal.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/connection.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/subscription.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/subscription_guarantor.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/subscriptions.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/consumer.js", "../../../node_modules/.pnpm/@rails+actioncable@7.2.200/node_modules/@rails/actioncable/src/index.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/webpack/universalModuleDefinition", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/enums.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getNodeName.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getWindow.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/instanceOf.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/applyStyles.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getBasePlacement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/math.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/userAgent.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/contains.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/isTableElement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getParentNode.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/within.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getFreshSideObject.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/mergePaddingObject.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/expandToHashMap.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/arrow.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getVariation.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/computeStyles.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/eventListeners.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getOppositePlacement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/rectToClientRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/computeOffsets.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/detectOverflow.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/flip.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/hide.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/offset.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/popperOffsets.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/getAltAxis.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/preventOverflow.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/modifiers/index.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/orderModifiers.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/debounce.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/utils/mergeByName.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/createPopper.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/popper.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/popper-lite.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/@popperjs/core/lib/index.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/node_modules/flowbite-datepicker/dist/main.cjs.js", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/accordion/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/carousel/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/clipboard/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/collapse/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/datepicker/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/dial/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/dismiss/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/drawer/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/dropdown/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/input-counter/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/modal/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/popover/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/tabs/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/components/tooltip/index.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/dom/events.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/dom/instances.ts", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/webpack/bootstrap", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/webpack/runtime/define property getters", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/webpack/runtime/hasOwnProperty shorthand", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/webpack/runtime/make namespace object", "../../../node_modules/.pnpm/flowbite@2.5.2/node_modules/flowbite/dist/webpack:/src/index.turbo.ts", "../../../node_modules/.pnpm/apexcharts@4.3.0/node_modules/apexcharts/dist/apexcharts.common.js", "../../../node_modules/.pnpm/aos@2.3.4/node_modules/aos/dist/aos.js", "../../../node_modules/.pnpm/recordrtc@5.6.2/node_modules/recordrtc/RecordRTC.js", "../../../node_modules/.pnpm/@hotwired+turbo@8.0.12/node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js", "../../../node_modules/.pnpm/@hotwired+turbo-rails@8.0.12/node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable.js", "../../../node_modules/.pnpm/@hotwired+turbo-rails@8.0.12/node_modules/@hotwired/turbo-rails/app/javascript/turbo/snakeize.js", "../../../node_modules/.pnpm/@hotwired+turbo-rails@8.0.12/node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable_stream_source_element.js", "../../../node_modules/.pnpm/@hotwired+turbo-rails@8.0.12/node_modules/@hotwired/turbo-rails/app/javascript/turbo/fetch_requests.js", "../../../node_modules/.pnpm/@hotwired+turbo-rails@8.0.12/node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js", "../../javascript/application.js", "../../../node_modules/.pnpm/@lit+reactive-element@2.0.4/node_modules/@lit/reactive-element/src/css-tag.ts", "../../../node_modules/.pnpm/@lit+reactive-element@2.0.4/node_modules/@lit/reactive-element/src/reactive-element.ts", "../../../node_modules/.pnpm/lit-html@3.2.1/node_modules/lit-html/src/lit-html.ts", "../../../node_modules/.pnpm/lit-element@4.1.1/node_modules/lit-element/src/lit-element.ts", "../../../node_modules/.pnpm/@lit+reactive-element@2.0.4/node_modules/@lit/reactive-element/src/decorators/custom-element.ts", "../../../node_modules/.pnpm/@lit+reactive-element@2.0.4/node_modules/@lit/reactive-element/src/decorators/property.ts", "../../../node_modules/.pnpm/@lit+reactive-element@2.0.4/node_modules/@lit/reactive-element/src/decorators/state.ts", "../../../node_modules/.pnpm/lit-html@3.2.1/node_modules/lit-html/src/directive.ts", "../../../node_modules/.pnpm/lit-html@3.2.1/node_modules/lit-html/src/directives/class-map.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/webpack/bootstrap", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/webpack/runtime/define property getters", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/webpack/runtime/hasOwnProperty shorthand", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/webpack/runtime/make namespace object", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/external module \"lit\"", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/str-tag.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/default-msg.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/init/install.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/locale-status-event.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/localized-controller.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/deferred.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/fnv1a64.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/id-generation.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/runtime-msg.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/init/runtime.js", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/external module \"lit/decorators.js\"", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locale-codes.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/ru.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/tr.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/de.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/es.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/nl.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/el.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/fr.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/sr.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/pl.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/uk.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/zh-HK.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/zh-CN.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/it.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/cs.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/no.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/pt.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/ja.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/sv.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/ko.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/km.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/fa.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/da.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/vi.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/locales/hu.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/localization/index.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/types/types.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/gallery/styles-gallery.scss", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/utils.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/gallery/template-gallery.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/gallery/index.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/styles-common.scss", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/bottom-sheet/styles-bottom-sheet.scss", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/external module \"lit/directives/class-map.js\"", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/bottom-sheet/template-bottom-sheet.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/bottom-sheet/index.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/styles.scss", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/apple/styles-apple.scss", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/chrome/template.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/templates/apple/template-apple.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/src/index.ts", "../../../node_modules/.pnpm/@khmyznikov+pwa-install@0.5.4_@lit+react@1.0.6_@types+react@18.3.12__@types+dom-chromium-inst_lthw27x3nwnwp5rydyfa7xfmgm/node_modules/@khmyznikov/pwa-install/dist/webpack:/@khmyznikov/pwa-install/node_modules/@lit/localize/internal/localized-decorator.js", "../../javascript/pwa_install.js", "../../javascript/custom_chart.js", "../../../node_modules/.pnpm/@hotwired+stimulus@3.2.2/node_modules/@hotwired/stimulus/dist/stimulus.js", "../../javascript/controllers/application.js", "../../../node_modules/.pnpm/@stimulus-components+dialog@1.0.1_@hotwired+stimulus@3.2.2/node_modules/@stimulus-components/dialog/dist/stimulus-dialog.mjs", "../../javascript/controllers/expenses_chart_controller.js", "../../javascript/controllers/infinite_list_controller.js", "../../javascript/controllers/index.js", "../../javascript/form_persistence.js", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/weekday.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/helpers.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/dateutil.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterresult.ts", "../../../node_modules/.pnpm/tslib@2.8.1/node_modules/tslib/tslib.es6.mjs", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/callbackiterresult.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/nlp/i18n.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/nlp/totext.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/nlp/parsetext.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/types.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/nlp/index.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/datetime.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/parseoptions.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/parsestring.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/datewithzone.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/optionstostring.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/cache.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/masks.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterinfo/yearinfo.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterinfo/monthinfo.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterinfo/easter.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterinfo/index.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iter/poslist.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iter/index.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/rrule.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/iterset.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/rrulestr.ts", "../../../node_modules/.pnpm/rrule@2.8.1/node_modules/rrule/src/rruleset.ts", "../../../node_modules/.pnpm/chartkick@5.0.1/node_modules/chartkick/dist/chartkick.esm.js", "../../../node_modules/.pnpm/@kurkle+color@0.3.4/node_modules/@kurkle/color/dist/color.esm.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.core.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.math.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.collection.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.extras.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.easing.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.color.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.animations.defaults.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.layouts.defaults.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.intl.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.ticks.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.scale.defaults.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.defaults.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.canvas.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.options.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.config.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.curve.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.dom.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.interpolation.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.rtl.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/helpers/helpers.segment.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.animator.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.animation.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.animations.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.datasetController.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.bar.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.bubble.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.doughnut.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.line.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.polarArea.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.pie.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.radar.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/controllers/controller.scatter.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.adapters.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.interaction.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.layouts.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/platform/platform.base.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/platform/platform.basic.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/platform/platform.dom.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/platform/index.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.element.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.scale.autoskip.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.scale.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.typedRegistry.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.registry.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.plugins.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.config.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/core/core.controller.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/elements/element.arc.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/elements/element.line.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/elements/element.point.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/elements/element.bar.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.colors.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.decimation.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.segment.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.helper.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.options.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.target.stack.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/simpleArc.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.target.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/filler.drawing.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.filler/index.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.legend.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.title.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.subtitle.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/plugins/plugin.tooltip.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.category.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.linearbase.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.linear.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.logarithmic.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.radialLinear.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.time.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/scales/scale.timeseries.js", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/src/index.ts", "../../../node_modules/.pnpm/chart.js@4.4.7/node_modules/chart.js/auto/auto.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constants.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constructFrom.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/toDate.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addDays.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addMonths.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addMilliseconds.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addHours.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/defaultOptions.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfISOWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getISOWeekYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/normalizeDates.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfDay.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInCalendarDays.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfISOWeekYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addMinutes.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addQuarters.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addSeconds.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addWeeks.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addYears.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/compareAsc.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isDate.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isValid.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInCalendarMonths.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInCalendarYears.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInDays.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/getRoundingMethod.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInHours.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInMilliseconds.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInMinutes.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfDay.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfMonth.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isLastDayOfMonth.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInMonths.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInQuarters.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInSeconds.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInWeeks.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceInYears.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfQuarter.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfMonth.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfHour.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfMinute.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfQuarter.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endOfSecond.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US/_lib/formatDistance.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildFormatLongFn.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US/_lib/formatLong.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US/_lib/formatRelative.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildLocalizeFn.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US/_lib/localize.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildMatchFn.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/_lib/buildMatchPatternFn.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US/_lib/match.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/en-US.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getDayOfYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getISOWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getWeekYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfWeekYear.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/addLeadingZeros.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/lightFormatters.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/formatters.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/longFormatters.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/protectedTokens.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/format.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getDefaultOptions.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getISODay.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/transpose.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/Setter.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/Parser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/EraParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/constants.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/utils.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/YearParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/LocalWeekYearParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ISOWeekYearParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ExtendedYearParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/QuarterParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/StandAloneQuarterParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/MonthParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/StandAloneMonthParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/LocalWeekParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setISOWeek.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ISOWeekParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/DateParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/DayOfYearParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setDay.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/DayParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/LocalDayParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/StandAloneLocalDayParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setISODay.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ISODayParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/AMPMParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/AMPMMidnightParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/DayPeriodParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/Hour1to12Parser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/Hour0to23Parser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/Hour0To11Parser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/Hour1To24Parser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/MinuteParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/SecondParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/FractionOfSecondParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ISOTimezoneWithZParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/ISOTimezoneParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/TimestampSecondsParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers/TimestampMillisecondsParser.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfHour.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfMinute.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startOfSecond.js", "../../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parseISO.js", "../../../node_modules/.pnpm/chartjs-adapter-date-fns@3.0.0_chart.js@4.4.7_date-fns@4.1.0/node_modules/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.esm.js", "../../../node_modules/.pnpm/chartkick@5.0.1/node_modules/chartkick/chart.js/chart.esm.js", "../../../node_modules/.pnpm/chartjs-plugin-datalabels@2.2.0_chart.js@4.4.7/node_modules/chartjs-plugin-datalabels/dist/chartjs-plugin-datalabels.esm.js", "../../../node_modules/.pnpm/chartjs-chart-sankey@0.13.0_chart.js@4.4.7/node_modules/chartjs-chart-sankey/dist/chartjs-chart-sankey.esm.js", "../../../node_modules/.pnpm/alpinejs@3.14.6/node_modules/alpinejs/dist/module.esm.js", "../../../node_modules/.pnpm/@alpinejs+focus@3.14.6/node_modules/@alpinejs/focus/dist/module.esm.js", "../../../node_modules/.pnpm/@alpinejs+anchor@3.14.8/node_modules/@alpinejs/anchor/dist/module.esm.js"], "sourcesContent": ["export default {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined,\n}\n", "import adapters from \"./adapters\"\n\n// The logger is disabled by default. You can enable it with:\n//\n// ActionCable.logger.enabled = true\n//\n// Example:\n//\n// import * as ActionCable from '@rails/actioncable'\n//\n// ActionCable.logger.enabled = true\n// ActionCable.logger.log('Connection Established.')\n//\n\nexport default {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now())\n adapters.logger.log(\"[ActionCable]\", ...messages)\n }\n },\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting\n// revival reconnections if things go astray. Internal class, not intended for direct user manipulation.\n\nconst now = () => new Date().getTime()\n\nconst secondsSince = time => (now() - time) / 1000\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this)\n this.connection = connection\n this.reconnectAttempts = 0\n }\n\n start() {\n if (!this.isRunning()) {\n this.startedAt = now()\n delete this.stoppedAt\n this.startPolling()\n addEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`)\n }\n }\n\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now()\n this.stopPolling()\n removeEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(\"ConnectionMonitor stopped\")\n }\n }\n\n isRunning() {\n return this.startedAt && !this.stoppedAt\n }\n\n recordMessage() {\n this.pingedAt = now()\n }\n\n recordConnect() {\n this.reconnectAttempts = 0\n delete this.disconnectedAt\n logger.log(\"ConnectionMonitor recorded connect\")\n }\n\n recordDisconnect() {\n this.disconnectedAt = now()\n logger.log(\"ConnectionMonitor recorded disconnect\")\n }\n\n // Private\n\n startPolling() {\n this.stopPolling()\n this.poll()\n }\n\n stopPolling() {\n clearTimeout(this.pollTimeout)\n }\n\n poll() {\n this.pollTimeout = setTimeout(() => {\n this.reconnectIfStale()\n this.poll()\n }\n , this.getPollInterval())\n }\n\n getPollInterval() {\n const { staleThreshold, reconnectionBackoffRate } = this.constructor\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10))\n const jitterMax = this.reconnectAttempts === 0 ? 1.0 : reconnectionBackoffRate\n const jitter = jitterMax * Math.random()\n return staleThreshold * 1000 * backoff * (1 + jitter)\n }\n\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`)\n this.reconnectAttempts++\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`)\n } else {\n logger.log(\"ConnectionMonitor reopening\")\n this.connection.reopen()\n }\n }\n }\n\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt\n }\n\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold\n }\n\n disconnectedRecently() {\n return this.disconnectedAt && (secondsSince(this.disconnectedAt) < this.constructor.staleThreshold)\n }\n\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout(() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`)\n this.connection.reopen()\n }\n }\n , 200)\n }\n }\n\n}\n\nConnectionMonitor.staleThreshold = 6 // Server::Connections::BEAT_INTERVAL * 2 (missed two pings)\nConnectionMonitor.reconnectionBackoffRate = 0.15\n\nexport default ConnectionMonitor\n", "export default {\n \"message_types\": {\n \"welcome\": \"welcome\",\n \"disconnect\": \"disconnect\",\n \"ping\": \"ping\",\n \"confirmation\": \"confirm_subscription\",\n \"rejection\": \"reject_subscription\"\n },\n \"disconnect_reasons\": {\n \"unauthorized\": \"unauthorized\",\n \"invalid_request\": \"invalid_request\",\n \"server_restart\": \"server_restart\",\n \"remote\": \"remote\"\n },\n \"default_mount_path\": \"/cable\",\n \"protocols\": [\n \"actioncable-v1-json\",\n \"actioncable-unsupported\"\n ]\n}\n", "import adapters from \"./adapters\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport INTERNAL from \"./internal\"\nimport logger from \"./logger\"\n\n// Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.\n\nconst {message_types, protocols} = INTERNAL\nconst supportedProtocols = protocols.slice(0, protocols.length - 1)\n\nconst indexOf = [].indexOf\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this)\n this.consumer = consumer\n this.subscriptions = this.consumer.subscriptions\n this.monitor = new ConnectionMonitor(this)\n this.disconnected = true\n }\n\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data))\n return true\n } else {\n return false\n }\n }\n\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`)\n return false\n } else {\n const socketProtocols = [...protocols, ...this.consumer.subprotocols || []]\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`)\n if (this.webSocket) { this.uninstallEventHandlers() }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols)\n this.installEventHandlers()\n this.monitor.start()\n return true\n }\n }\n\n close({allowReconnect} = {allowReconnect: true}) {\n if (!allowReconnect) { this.monitor.stop() }\n // Avoid closing websockets in a \"connecting\" state due to Safari 15.1+ bug. See: https://github.com/rails/rails/issues/43835#issuecomment-1002288478\n if (this.isOpen()) {\n return this.webSocket.close()\n }\n }\n\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`)\n if (this.isActive()) {\n try {\n return this.close()\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error)\n }\n finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`)\n setTimeout(this.open, this.constructor.reopenDelay)\n }\n } else {\n return this.open()\n }\n }\n\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol\n }\n }\n\n isOpen() {\n return this.isState(\"open\")\n }\n\n isActive() {\n return this.isState(\"open\", \"connecting\")\n }\n\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0\n }\n\n // Private\n\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0\n }\n\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0\n }\n\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase()\n }\n }\n }\n return null\n }\n\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this)\n this.webSocket[`on${eventName}`] = handler\n }\n }\n\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {}\n }\n }\n\n}\n\nConnection.reopenDelay = 500\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) { return }\n const {identifier, message, reason, reconnect, type} = JSON.parse(event.data)\n this.monitor.recordMessage()\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true\n }\n this.monitor.recordConnect()\n return this.subscriptions.reload()\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`)\n return this.close({allowReconnect: reconnect})\n case message_types.ping:\n return null\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier)\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: true})\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: false})\n }\n case message_types.rejection:\n return this.subscriptions.reject(identifier)\n default:\n return this.subscriptions.notify(identifier, \"received\", message)\n }\n },\n\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`)\n this.disconnected = false\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\")\n return this.close({allowReconnect: false})\n }\n },\n\n close(event) {\n logger.log(\"WebSocket onclose event\")\n if (this.disconnected) { return }\n this.disconnected = true\n this.monitor.recordDisconnect()\n return this.subscriptions.notifyAll(\"disconnected\", {willAttemptReconnect: this.monitor.isRunning()})\n },\n\n error() {\n logger.log(\"WebSocket onerror event\")\n }\n}\n\nexport default Connection\n", "// A new subscription is created through the ActionCable.Subscriptions instance available on the consumer.\n// It provides a number of callbacks and a method for calling remote procedure calls on the corresponding\n// Channel instance on the server side.\n//\n// An example demonstrates the basic functionality:\n//\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\", {\n// connected() {\n// // Called once the subscription has been successfully completed\n// },\n//\n// disconnected({ willAttemptReconnect: boolean }) {\n// // Called when the client has disconnected with the server.\n// // The object will have an `willAttemptReconnect` property which\n// // says whether the client has the intention of attempting\n// // to reconnect.\n// },\n//\n// appear() {\n// this.perform('appear', {appearing_on: this.appearingOn()})\n// },\n//\n// away() {\n// this.perform('away')\n// },\n//\n// appearingOn() {\n// $('main').data('appearing-on')\n// }\n// })\n//\n// The methods #appear and #away forward their intent to the remote AppearanceChannel instance on the server\n// by calling the `perform` method with the first parameter being the action (which maps to AppearanceChannel#appear/away).\n// The second parameter is a hash that'll get JSON encoded and made available on the server in the data parameter.\n//\n// This is how the server component would look:\n//\n// class AppearanceChannel < ApplicationActionCable::Channel\n// def subscribed\n// current_user.appear\n// end\n//\n// def unsubscribed\n// current_user.disappear\n// end\n//\n// def appear(data)\n// current_user.appear on: data['appearing_on']\n// end\n//\n// def away\n// current_user.away\n// end\n// end\n//\n// The \"AppearanceChannel\" name is automatically mapped between the client-side subscription creation and the server-side Ruby class name.\n// The AppearanceChannel#appear/away public methods are exposed automatically to client-side invocation through the perform method.\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key]\n object[key] = value\n }\n }\n return object\n}\n\nexport default class Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer\n this.identifier = JSON.stringify(params)\n extend(this, mixin)\n }\n\n // Perform a channel action with the optional data passed as an attribute\n perform(action, data = {}) {\n data.action = action\n return this.send(data)\n }\n\n send(data) {\n return this.consumer.send({command: \"message\", identifier: this.identifier, data: JSON.stringify(data)})\n }\n\n unsubscribe() {\n return this.consumer.subscriptions.remove(this)\n }\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring channel subscribe command is confirmed, retrying until confirmation is received.\n// Internal class, not intended for direct user manipulation.\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions\n this.pendingSubscriptions = []\n }\n\n guarantee(subscription) {\n if(this.pendingSubscriptions.indexOf(subscription) == -1){ \n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)\n this.pendingSubscriptions.push(subscription) \n }\n else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`)\n }\n this.startGuaranteeing()\n }\n\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`)\n this.pendingSubscriptions = (this.pendingSubscriptions.filter((s) => s !== subscription))\n }\n\n startGuaranteeing() {\n this.stopGuaranteeing()\n this.retrySubscribing()\n }\n \n stopGuaranteeing() {\n clearTimeout(this.retryTimeout)\n }\n\n retrySubscribing() {\n this.retryTimeout = setTimeout(() => {\n if (this.subscriptions && typeof(this.subscriptions.subscribe) === \"function\") {\n this.pendingSubscriptions.map((subscription) => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`)\n this.subscriptions.subscribe(subscription)\n })\n }\n }\n , 500)\n }\n}\n\nexport default SubscriptionGuarantor", "import Subscription from \"./subscription\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\nimport logger from \"./logger\"\n\n// Collection class for creating (and internally managing) channel subscriptions.\n// The only method intended to be triggered by the user is ActionCable.Subscriptions#create,\n// and it should be called through the consumer like so:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n\nexport default class Subscriptions {\n constructor(consumer) {\n this.consumer = consumer\n this.guarantor = new SubscriptionGuarantor(this)\n this.subscriptions = []\n }\n\n create(channelName, mixin) {\n const channel = channelName\n const params = typeof channel === \"object\" ? channel : {channel}\n const subscription = new Subscription(this.consumer, params, mixin)\n return this.add(subscription)\n }\n\n // Private\n\n add(subscription) {\n this.subscriptions.push(subscription)\n this.consumer.ensureActiveConnection()\n this.notify(subscription, \"initialized\")\n this.subscribe(subscription)\n return subscription\n }\n\n remove(subscription) {\n this.forget(subscription)\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\")\n }\n return subscription\n }\n\n reject(identifier) {\n return this.findAll(identifier).map((subscription) => {\n this.forget(subscription)\n this.notify(subscription, \"rejected\")\n return subscription\n })\n }\n\n forget(subscription) {\n this.guarantor.forget(subscription)\n this.subscriptions = (this.subscriptions.filter((s) => s !== subscription))\n return subscription\n }\n\n findAll(identifier) {\n return this.subscriptions.filter((s) => s.identifier === identifier)\n }\n\n reload() {\n return this.subscriptions.map((subscription) =>\n this.subscribe(subscription))\n }\n\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription) =>\n this.notify(subscription, callbackName, ...args))\n }\n\n notify(subscription, callbackName, ...args) {\n let subscriptions\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription)\n } else {\n subscriptions = [subscription]\n }\n\n return subscriptions.map((subscription) =>\n (typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined))\n }\n\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription)\n }\n }\n\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`)\n this.findAll(identifier).map((subscription) =>\n this.guarantor.forget(subscription))\n }\n\n sendCommand(subscription, command) {\n const {identifier} = subscription\n return this.consumer.send({command, identifier})\n }\n}\n", "import Connection from \"./connection\"\nimport Subscriptions from \"./subscriptions\"\n\n// The ActionCable.Consumer establishes the connection to a server-side Ruby Connection object. Once established,\n// the ActionCable.ConnectionMonitor will ensure that its properly maintained through heartbeats and checking for stale updates.\n// The Consumer instance is also the gateway to establishing subscriptions to desired channels through the #createSubscription\n// method.\n//\n// The following example shows how this can be set up:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n//\n// When a consumer is created, it automatically connects with the server.\n//\n// To disconnect from the server, call\n//\n// App.cable.disconnect()\n//\n// and to restart the connection:\n//\n// App.cable.connect()\n//\n// Any channel subscriptions which existed prior to disconnecting will\n// automatically resubscribe.\n\nexport default class Consumer {\n constructor(url) {\n this._url = url\n this.subscriptions = new Subscriptions(this)\n this.connection = new Connection(this)\n this.subprotocols = []\n }\n\n get url() {\n return createWebSocketURL(this._url)\n }\n\n send(data) {\n return this.connection.send(data)\n }\n\n connect() {\n return this.connection.open()\n }\n\n disconnect() {\n return this.connection.close({allowReconnect: false})\n }\n\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open()\n }\n }\n\n addSubProtocol(subprotocol) {\n this.subprotocols = [...this.subprotocols, subprotocol]\n }\n}\n\nexport function createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url()\n }\n\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\")\n a.href = url\n // Fix populating Location properties in IE. Otherwise, protocol will be blank.\n a.href = a.href\n a.protocol = a.protocol.replace(\"http\", \"ws\")\n return a.href\n } else {\n return url\n }\n}\n", "import Connection from \"./connection\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport Consumer, { createWebSocketURL } from \"./consumer\"\nimport INTERNAL from \"./internal\"\nimport Subscription from \"./subscription\"\nimport Subscriptions from \"./subscriptions\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\nimport adapters from \"./adapters\"\nimport logger from \"./logger\"\n\nexport {\n Connection,\n ConnectionMonitor,\n Consumer,\n INTERNAL,\n Subscription,\n Subscriptions,\n SubscriptionGuarantor,\n adapters,\n createWebSocketURL,\n logger,\n}\n\nexport function createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url)\n}\n\nexport function getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`)\n if (element) {\n return element.getAttribute(\"content\")\n }\n}\n", "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"Flowbite\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Flowbite\"] = factory();\n\telse\n\t\troot[\"Flowbite\"] = factory();\n})(self, function() {\nreturn ", "export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];", "export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}", "export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}", "import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };", "import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};", "import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}", "export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;", "export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}", "import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}", "import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}", "import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}", "import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}", "import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}", "import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}", "import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}", "import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}", "import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}", "export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}", "import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}", "export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}", "import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}", "export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}", "import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n if (!isHTMLElement(arrowElement)) {\n console.error(['Popper: \"arrow\" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' '));\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(['Popper: \"arrow\" modifier\\'s `element` must be a child of the popper', 'element.'].join(' '));\n }\n\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};", "export default function getVariation(placement) {\n return placement.split('-')[1];\n}", "import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref) {\n var x = _ref.x,\n y = _ref.y;\n var win = window;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n\n if (process.env.NODE_ENV !== \"production\") {\n var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || '';\n\n if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {\n return transitionProperty.indexOf(property) >= 0;\n })) {\n console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: \"transform\", \"top\", \"right\", \"bottom\", \"left\".', '\\n\\n', 'Disable the \"computeStyles\" modifier\\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\\n\\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));\n }\n }\n\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};", "import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};", "var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}", "var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}", "import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}", "import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on \n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}", "import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}", "import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `
` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}", "import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}", "import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}", "import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}", "export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}", "import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}", "import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}", "import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}", "import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n\n if (process.env.NODE_ENV !== \"production\") {\n console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, \"auto\" cannot be used to allow \"bottom-start\".', 'Use \"auto-start\" instead.'].join(' '));\n }\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}", "import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};", "import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};", "import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};", "import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};", "export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}", "import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};", "export { default as applyStyles } from \"./applyStyles.js\";\nexport { default as arrow } from \"./arrow.js\";\nexport { default as computeStyles } from \"./computeStyles.js\";\nexport { default as eventListeners } from \"./eventListeners.js\";\nexport { default as flip } from \"./flip.js\";\nexport { default as hide } from \"./hide.js\";\nexport { default as offset } from \"./offset.js\";\nexport { default as popperOffsets } from \"./popperOffsets.js\";\nexport { default as preventOverflow } from \"./preventOverflow.js\";", "export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}", "import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}", "import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}", "import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}", "export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}", "export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}", "import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport getComputedStyle from \"./dom-utils/getComputedStyle.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport validateModifiers from \"./utils/validateModifiers.js\";\nimport uniqueBy from \"./utils/uniqueBy.js\";\nimport getBasePlacement from \"./utils/getBasePlacement.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nimport { auto } from \"./enums.js\";\nvar INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.';\nvar INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n }); // Validate the provided modifiers so that the consumer will get warned\n // if one of the modifiers is invalid for any reason\n\n if (process.env.NODE_ENV !== \"production\") {\n var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) {\n var name = _ref.name;\n return name;\n });\n validateModifiers(modifiers);\n\n if (getBasePlacement(state.options.placement) === auto) {\n var flipModifier = state.orderedModifiers.find(function (_ref2) {\n var name = _ref2.name;\n return name === 'flip';\n });\n\n if (!flipModifier) {\n console.error(['Popper: \"auto\" placements require the \"flip\" modifier be', 'present and enabled to work.'].join(' '));\n }\n }\n\n var _getComputedStyle = getComputedStyle(popper),\n marginTop = _getComputedStyle.marginTop,\n marginRight = _getComputedStyle.marginRight,\n marginBottom = _getComputedStyle.marginBottom,\n marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can\n // cause bugs with positioning, so we'll warn the consumer\n\n\n if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) {\n return parseFloat(margin);\n })) {\n console.warn(['Popper: CSS \"margin\" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' '));\n }\n }\n\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(INVALID_ELEMENT_ERROR);\n }\n\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n var __debug_loops__ = 0;\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (process.env.NODE_ENV !== \"production\") {\n __debug_loops__ += 1;\n\n if (__debug_loops__ > 100) {\n console.error(INFINITE_LOOP_ERROR);\n break;\n }\n }\n\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(INVALID_ELEMENT_ERROR);\n }\n\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref3) {\n var name = _ref3.name,\n _ref3$options = _ref3.options,\n options = _ref3$options === void 0 ? {} : _ref3$options,\n effect = _ref3.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };", "import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";", "import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };", "export * from \"./enums.js\";\nexport * from \"./modifiers/index.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport { popperGenerator, detectOverflow, createPopper as createPopperBase } from \"./createPopper.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper } from \"./popper.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\";", "'use strict';\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\nfunction _arrayLikeToArray(r, a) {\n (null == a || a > r.length) && (a = r.length);\n for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];\n return n;\n}\nfunction _arrayWithHoles(r) {\n if (Array.isArray(r)) return r;\n}\nfunction _arrayWithoutHoles(r) {\n if (Array.isArray(r)) return _arrayLikeToArray(r);\n}\nfunction _assertThisInitialized(e) {\n if (void 0 === e) throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n return e;\n}\nfunction _callSuper(t, o, e) {\n return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));\n}\nfunction _classCallCheck(a, n) {\n if (!(a instanceof n)) throw new TypeError(\"Cannot call a class as a function\");\n}\nfunction _defineProperties(e, r) {\n for (var t = 0; t < r.length; t++) {\n var o = r[t];\n o.enumerable = o.enumerable || !1, o.configurable = !0, \"value\" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);\n }\n}\nfunction _createClass(e, r, t) {\n return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, \"prototype\", {\n writable: !1\n }), e;\n}\nfunction _get() {\n return _get = \"undefined\" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {\n var p = _superPropBase(e, t);\n if (p) {\n var n = Object.getOwnPropertyDescriptor(p, t);\n return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;\n }\n }, _get.apply(null, arguments);\n}\nfunction _getPrototypeOf(t) {\n return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {\n return t.__proto__ || Object.getPrototypeOf(t);\n }, _getPrototypeOf(t);\n}\nfunction _inherits(t, e) {\n if (\"function\" != typeof e && null !== e) throw new TypeError(\"Super expression must either be null or a function\");\n t.prototype = Object.create(e && e.prototype, {\n constructor: {\n value: t,\n writable: !0,\n configurable: !0\n }\n }), Object.defineProperty(t, \"prototype\", {\n writable: !1\n }), e && _setPrototypeOf(t, e);\n}\nfunction _isNativeReflectConstruct() {\n try {\n var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n } catch (t) {}\n return (_isNativeReflectConstruct = function () {\n return !!t;\n })();\n}\nfunction _iterableToArray(r) {\n if (\"undefined\" != typeof Symbol && null != r[Symbol.iterator] || null != r[\"@@iterator\"]) return Array.from(r);\n}\nfunction _iterableToArrayLimit(r, l) {\n var t = null == r ? null : \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"];\n if (null != t) {\n var e,\n n,\n i,\n u,\n a = [],\n f = !0,\n o = !1;\n try {\n if (i = (t = t.call(r)).next, 0 === l) {\n if (Object(t) !== t) return;\n f = !1;\n } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);\n } catch (r) {\n o = !0, n = r;\n } finally {\n try {\n if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;\n } finally {\n if (o) throw n;\n }\n }\n return a;\n }\n}\nfunction _nonIterableRest() {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nfunction _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nfunction _possibleConstructorReturn(t, e) {\n if (e && (\"object\" == typeof e || \"function\" == typeof e)) return e;\n if (void 0 !== e) throw new TypeError(\"Derived constructors may only return object or undefined\");\n return _assertThisInitialized(t);\n}\nfunction _setPrototypeOf(t, e) {\n return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {\n return t.__proto__ = e, t;\n }, _setPrototypeOf(t, e);\n}\nfunction _slicedToArray(r, e) {\n return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();\n}\nfunction _superPropBase(t, o) {\n for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t)););\n return t;\n}\nfunction _toConsumableArray(r) {\n return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();\n}\nfunction _toPrimitive(t, r) {\n if (\"object\" != typeof t || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != typeof i) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nfunction _toPropertyKey(t) {\n var i = _toPrimitive(t, \"string\");\n return \"symbol\" == typeof i ? i : i + \"\";\n}\nfunction _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}\nfunction _unsupportedIterableToArray(r, a) {\n if (r) {\n if (\"string\" == typeof r) return _arrayLikeToArray(r, a);\n var t = {}.toString.call(r).slice(8, -1);\n return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;\n }\n}\n\nfunction hasProperty(obj, prop) {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n}\nfunction lastItemOf(arr) {\n return arr[arr.length - 1];\n}\n\n// push only the items not included in the array\nfunction pushUnique(arr) {\n for (var _len = arguments.length, items = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n items[_key - 1] = arguments[_key];\n }\n items.forEach(function (item) {\n if (arr.includes(item)) {\n return;\n }\n arr.push(item);\n });\n return arr;\n}\nfunction stringToArray(str, separator) {\n // convert empty string to an empty array\n return str ? str.split(separator) : [];\n}\nfunction isInRange(testVal, min, max) {\n var minOK = min === undefined || testVal >= min;\n var maxOK = max === undefined || testVal <= max;\n return minOK && maxOK;\n}\nfunction limitToRange(val, min, max) {\n if (val < min) {\n return min;\n }\n if (val > max) {\n return max;\n }\n return val;\n}\nfunction createTagRepeat(tagName, repeat) {\n var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n var html = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '';\n var openTagSrc = Object.keys(attributes).reduce(function (src, attr) {\n var val = attributes[attr];\n if (typeof val === 'function') {\n val = val(index);\n }\n return \"\".concat(src, \" \").concat(attr, \"=\\\"\").concat(val, \"\\\"\");\n }, tagName);\n html += \"<\".concat(openTagSrc, \">\").concat(tagName, \">\");\n var next = index + 1;\n return next < repeat ? createTagRepeat(tagName, repeat, attributes, next, html) : html;\n}\n\n// Remove the spacing surrounding tags for HTML parser not to create text nodes\n// before/after elements\nfunction optimizeTemplateHTML(html) {\n return html.replace(/>\\s+/g, '>').replace(/\\s+, '<');\n}\n\nfunction stripTime(timeValue) {\n return new Date(timeValue).setHours(0, 0, 0, 0);\n}\nfunction today() {\n return new Date().setHours(0, 0, 0, 0);\n}\n\n// Get the time value of the start of given date or year, month and day\nfunction dateValue() {\n switch (arguments.length) {\n case 0:\n return today();\n case 1:\n return stripTime(arguments.length <= 0 ? undefined : arguments[0]);\n }\n\n // use setFullYear() to keep 2-digit year from being mapped to 1900-1999\n var newDate = new Date(0);\n newDate.setFullYear.apply(newDate, arguments);\n return newDate.setHours(0, 0, 0, 0);\n}\nfunction addDays(date, amount) {\n var newDate = new Date(date);\n return newDate.setDate(newDate.getDate() + amount);\n}\nfunction addWeeks(date, amount) {\n return addDays(date, amount * 7);\n}\nfunction addMonths(date, amount) {\n // If the day of the date is not in the new month, the last day of the new\n // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03)\n var newDate = new Date(date);\n var monthsToSet = newDate.getMonth() + amount;\n var expectedMonth = monthsToSet % 12;\n if (expectedMonth < 0) {\n expectedMonth += 12;\n }\n var time = newDate.setMonth(monthsToSet);\n return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;\n}\nfunction addYears(date, amount) {\n // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the\n // new year will be returned.\n var newDate = new Date(date);\n var expectedMonth = newDate.getMonth();\n var time = newDate.setFullYear(newDate.getFullYear() + amount);\n return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time;\n}\n\n// Calculate the distance bettwen 2 days of the week\nfunction dayDiff(day, from) {\n return (day - from + 7) % 7;\n}\n\n// Get the date of the specified day of the week of given base date\nfunction dayOfTheWeekOf(baseDate, dayOfWeek) {\n var weekStart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n var baseDay = new Date(baseDate).getDay();\n return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart));\n}\n\n// Get the ISO week of a date\nfunction getWeek(date) {\n // start of ISO week is Monday\n var thuOfTheWeek = dayOfTheWeekOf(date, 4, 1);\n // 1st week == the week where the 4th of January is in\n var firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1);\n return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1;\n}\n\n// Get the start year of the period of years that includes given date\n// years: length of the year period\nfunction startOfYearPeriod(date, years) {\n /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */\n var year = new Date(date).getFullYear();\n return Math.floor(year / years) * years;\n}\n\n// pattern for format parts\nvar reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/;\n// pattern for non date parts\nvar reNonDateParts = /[\\s!-/:-@[-`{-~年月日]+/;\n// cache for persed formats\nvar knownFormats = {};\n// parse funtions for date parts\nvar parseFns = {\n y: function y(date, year) {\n return new Date(date).setFullYear(parseInt(year, 10));\n },\n m: function m(date, month, locale) {\n var newDate = new Date(date);\n var monthIndex = parseInt(month, 10) - 1;\n if (isNaN(monthIndex)) {\n if (!month) {\n return NaN;\n }\n var monthName = month.toLowerCase();\n var compareNames = function compareNames(name) {\n return name.toLowerCase().startsWith(monthName);\n };\n // compare with both short and full names because some locales have periods\n // in the short names (not equal to the first X letters of the full names)\n monthIndex = locale.monthsShort.findIndex(compareNames);\n if (monthIndex < 0) {\n monthIndex = locale.months.findIndex(compareNames);\n }\n if (monthIndex < 0) {\n return NaN;\n }\n }\n newDate.setMonth(monthIndex);\n return newDate.getMonth() !== normalizeMonth(monthIndex) ? newDate.setDate(0) : newDate.getTime();\n },\n d: function d(date, day) {\n return new Date(date).setDate(parseInt(day, 10));\n }\n};\n// format functions for date parts\nvar formatFns = {\n d: function d(date) {\n return date.getDate();\n },\n dd: function dd(date) {\n return padZero(date.getDate(), 2);\n },\n D: function D(date, locale) {\n return locale.daysShort[date.getDay()];\n },\n DD: function DD(date, locale) {\n return locale.days[date.getDay()];\n },\n m: function m(date) {\n return date.getMonth() + 1;\n },\n mm: function mm(date) {\n return padZero(date.getMonth() + 1, 2);\n },\n M: function M(date, locale) {\n return locale.monthsShort[date.getMonth()];\n },\n MM: function MM(date, locale) {\n return locale.months[date.getMonth()];\n },\n y: function y(date) {\n return date.getFullYear();\n },\n yy: function yy(date) {\n return padZero(date.getFullYear(), 2).slice(-2);\n },\n yyyy: function yyyy(date) {\n return padZero(date.getFullYear(), 4);\n }\n};\n\n// get month index in normal range (0 - 11) from any number\nfunction normalizeMonth(monthIndex) {\n return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12);\n}\nfunction padZero(num, length) {\n return num.toString().padStart(length, '0');\n}\nfunction parseFormatString(format) {\n if (typeof format !== 'string') {\n throw new Error(\"Invalid date format.\");\n }\n if (format in knownFormats) {\n return knownFormats[format];\n }\n\n // sprit the format string into parts and seprators\n var separators = format.split(reFormatTokens);\n var parts = format.match(new RegExp(reFormatTokens, 'g'));\n if (separators.length === 0 || !parts) {\n throw new Error(\"Invalid date format.\");\n }\n\n // collect format functions used in the format\n var partFormatters = parts.map(function (token) {\n return formatFns[token];\n });\n\n // collect parse function keys used in the format\n // iterate over parseFns' keys in order to keep the order of the keys.\n var partParserKeys = Object.keys(parseFns).reduce(function (keys, key) {\n var token = parts.find(function (part) {\n return part[0] !== 'D' && part[0].toLowerCase() === key;\n });\n if (token) {\n keys.push(key);\n }\n return keys;\n }, []);\n return knownFormats[format] = {\n parser: function parser(dateStr, locale) {\n var dateParts = dateStr.split(reNonDateParts).reduce(function (dtParts, part, index) {\n if (part.length > 0 && parts[index]) {\n var token = parts[index][0];\n if (token === 'M') {\n dtParts.m = part;\n } else if (token !== 'D') {\n dtParts[token] = part;\n }\n }\n return dtParts;\n }, {});\n\n // iterate over partParserkeys so that the parsing is made in the oder\n // of year, month and day to prevent the day parser from correcting last\n // day of month wrongly\n return partParserKeys.reduce(function (origDate, key) {\n var newDate = parseFns[key](origDate, dateParts[key], locale);\n // ingnore the part failed to parse\n return isNaN(newDate) ? origDate : newDate;\n }, today());\n },\n formatter: function formatter(date, locale) {\n var dateStr = partFormatters.reduce(function (str, fn, index) {\n return str += \"\".concat(separators[index]).concat(fn(date, locale));\n }, '');\n // separators' length is always parts' length + 1,\n return dateStr += lastItemOf(separators);\n }\n };\n}\nfunction parseDate(dateStr, format, locale) {\n if (dateStr instanceof Date || typeof dateStr === 'number') {\n var date = stripTime(dateStr);\n return isNaN(date) ? undefined : date;\n }\n if (!dateStr) {\n return undefined;\n }\n if (dateStr === 'today') {\n return today();\n }\n if (format && format.toValue) {\n var _date = format.toValue(dateStr, format, locale);\n return isNaN(_date) ? undefined : stripTime(_date);\n }\n return parseFormatString(format).parser(dateStr, locale);\n}\nfunction formatDate(date, format, locale) {\n if (isNaN(date) || !date && date !== 0) {\n return '';\n }\n var dateObj = typeof date === 'number' ? new Date(date) : date;\n if (format.toDisplay) {\n return format.toDisplay(dateObj, format, locale);\n }\n return parseFormatString(format).formatter(dateObj, locale);\n}\n\nvar listenerRegistry = new WeakMap();\nvar _EventTarget$prototyp = EventTarget.prototype,\n addEventListener = _EventTarget$prototyp.addEventListener,\n removeEventListener = _EventTarget$prototyp.removeEventListener;\n\n// Register event listeners to a key object\n// listeners: array of listener definitions;\n// - each definition must be a flat array of event target and the arguments\n// used to call addEventListener() on the target\nfunction registerListeners(keyObj, listeners) {\n var registered = listenerRegistry.get(keyObj);\n if (!registered) {\n registered = [];\n listenerRegistry.set(keyObj, registered);\n }\n listeners.forEach(function (listener) {\n addEventListener.call.apply(addEventListener, _toConsumableArray(listener));\n registered.push(listener);\n });\n}\nfunction unregisterListeners(keyObj) {\n var listeners = listenerRegistry.get(keyObj);\n if (!listeners) {\n return;\n }\n listeners.forEach(function (listener) {\n removeEventListener.call.apply(removeEventListener, _toConsumableArray(listener));\n });\n listenerRegistry[\"delete\"](keyObj);\n}\n\n// Event.composedPath() polyfill for Edge\n// based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec\nif (!Event.prototype.composedPath) {\n var getComposedPath = function getComposedPath(node) {\n var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n path.push(node);\n var parent;\n if (node.parentNode) {\n parent = node.parentNode;\n } else if (node.host) {\n // ShadowRoot\n parent = node.host;\n } else if (node.defaultView) {\n // Document\n parent = node.defaultView;\n }\n return parent ? getComposedPath(parent, path) : path;\n };\n Event.prototype.composedPath = function () {\n return getComposedPath(this.target);\n };\n}\nfunction findFromPath(path, criteria, currentTarget) {\n var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n var el = path[index];\n if (criteria(el)) {\n return el;\n } else if (el === currentTarget || !el.parentElement) {\n // stop when reaching currentTarget or \n return;\n }\n return findFromPath(path, criteria, currentTarget, index + 1);\n}\n\n// Search for the actual target of a delegated event\nfunction findElementInEventPath(ev, selector) {\n var criteria = typeof selector === 'function' ? selector : function (el) {\n return el.matches(selector);\n };\n return findFromPath(ev.composedPath(), criteria, ev.currentTarget);\n}\n\n// default locales\nvar locales = {\n en: {\n days: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n daysShort: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n daysMin: [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n months: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n monthsShort: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"],\n today: \"Today\",\n clear: \"Clear\",\n titleFormat: \"MM y\"\n }\n};\n\n// config options updatable by setOptions() and their default values\nvar defaultOptions = {\n autohide: false,\n beforeShowDay: null,\n beforeShowDecade: null,\n beforeShowMonth: null,\n beforeShowYear: null,\n calendarWeeks: false,\n clearBtn: false,\n dateDelimiter: ',',\n datesDisabled: [],\n daysOfWeekDisabled: [],\n daysOfWeekHighlighted: [],\n defaultViewDate: undefined,\n // placeholder, defaults to today() by the program\n disableTouchKeyboard: false,\n format: 'mm/dd/yyyy',\n language: 'en',\n maxDate: null,\n maxNumberOfDates: 1,\n maxView: 3,\n minDate: null,\n nextArrow: '',\n orientation: 'auto',\n pickLevel: 0,\n prevArrow: '',\n showDaysOfWeek: true,\n showOnClick: true,\n showOnFocus: true,\n startView: 0,\n title: '',\n todayBtn: false,\n todayBtnMode: 0,\n todayHighlight: false,\n updateOnBlur: true,\n weekStart: 0\n};\n\nvar range = document.createRange();\nfunction parseHTML(html) {\n return range.createContextualFragment(html);\n}\nfunction hideElement(el) {\n if (el.style.display === 'none') {\n return;\n }\n // back up the existing display setting in data-style-display\n if (el.style.display) {\n el.dataset.styleDisplay = el.style.display;\n }\n el.style.display = 'none';\n}\nfunction showElement(el) {\n if (el.style.display !== 'none') {\n return;\n }\n if (el.dataset.styleDisplay) {\n // restore backed-up dispay property\n el.style.display = el.dataset.styleDisplay;\n delete el.dataset.styleDisplay;\n } else {\n el.style.display = '';\n }\n}\nfunction emptyChildNodes(el) {\n if (el.firstChild) {\n el.removeChild(el.firstChild);\n emptyChildNodes(el);\n }\n}\nfunction replaceChildNodes(el, newChildNodes) {\n emptyChildNodes(el);\n if (newChildNodes instanceof DocumentFragment) {\n el.appendChild(newChildNodes);\n } else if (typeof newChildNodes === 'string') {\n el.appendChild(parseHTML(newChildNodes));\n } else if (typeof newChildNodes.forEach === 'function') {\n newChildNodes.forEach(function (node) {\n el.appendChild(node);\n });\n }\n}\n\nvar defaultLang = defaultOptions.language,\n defaultFormat = defaultOptions.format,\n defaultWeekStart = defaultOptions.weekStart;\n\n// Reducer function to filter out invalid day-of-week from the input\nfunction sanitizeDOW(dow, day) {\n return dow.length < 6 && day >= 0 && day < 7 ? pushUnique(dow, day) : dow;\n}\nfunction calcEndOfWeek(startOfWeek) {\n return (startOfWeek + 6) % 7;\n}\n\n// validate input date. if invalid, fallback to the original value\nfunction validateDate(value, format, locale, origValue) {\n var date = parseDate(value, format, locale);\n return date !== undefined ? date : origValue;\n}\n\n// Validate viewId. if invalid, fallback to the original value\nfunction validateViewId(value, origValue) {\n var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;\n var viewId = parseInt(value, 10);\n return viewId >= 0 && viewId <= max ? viewId : origValue;\n}\n\n// Create Datepicker configuration to set\nfunction processOptions(options, datepicker) {\n var inOpts = Object.assign({}, options);\n var config = {};\n var locales = datepicker.constructor.locales;\n var _ref = datepicker.config || {},\n format = _ref.format,\n language = _ref.language,\n locale = _ref.locale,\n maxDate = _ref.maxDate,\n maxView = _ref.maxView,\n minDate = _ref.minDate,\n pickLevel = _ref.pickLevel,\n startView = _ref.startView,\n weekStart = _ref.weekStart;\n if (inOpts.language) {\n var lang;\n if (inOpts.language !== language) {\n if (locales[inOpts.language]) {\n lang = inOpts.language;\n } else {\n // Check if langauge + region tag can fallback to the one without\n // region (e.g. fr-CA → fr)\n lang = inOpts.language.split('-')[0];\n if (locales[lang] === undefined) {\n lang = false;\n }\n }\n }\n delete inOpts.language;\n if (lang) {\n language = config.language = lang;\n\n // update locale as well when updating language\n var origLocale = locale || locales[defaultLang];\n // use default language's properties for the fallback\n locale = Object.assign({\n format: defaultFormat,\n weekStart: defaultWeekStart\n }, locales[defaultLang]);\n if (language !== defaultLang) {\n Object.assign(locale, locales[language]);\n }\n config.locale = locale;\n // if format and/or weekStart are the same as old locale's defaults,\n // update them to new locale's defaults\n if (format === origLocale.format) {\n format = config.format = locale.format;\n }\n if (weekStart === origLocale.weekStart) {\n weekStart = config.weekStart = locale.weekStart;\n config.weekEnd = calcEndOfWeek(locale.weekStart);\n }\n }\n }\n if (inOpts.format) {\n var hasToDisplay = typeof inOpts.format.toDisplay === 'function';\n var hasToValue = typeof inOpts.format.toValue === 'function';\n var validFormatString = reFormatTokens.test(inOpts.format);\n if (hasToDisplay && hasToValue || validFormatString) {\n format = config.format = inOpts.format;\n }\n delete inOpts.format;\n }\n\n //*** dates ***//\n // while min and maxDate for \"no limit\" in the options are better to be null\n // (especially when updating), the ones in the config have to be undefined\n // because null is treated as 0 (= unix epoch) when comparing with time value\n var minDt = minDate;\n var maxDt = maxDate;\n if (inOpts.minDate !== undefined) {\n minDt = inOpts.minDate === null ? dateValue(0, 0, 1) // set 0000-01-01 to prevent negative values for year\n : validateDate(inOpts.minDate, format, locale, minDt);\n delete inOpts.minDate;\n }\n if (inOpts.maxDate !== undefined) {\n maxDt = inOpts.maxDate === null ? undefined : validateDate(inOpts.maxDate, format, locale, maxDt);\n delete inOpts.maxDate;\n }\n if (maxDt < minDt) {\n minDate = config.minDate = maxDt;\n maxDate = config.maxDate = minDt;\n } else {\n if (minDate !== minDt) {\n minDate = config.minDate = minDt;\n }\n if (maxDate !== maxDt) {\n maxDate = config.maxDate = maxDt;\n }\n }\n if (inOpts.datesDisabled) {\n config.datesDisabled = inOpts.datesDisabled.reduce(function (dates, dt) {\n var date = parseDate(dt, format, locale);\n return date !== undefined ? pushUnique(dates, date) : dates;\n }, []);\n delete inOpts.datesDisabled;\n }\n if (inOpts.defaultViewDate !== undefined) {\n var viewDate = parseDate(inOpts.defaultViewDate, format, locale);\n if (viewDate !== undefined) {\n config.defaultViewDate = viewDate;\n }\n delete inOpts.defaultViewDate;\n }\n\n //*** days of week ***//\n if (inOpts.weekStart !== undefined) {\n var wkStart = Number(inOpts.weekStart) % 7;\n if (!isNaN(wkStart)) {\n weekStart = config.weekStart = wkStart;\n config.weekEnd = calcEndOfWeek(wkStart);\n }\n delete inOpts.weekStart;\n }\n if (inOpts.daysOfWeekDisabled) {\n config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);\n delete inOpts.daysOfWeekDisabled;\n }\n if (inOpts.daysOfWeekHighlighted) {\n config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);\n delete inOpts.daysOfWeekHighlighted;\n }\n\n //*** multi date ***//\n if (inOpts.maxNumberOfDates !== undefined) {\n var maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);\n if (maxNumberOfDates >= 0) {\n config.maxNumberOfDates = maxNumberOfDates;\n config.multidate = maxNumberOfDates !== 1;\n }\n delete inOpts.maxNumberOfDates;\n }\n if (inOpts.dateDelimiter) {\n config.dateDelimiter = String(inOpts.dateDelimiter);\n delete inOpts.dateDelimiter;\n }\n\n //*** pick level & view ***//\n var newPickLevel = pickLevel;\n if (inOpts.pickLevel !== undefined) {\n newPickLevel = validateViewId(inOpts.pickLevel, 2);\n delete inOpts.pickLevel;\n }\n if (newPickLevel !== pickLevel) {\n pickLevel = config.pickLevel = newPickLevel;\n }\n var newMaxView = maxView;\n if (inOpts.maxView !== undefined) {\n newMaxView = validateViewId(inOpts.maxView, maxView);\n delete inOpts.maxView;\n }\n // ensure max view >= pick level\n newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;\n if (newMaxView !== maxView) {\n maxView = config.maxView = newMaxView;\n }\n var newStartView = startView;\n if (inOpts.startView !== undefined) {\n newStartView = validateViewId(inOpts.startView, newStartView);\n delete inOpts.startView;\n }\n // ensure pick level <= start view <= max view\n if (newStartView < pickLevel) {\n newStartView = pickLevel;\n } else if (newStartView > maxView) {\n newStartView = maxView;\n }\n if (newStartView !== startView) {\n config.startView = newStartView;\n }\n\n //*** template ***//\n if (inOpts.prevArrow) {\n var prevArrow = parseHTML(inOpts.prevArrow);\n if (prevArrow.childNodes.length > 0) {\n config.prevArrow = prevArrow.childNodes;\n }\n delete inOpts.prevArrow;\n }\n if (inOpts.nextArrow) {\n var nextArrow = parseHTML(inOpts.nextArrow);\n if (nextArrow.childNodes.length > 0) {\n config.nextArrow = nextArrow.childNodes;\n }\n delete inOpts.nextArrow;\n }\n\n //*** misc ***//\n if (inOpts.disableTouchKeyboard !== undefined) {\n config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;\n delete inOpts.disableTouchKeyboard;\n }\n if (inOpts.orientation) {\n var orientation = inOpts.orientation.toLowerCase().split(/\\s+/g);\n config.orientation = {\n x: orientation.find(function (x) {\n return x === 'left' || x === 'right';\n }) || 'auto',\n y: orientation.find(function (y) {\n return y === 'top' || y === 'bottom';\n }) || 'auto'\n };\n delete inOpts.orientation;\n }\n if (inOpts.todayBtnMode !== undefined) {\n switch (inOpts.todayBtnMode) {\n case 0:\n case 1:\n config.todayBtnMode = inOpts.todayBtnMode;\n }\n delete inOpts.todayBtnMode;\n }\n\n //*** copy the rest ***//\n Object.keys(inOpts).forEach(function (key) {\n if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) {\n config[key] = inOpts[key];\n }\n });\n return config;\n}\n\nvar pickerTemplate = optimizeTemplateHTML(\"\"recorder.getBlob()\"
method. Usage of \"getBlob\" is recommended, though.\r\n * @property {Blob} blob - Recorded Blob can be accessed using this property.\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * var blob = this.blob;\r\n *\r\n * // below one is recommended\r\n * var blob = this.getBlob();\r\n * });\r\n */\r\n blob: null,\r\n\r\n /**\r\n * This works only with {recorderType:StereoAudioRecorder}. Use this property on \"stopRecording\" to verify the encoder's sample-rates.\r\n * @property {number} bufferSize - Buffer-size used to encode the WAV container\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * alert('Recorder used this buffer-size: ' + this.bufferSize);\r\n * });\r\n */\r\n bufferSize: 0,\r\n\r\n /**\r\n * This works only with {recorderType:StereoAudioRecorder}. Use this property on \"stopRecording\" to verify the encoder's sample-rates.\r\n * @property {number} sampleRate - Sample-rates used to encode the WAV container\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * alert('Recorder used these sample-rates: ' + this.sampleRate);\r\n * });\r\n */\r\n sampleRate: 0,\r\n\r\n /**\r\n * {recorderType:StereoAudioRecorder} returns ArrayBuffer object.\r\n * @property {ArrayBuffer} buffer - Audio ArrayBuffer, supported only in Chrome.\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * var arrayBuffer = this.buffer;\r\n * alert(arrayBuffer.byteLength);\r\n * });\r\n */\r\n buffer: null,\r\n\r\n /**\r\n * This method resets the recorder. So that you can reuse single recorder instance many times.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.reset();\r\n * recorder.startRecording();\r\n */\r\n reset: function() {\r\n if (self.state === 'recording' && !config.disableLogs) {\r\n console.warn('Stop an active recorder.');\r\n }\r\n\r\n if (mediaRecorder && typeof mediaRecorder.clearRecordedData === 'function') {\r\n mediaRecorder.clearRecordedData();\r\n }\r\n mediaRecorder = null;\r\n setState('inactive');\r\n self.blob = null;\r\n },\r\n\r\n /**\r\n * This method is called whenever recorder's state changes. Use this as an \"event\".\r\n * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.onStateChanged = function(state) {\r\n * console.log('Recorder state: ', state);\r\n * };\r\n */\r\n onStateChanged: function(state) {\r\n if (!config.disableLogs) {\r\n console.log('Recorder state changed:', state);\r\n }\r\n },\r\n\r\n /**\r\n * A recorder can have inactive, recording, paused or stopped states.\r\n * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive.\r\n * @memberof RecordRTC\r\n * @static\r\n * @readonly\r\n * @example\r\n * // this looper function will keep you updated about the recorder's states.\r\n * (function looper() {\r\n * document.querySelector('h1').innerHTML = 'Recorder\\'s state is: ' + recorder.state;\r\n * if(recorder.state === 'stopped') return; // ignore+stop\r\n * setTimeout(looper, 1000); // update after every 3-seconds\r\n * })();\r\n * recorder.startRecording();\r\n */\r\n state: 'inactive',\r\n\r\n /**\r\n * Get recorder's readonly state.\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * var state = recorder.getState();\r\n * @returns {String} Returns recording state.\r\n */\r\n getState: function() {\r\n return self.state;\r\n },\r\n\r\n /**\r\n * Destroy RecordRTC instance. Clear all recorders and objects.\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * recorder.destroy();\r\n */\r\n destroy: function() {\r\n var disableLogsCache = config.disableLogs;\r\n\r\n config = {\r\n disableLogs: true\r\n };\r\n self.reset();\r\n setState('destroyed');\r\n returnObject = self = null;\r\n\r\n if (Storage.AudioContextConstructor) {\r\n Storage.AudioContextConstructor.close();\r\n Storage.AudioContextConstructor = null;\r\n }\r\n\r\n config.disableLogs = disableLogsCache;\r\n\r\n if (!config.disableLogs) {\r\n console.log('RecordRTC is destroyed.');\r\n }\r\n },\r\n\r\n /**\r\n * RecordRTC version number\r\n * @property {String} version - Release version number.\r\n * @memberof RecordRTC\r\n * @static\r\n * @readonly\r\n * @example\r\n * alert(recorder.version);\r\n */\r\n version: '5.6.2'\r\n };\r\n\r\n if (!this) {\r\n self = returnObject;\r\n return returnObject;\r\n }\r\n\r\n // if someone wants to use RecordRTC with the \"new\" keyword.\r\n for (var prop in returnObject) {\r\n this[prop] = returnObject[prop];\r\n }\r\n\r\n self = this;\r\n\r\n return returnObject;\r\n}\r\n\r\nRecordRTC.version = '5.6.2';\r\n\r\nif (typeof module !== 'undefined' /* && !!module.exports*/ ) {\r\n module.exports = RecordRTC;\r\n}\r\n\r\nif (typeof define === 'function' && define.amd) {\r\n define('RecordRTC', [], function() {\r\n return RecordRTC;\r\n });\r\n}\n\r\nRecordRTC.getFromDisk = function(type, callback) {\r\n if (!callback) {\r\n throw 'callback is mandatory.';\r\n }\r\n\r\n console.log('Getting recorded ' + (type === 'all' ? 'blobs' : type + ' blob ') + ' from disk!');\r\n DiskStorage.Fetch(function(dataURL, _type) {\r\n if (type !== 'all' && _type === type + 'Blob' && callback) {\r\n callback(dataURL);\r\n }\r\n\r\n if (type === 'all' && callback) {\r\n callback(dataURL, _type.replace('Blob', ''));\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * This method can be used to store recorded blobs into IndexedDB storage.\r\n * @param {object} options - {audio: Blob, video: Blob, gif: Blob}\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * RecordRTC.writeToDisk({\r\n * audio: audioBlob,\r\n * video: videoBlob,\r\n * gif : gifBlob\r\n * });\r\n */\r\nRecordRTC.writeToDisk = function(options) {\r\n console.log('Writing recorded blob(s) to disk!');\r\n options = options || {};\r\n if (options.audio && options.video && options.gif) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n videoBlob: videoDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n });\r\n } else if (options.audio && options.video) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n videoBlob: videoDataURL\r\n });\r\n });\r\n });\r\n } else if (options.audio && options.gif) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n } else if (options.video && options.gif) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n videoBlob: videoDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n } else if (options.audio) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL\r\n });\r\n });\r\n } else if (options.video) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n DiskStorage.Store({\r\n videoBlob: videoDataURL\r\n });\r\n });\r\n } else if (options.gif) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n }\r\n};\n\r\n// __________________________\r\n// RecordRTC-Configuration.js\r\n\r\n/**\r\n * {@link RecordRTCConfiguration} is an inner/private helper for {@link RecordRTC}.\r\n * @summary It configures the 2nd parameter passed over {@link RecordRTC} and returns a valid \"config\" object.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef RecordRTCConfiguration\r\n * @class\r\n * @example\r\n * var options = RecordRTCConfiguration(mediaStream, options);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {type:\"video\", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, getNativeBlob:true, etc.}\r\n */\r\n\r\nfunction RecordRTCConfiguration(mediaStream, config) {\r\n if (!config.recorderType && !config.type) {\r\n if (!!config.audio && !!config.video) {\r\n config.type = 'video';\r\n } else if (!!config.audio && !config.video) {\r\n config.type = 'audio';\r\n }\r\n }\r\n\r\n if (config.recorderType && !config.type) {\r\n if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || (typeof WebAssemblyRecorder !== 'undefined' && config.recorderType === WebAssemblyRecorder)) {\r\n config.type = 'video';\r\n } else if (config.recorderType === GifRecorder) {\r\n config.type = 'gif';\r\n } else if (config.recorderType === StereoAudioRecorder) {\r\n config.type = 'audio';\r\n } else if (config.recorderType === MediaStreamRecorder) {\r\n if (getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) {\r\n config.type = 'video';\r\n } else if (!getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) {\r\n config.type = 'video';\r\n } else if (getTracks(mediaStream, 'audio').length && !getTracks(mediaStream, 'video').length) {\r\n config.type = 'audio';\r\n } else {\r\n // config.type = 'UnKnown';\r\n }\r\n }\r\n }\r\n\r\n if (typeof MediaStreamRecorder !== 'undefined' && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) {\r\n if (!config.mimeType) {\r\n config.mimeType = 'video/webm';\r\n }\r\n\r\n if (!config.type) {\r\n config.type = config.mimeType.split('/')[0];\r\n }\r\n\r\n if (!config.bitsPerSecond) {\r\n // config.bitsPerSecond = 128000;\r\n }\r\n }\r\n\r\n // consider default type=audio\r\n if (!config.type) {\r\n if (config.mimeType) {\r\n config.type = config.mimeType.split('/')[0];\r\n }\r\n if (!config.type) {\r\n config.type = 'audio';\r\n }\r\n }\r\n\r\n return config;\r\n}\n\r\n// __________________\r\n// GetRecorderType.js\r\n\r\n/**\r\n * {@link GetRecorderType} is an inner/private helper for {@link RecordRTC}.\r\n * @summary It returns best recorder-type available for your browser.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef GetRecorderType\r\n * @class\r\n * @example\r\n * var RecorderType = GetRecorderType(options);\r\n * var recorder = new RecorderType(options);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {type:\"video\", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}\r\n */\r\n\r\nfunction GetRecorderType(mediaStream, config) {\r\n var recorder;\r\n\r\n // StereoAudioRecorder can work with all three: Edge, Firefox and Chrome\r\n // todo: detect if it is Edge, then auto use: StereoAudioRecorder\r\n if (isChrome || isEdge || isOpera) {\r\n // Media Stream Recording API has not been implemented in chrome yet;\r\n // That's why using WebAudio API to record stereo audio in WAV format\r\n recorder = StereoAudioRecorder;\r\n }\r\n\r\n if (typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype && !isChrome) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n\r\n // video recorder (in WebM format)\r\n if (config.type === 'video' && (isChrome || isOpera)) {\r\n recorder = WhammyRecorder;\r\n\r\n if (typeof WebAssemblyRecorder !== 'undefined' && typeof ReadableStream !== 'undefined') {\r\n recorder = WebAssemblyRecorder;\r\n }\r\n }\r\n\r\n // video recorder (in Gif format)\r\n if (config.type === 'gif') {\r\n recorder = GifRecorder;\r\n }\r\n\r\n // html2canvas recording!\r\n if (config.type === 'canvas') {\r\n recorder = CanvasRecorder;\r\n }\r\n\r\n if (isMediaRecorderCompatible() && recorder !== CanvasRecorder && recorder !== GifRecorder && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) {\r\n if (getTracks(mediaStream, 'video').length || getTracks(mediaStream, 'audio').length) {\r\n // audio-only recording\r\n if (config.type === 'audio') {\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('audio/webm')) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n // else recorder = StereoAudioRecorder;\r\n } else {\r\n // video or screen tracks\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('video/webm')) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (mediaStream instanceof Array && mediaStream.length) {\r\n recorder = MultiStreamRecorder;\r\n }\r\n\r\n if (config.recorderType) {\r\n recorder = config.recorderType;\r\n }\r\n\r\n if (!config.disableLogs && !!recorder && !!recorder.name) {\r\n console.log('Using recorderType:', recorder.name || recorder.constructor.name);\r\n }\r\n\r\n if (!recorder && isSafari) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n\r\n return recorder;\r\n}\n\r\n// _____________\r\n// MRecordRTC.js\r\n\r\n/**\r\n * MRecordRTC runs on top of {@link RecordRTC} to bring multiple recordings in a single place, by providing simple API.\r\n * @summary MRecordRTC stands for \"Multiple-RecordRTC\".\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef MRecordRTC\r\n * @class\r\n * @example\r\n * var recorder = new MRecordRTC();\r\n * recorder.addStream(MediaStream);\r\n * recorder.mediaType = {\r\n * audio: true, // or StereoAudioRecorder or MediaStreamRecorder\r\n * video: true, // or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder\r\n * gif: true // or GifRecorder\r\n * };\r\n * // mimeType is optional and should be set only in advance cases.\r\n * recorder.mimeType = {\r\n * audio: 'audio/wav',\r\n * video: 'video/webm',\r\n * gif: 'image/gif'\r\n * };\r\n * recorder.startRecording();\r\n * @see For further information:\r\n * @see {@link https://github.com/muaz-khan/RecordRTC/tree/master/MRecordRTC|MRecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @requires {@link RecordRTC}\r\n */\r\n\r\nfunction MRecordRTC(mediaStream) {\r\n\r\n /**\r\n * This method attaches MediaStream object to {@link MRecordRTC}.\r\n * @param {MediaStream} mediaStream - A MediaStream object, either fetched using getUserMedia API, or generated using captureStreamUntilEnded or WebAudio API.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.addStream(MediaStream);\r\n */\r\n this.addStream = function(_mediaStream) {\r\n if (_mediaStream) {\r\n mediaStream = _mediaStream;\r\n }\r\n };\r\n\r\n /**\r\n * This property can be used to set the recording type e.g. audio, or video, or gif, or canvas.\r\n * @property {object} mediaType - {audio: true, video: true, gif: true}\r\n * @memberof MRecordRTC\r\n * @example\r\n * var recorder = new MRecordRTC();\r\n * recorder.mediaType = {\r\n * audio: true, // TRUE or StereoAudioRecorder or MediaStreamRecorder\r\n * video: true, // TRUE or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder\r\n * gif : true // TRUE or GifRecorder\r\n * };\r\n */\r\n this.mediaType = {\r\n audio: true,\r\n video: true\r\n };\r\n\r\n /**\r\n * This method starts recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.startRecording();\r\n */\r\n this.startRecording = function() {\r\n var mediaType = this.mediaType;\r\n var recorderType;\r\n var mimeType = this.mimeType || {\r\n audio: null,\r\n video: null,\r\n gif: null\r\n };\r\n\r\n if (typeof mediaType.audio !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'audio').length) {\r\n mediaType.audio = false;\r\n }\r\n\r\n if (typeof mediaType.video !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) {\r\n mediaType.video = false;\r\n }\r\n\r\n if (typeof mediaType.gif !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) {\r\n mediaType.gif = false;\r\n }\r\n\r\n if (!mediaType.audio && !mediaType.video && !mediaType.gif) {\r\n throw 'MediaStream must have either audio or video tracks.';\r\n }\r\n\r\n if (!!mediaType.audio) {\r\n recorderType = null;\r\n if (typeof mediaType.audio === 'function') {\r\n recorderType = mediaType.audio;\r\n }\r\n\r\n this.audioRecorder = new RecordRTC(mediaStream, {\r\n type: 'audio',\r\n bufferSize: this.bufferSize,\r\n sampleRate: this.sampleRate,\r\n numberOfAudioChannels: this.numberOfAudioChannels || 2,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.audio,\r\n timeSlice: this.timeSlice,\r\n onTimeStamp: this.onTimeStamp\r\n });\r\n\r\n if (!mediaType.video) {\r\n this.audioRecorder.startRecording();\r\n }\r\n }\r\n\r\n if (!!mediaType.video) {\r\n recorderType = null;\r\n if (typeof mediaType.video === 'function') {\r\n recorderType = mediaType.video;\r\n }\r\n\r\n var newStream = mediaStream;\r\n\r\n if (isMediaRecorderCompatible() && !!mediaType.audio && typeof mediaType.audio === 'function') {\r\n var videoTrack = getTracks(mediaStream, 'video')[0];\r\n\r\n if (isFirefox) {\r\n newStream = new MediaStream();\r\n newStream.addTrack(videoTrack);\r\n\r\n if (recorderType && recorderType === WhammyRecorder) {\r\n // Firefox does NOT supports webp-encoding yet\r\n // But Firefox do supports WebAssemblyRecorder\r\n recorderType = MediaStreamRecorder;\r\n }\r\n } else {\r\n newStream = new MediaStream();\r\n newStream.addTrack(videoTrack);\r\n }\r\n }\r\n\r\n this.videoRecorder = new RecordRTC(newStream, {\r\n type: 'video',\r\n video: this.video,\r\n canvas: this.canvas,\r\n frameInterval: this.frameInterval || 10,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.video,\r\n timeSlice: this.timeSlice,\r\n onTimeStamp: this.onTimeStamp,\r\n workerPath: this.workerPath,\r\n webAssemblyPath: this.webAssemblyPath,\r\n frameRate: this.frameRate, // used by WebAssemblyRecorder; values: usually 30; accepts any.\r\n bitrate: this.bitrate // used by WebAssemblyRecorder; values: 0 to 1000+\r\n });\r\n\r\n if (!mediaType.audio) {\r\n this.videoRecorder.startRecording();\r\n }\r\n }\r\n\r\n if (!!mediaType.audio && !!mediaType.video) {\r\n var self = this;\r\n\r\n var isSingleRecorder = isMediaRecorderCompatible() === true;\r\n\r\n if (mediaType.audio instanceof StereoAudioRecorder && !!mediaType.video) {\r\n isSingleRecorder = false;\r\n } else if (mediaType.audio !== true && mediaType.video !== true && mediaType.audio !== mediaType.video) {\r\n isSingleRecorder = false;\r\n }\r\n\r\n if (isSingleRecorder === true) {\r\n self.audioRecorder = null;\r\n self.videoRecorder.startRecording();\r\n } else {\r\n self.videoRecorder.initRecorder(function() {\r\n self.audioRecorder.initRecorder(function() {\r\n // Both recorders are ready to record things accurately\r\n self.videoRecorder.startRecording();\r\n self.audioRecorder.startRecording();\r\n });\r\n });\r\n }\r\n }\r\n\r\n if (!!mediaType.gif) {\r\n recorderType = null;\r\n if (typeof mediaType.gif === 'function') {\r\n recorderType = mediaType.gif;\r\n }\r\n this.gifRecorder = new RecordRTC(mediaStream, {\r\n type: 'gif',\r\n frameRate: this.frameRate || 200,\r\n quality: this.quality || 10,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.gif\r\n });\r\n this.gifRecorder.startRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method stops recording.\r\n * @param {function} callback - Callback function is invoked when all encoders finished their jobs.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.stopRecording(function(recording){\r\n * var audioBlob = recording.audio;\r\n * var videoBlob = recording.video;\r\n * var gifBlob = recording.gif;\r\n * });\r\n */\r\n this.stopRecording = function(callback) {\r\n callback = callback || function() {};\r\n\r\n if (this.audioRecorder) {\r\n this.audioRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'audio');\r\n });\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'video');\r\n });\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'gif');\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * This method pauses recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.pauseRecording();\r\n */\r\n this.pauseRecording = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.pauseRecording();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.pauseRecording();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.pauseRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.resumeRecording();\r\n */\r\n this.resumeRecording = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.resumeRecording();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.resumeRecording();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.resumeRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to manually get all recorded blobs.\r\n * @param {function} callback - All recorded blobs are passed back to the \"callback\" function.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.getBlob(function(recording){\r\n * var audioBlob = recording.audio;\r\n * var videoBlob = recording.video;\r\n * var gifBlob = recording.gif;\r\n * });\r\n * // or\r\n * var audioBlob = recorder.getBlob().audio;\r\n * var videoBlob = recorder.getBlob().video;\r\n */\r\n this.getBlob = function(callback) {\r\n var output = {};\r\n\r\n if (this.audioRecorder) {\r\n output.audio = this.audioRecorder.getBlob();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n output.video = this.videoRecorder.getBlob();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n output.gif = this.gifRecorder.getBlob();\r\n }\r\n\r\n if (callback) {\r\n callback(output);\r\n }\r\n\r\n return output;\r\n };\r\n\r\n /**\r\n * Destroy all recorder instances.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.destroy();\r\n */\r\n this.destroy = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.destroy();\r\n this.audioRecorder = null;\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.destroy();\r\n this.videoRecorder = null;\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.destroy();\r\n this.gifRecorder = null;\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to manually get all recorded blobs' DataURLs.\r\n * @param {function} callback - All recorded blobs' DataURLs are passed back to the \"callback\" function.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.getDataURL(function(recording){\r\n * var audioDataURL = recording.audio;\r\n * var videoDataURL = recording.video;\r\n * var gifDataURL = recording.gif;\r\n * });\r\n */\r\n this.getDataURL = function(callback) {\r\n this.getBlob(function(blob) {\r\n if (blob.audio && blob.video) {\r\n getDataURL(blob.audio, function(_audioDataURL) {\r\n getDataURL(blob.video, function(_videoDataURL) {\r\n callback({\r\n audio: _audioDataURL,\r\n video: _videoDataURL\r\n });\r\n });\r\n });\r\n } else if (blob.audio) {\r\n getDataURL(blob.audio, function(_audioDataURL) {\r\n callback({\r\n audio: _audioDataURL\r\n });\r\n });\r\n } else if (blob.video) {\r\n getDataURL(blob.video, function(_videoDataURL) {\r\n callback({\r\n video: _videoDataURL\r\n });\r\n });\r\n }\r\n });\r\n\r\n function getDataURL(blob, callback00) {\r\n if (typeof Worker !== 'undefined') {\r\n var webWorker = processInWebWorker(function readFile(_blob) {\r\n postMessage(new FileReaderSync().readAsDataURL(_blob));\r\n });\r\n\r\n webWorker.onmessage = function(event) {\r\n callback00(event.data);\r\n };\r\n\r\n webWorker.postMessage(blob);\r\n } else {\r\n var reader = new FileReader();\r\n reader.readAsDataURL(blob);\r\n reader.onload = function(event) {\r\n callback00(event.target.result);\r\n };\r\n }\r\n }\r\n\r\n function processInWebWorker(_function) {\r\n var blob = URL.createObjectURL(new Blob([_function.toString(),\r\n 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(blob);\r\n var url;\r\n if (typeof URL !== 'undefined') {\r\n url = URL;\r\n } else if (typeof webkitURL !== 'undefined') {\r\n url = webkitURL;\r\n } else {\r\n throw 'Neither URL nor webkitURL detected.';\r\n }\r\n url.revokeObjectURL(blob);\r\n return worker;\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to ask {@link MRecordRTC} to write all recorded blobs into IndexedDB storage.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.writeToDisk();\r\n */\r\n this.writeToDisk = function() {\r\n RecordRTC.writeToDisk({\r\n audio: this.audioRecorder,\r\n video: this.videoRecorder,\r\n gif: this.gifRecorder\r\n });\r\n };\r\n\r\n /**\r\n * This method can be used to invoke a save-as dialog for all recorded blobs.\r\n * @param {object} args - {audio: 'audio-name', video: 'video-name', gif: 'gif-name'}\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.save({\r\n * audio: 'audio-file-name',\r\n * video: 'video-file-name',\r\n * gif : 'gif-file-name'\r\n * });\r\n */\r\n this.save = function(args) {\r\n args = args || {\r\n audio: true,\r\n video: true,\r\n gif: true\r\n };\r\n\r\n if (!!args.audio && this.audioRecorder) {\r\n this.audioRecorder.save(typeof args.audio === 'string' ? args.audio : '');\r\n }\r\n\r\n if (!!args.video && this.videoRecorder) {\r\n this.videoRecorder.save(typeof args.video === 'string' ? args.video : '');\r\n }\r\n if (!!args.gif && this.gifRecorder) {\r\n this.gifRecorder.save(typeof args.gif === 'string' ? args.gif : '');\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * This method can be used to get all recorded blobs from IndexedDB storage.\r\n * @param {string} type - 'all' or 'audio' or 'video' or 'gif'\r\n * @param {function} callback - Callback function to get all stored blobs.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * MRecordRTC.getFromDisk('all', function(dataURL, type){\r\n * if(type === 'audio') { }\r\n * if(type === 'video') { }\r\n * if(type === 'gif') { }\r\n * });\r\n */\r\nMRecordRTC.getFromDisk = RecordRTC.getFromDisk;\r\n\r\n/**\r\n * This method can be used to store recorded blobs into IndexedDB storage.\r\n * @param {object} options - {audio: Blob, video: Blob, gif: Blob}\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * MRecordRTC.writeToDisk({\r\n * audio: audioBlob,\r\n * video: videoBlob,\r\n * gif : gifBlob\r\n * });\r\n */\r\nMRecordRTC.writeToDisk = RecordRTC.writeToDisk;\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MRecordRTC = MRecordRTC;\r\n}\n\r\nvar browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45';\r\n\r\n(function(that) {\r\n if (!that) {\r\n return;\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (typeof global === 'undefined') {\r\n return;\r\n }\r\n\r\n global.navigator = {\r\n userAgent: browserFakeUserAgent,\r\n getUserMedia: function() {}\r\n };\r\n\r\n if (!global.console) {\r\n global.console = {};\r\n }\r\n\r\n if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') {\r\n global.console.error = global.console.log = global.console.log || function() {\r\n console.log(arguments);\r\n };\r\n }\r\n\r\n if (typeof document === 'undefined') {\r\n /*global document:true */\r\n that.document = {\r\n documentElement: {\r\n appendChild: function() {\r\n return '';\r\n }\r\n }\r\n };\r\n\r\n document.createElement = document.captureStream = document.mozCaptureStream = function() {\r\n var obj = {\r\n getContext: function() {\r\n return obj;\r\n },\r\n play: function() {},\r\n pause: function() {},\r\n drawImage: function() {},\r\n toDataURL: function() {\r\n return '';\r\n },\r\n style: {}\r\n };\r\n return obj;\r\n };\r\n\r\n that.HTMLVideoElement = function() {};\r\n }\r\n\r\n if (typeof location === 'undefined') {\r\n /*global location:true */\r\n that.location = {\r\n protocol: 'file:',\r\n href: '',\r\n hash: ''\r\n };\r\n }\r\n\r\n if (typeof screen === 'undefined') {\r\n /*global screen:true */\r\n that.screen = {\r\n width: 0,\r\n height: 0\r\n };\r\n }\r\n\r\n if (typeof URL === 'undefined') {\r\n /*global screen:true */\r\n that.URL = {\r\n createObjectURL: function() {\r\n return '';\r\n },\r\n revokeObjectURL: function() {\r\n return '';\r\n }\r\n };\r\n }\r\n\r\n /*global window:true */\r\n that.window = global;\r\n})(typeof global !== 'undefined' ? global : null);\n\r\n// _____________________________\r\n// Cross-Browser-Declarations.js\r\n\r\n// animation-frame used in WebM recording\r\n\r\n/*jshint -W079 */\r\nvar requestAnimationFrame = window.requestAnimationFrame;\r\nif (typeof requestAnimationFrame === 'undefined') {\r\n if (typeof webkitRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = webkitRequestAnimationFrame;\r\n } else if (typeof mozRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = mozRequestAnimationFrame;\r\n } else if (typeof msRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = msRequestAnimationFrame;\r\n } else if (typeof requestAnimationFrame === 'undefined') {\r\n // via: https://gist.github.com/paulirish/1579671\r\n var lastTime = 0;\r\n\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = function(callback, element) {\r\n var currTime = new Date().getTime();\r\n var timeToCall = Math.max(0, 16 - (currTime - lastTime));\r\n var id = setTimeout(function() {\r\n callback(currTime + timeToCall);\r\n }, timeToCall);\r\n lastTime = currTime + timeToCall;\r\n return id;\r\n };\r\n }\r\n}\r\n\r\n/*jshint -W079 */\r\nvar cancelAnimationFrame = window.cancelAnimationFrame;\r\nif (typeof cancelAnimationFrame === 'undefined') {\r\n if (typeof webkitCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = webkitCancelAnimationFrame;\r\n } else if (typeof mozCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = mozCancelAnimationFrame;\r\n } else if (typeof msCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = msCancelAnimationFrame;\r\n } else if (typeof cancelAnimationFrame === 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = function(id) {\r\n clearTimeout(id);\r\n };\r\n }\r\n}\r\n\r\n// WebAudio API representer\r\nvar AudioContext = window.AudioContext;\r\n\r\nif (typeof AudioContext === 'undefined') {\r\n if (typeof webkitAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = webkitAudioContext;\r\n }\r\n\r\n if (typeof mozAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = mozAudioContext;\r\n }\r\n}\r\n\r\n/*jshint -W079 */\r\nvar URL = window.URL;\r\n\r\nif (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {\r\n /*global URL:true */\r\n URL = webkitURL;\r\n}\r\n\r\nif (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?\r\n if (typeof navigator.webkitGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.webkitGetUserMedia;\r\n }\r\n\r\n if (typeof navigator.mozGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.mozGetUserMedia;\r\n }\r\n}\r\n\r\nvar isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveBlob || !!navigator.msSaveOrOpenBlob);\r\nvar isOpera = !!window.opera || navigator.userAgent.indexOf('OPR/') !== -1;\r\nvar isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && ('netscape' in window) && / rv:/.test(navigator.userAgent);\r\nvar isChrome = (!isOpera && !isEdge && !!navigator.webkitGetUserMedia) || isElectron() || navigator.userAgent.toLowerCase().indexOf('chrome/') !== -1;\r\n\r\nvar isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\r\n\r\nif (isSafari && !isChrome && navigator.userAgent.indexOf('CriOS') !== -1) {\r\n isSafari = false;\r\n isChrome = true;\r\n}\r\n\r\nvar MediaStream = window.MediaStream;\r\n\r\nif (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {\r\n MediaStream = webkitMediaStream;\r\n}\r\n\r\n/*global MediaStream:true */\r\nif (typeof MediaStream !== 'undefined') {\r\n // override \"stop\" method for all browsers\r\n if (typeof MediaStream.prototype.stop === 'undefined') {\r\n MediaStream.prototype.stop = function() {\r\n this.getTracks().forEach(function(track) {\r\n track.stop();\r\n });\r\n };\r\n }\r\n}\r\n\r\n// below function via: http://goo.gl/B3ae8c\r\n/**\r\n * Return human-readable file size.\r\n * @param {number} bytes - Pass bytes and get formatted string.\r\n * @returns {string} - formatted string\r\n * @example\r\n * bytesToSize(1024*1024*5) === '5 GB'\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction bytesToSize(bytes) {\r\n var k = 1000;\r\n var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\r\n if (bytes === 0) {\r\n return '0 Bytes';\r\n }\r\n var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10);\r\n return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];\r\n}\r\n\r\n/**\r\n * @param {Blob} file - File or Blob object. This parameter is required.\r\n * @param {string} fileName - Optional file name e.g. \"Recorded-Video.webm\"\r\n * @example\r\n * invokeSaveAsDialog(blob or file, [optional] fileName);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction invokeSaveAsDialog(file, fileName) {\r\n if (!file) {\r\n throw 'Blob object is required.';\r\n }\r\n\r\n if (!file.type) {\r\n try {\r\n file.type = 'video/webm';\r\n } catch (e) {}\r\n }\r\n\r\n var fileExtension = (file.type || 'video/webm').split('/')[1];\r\n if (fileExtension.indexOf(';') !== -1) {\r\n // extended mimetype, e.g. 'video/webm;codecs=vp8,opus'\r\n fileExtension = fileExtension.split(';')[0];\r\n }\r\n if (fileName && fileName.indexOf('.') !== -1) {\r\n var splitted = fileName.split('.');\r\n fileName = splitted[0];\r\n fileExtension = splitted[1];\r\n }\r\n\r\n var fileFullName = (fileName || (Math.round(Math.random() * 9999999999) + 888888888)) + '.' + fileExtension;\r\n\r\n if (typeof navigator.msSaveOrOpenBlob !== 'undefined') {\r\n return navigator.msSaveOrOpenBlob(file, fileFullName);\r\n } else if (typeof navigator.msSaveBlob !== 'undefined') {\r\n return navigator.msSaveBlob(file, fileFullName);\r\n }\r\n\r\n var hyperlink = document.createElement('a');\r\n hyperlink.href = URL.createObjectURL(file);\r\n hyperlink.download = fileFullName;\r\n\r\n hyperlink.style = 'display:none;opacity:0;color:transparent;';\r\n (document.body || document.documentElement).appendChild(hyperlink);\r\n\r\n if (typeof hyperlink.click === 'function') {\r\n hyperlink.click();\r\n } else {\r\n hyperlink.target = '_blank';\r\n hyperlink.dispatchEvent(new MouseEvent('click', {\r\n view: window,\r\n bubbles: true,\r\n cancelable: true\r\n }));\r\n }\r\n\r\n URL.revokeObjectURL(hyperlink.href);\r\n}\r\n\r\n/**\r\n * from: https://github.com/cheton/is-electron/blob/master/index.js\r\n **/\r\nfunction isElectron() {\r\n // Renderer process\r\n if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {\r\n return true;\r\n }\r\n\r\n // Main process\r\n if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {\r\n return true;\r\n }\r\n\r\n // Detect the user agent when the `nodeIntegration` option is set to true\r\n if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nfunction getTracks(stream, kind) {\r\n if (!stream || !stream.getTracks) {\r\n return [];\r\n }\r\n\r\n return stream.getTracks().filter(function(t) {\r\n return t.kind === (kind || 'audio');\r\n });\r\n}\r\n\r\nfunction setSrcObject(stream, element) {\r\n if ('srcObject' in element) {\r\n element.srcObject = stream;\r\n } else if ('mozSrcObject' in element) {\r\n element.mozSrcObject = stream;\r\n } else {\r\n element.srcObject = stream;\r\n }\r\n}\r\n\r\n/**\r\n * @param {Blob} file - File or Blob object.\r\n * @param {function} callback - Callback function.\r\n * @example\r\n * getSeekableBlob(blob or file, callback);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction getSeekableBlob(inputBlob, callback) {\r\n // EBML.js copyrights goes to: https://github.com/legokichi/ts-ebml\r\n if (typeof EBML === 'undefined') {\r\n throw new Error('Please link: https://www.webrtc-experiment.com/EBML.js');\r\n }\r\n\r\n var reader = new EBML.Reader();\r\n var decoder = new EBML.Decoder();\r\n var tools = EBML.tools;\r\n\r\n var fileReader = new FileReader();\r\n fileReader.onload = function(e) {\r\n var ebmlElms = decoder.decode(this.result);\r\n ebmlElms.forEach(function(element) {\r\n reader.read(element);\r\n });\r\n reader.stop();\r\n var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues);\r\n var body = this.result.slice(reader.metadataSize);\r\n var newBlob = new Blob([refinedMetadataBuf, body], {\r\n type: 'video/webm'\r\n });\r\n\r\n callback(newBlob);\r\n };\r\n fileReader.readAsArrayBuffer(inputBlob);\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.invokeSaveAsDialog = invokeSaveAsDialog;\r\n RecordRTC.getTracks = getTracks;\r\n RecordRTC.getSeekableBlob = getSeekableBlob;\r\n RecordRTC.bytesToSize = bytesToSize;\r\n RecordRTC.isElectron = isElectron;\r\n}\r\n\r\n// __________ (used to handle stuff like http://goo.gl/xmE5eg) issue #129\r\n// Storage.js\r\n\r\n/**\r\n * Storage is a standalone object used by {@link RecordRTC} to store reusable objects e.g. \"new AudioContext\".\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @example\r\n * Storage.AudioContext === webkitAudioContext\r\n * @property {webkitAudioContext} AudioContext - Keeps a reference to AudioContext object.\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\nvar Storage = {};\r\n\r\nif (typeof AudioContext !== 'undefined') {\r\n Storage.AudioContext = AudioContext;\r\n} else if (typeof webkitAudioContext !== 'undefined') {\r\n Storage.AudioContext = webkitAudioContext;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.Storage = Storage;\r\n}\n\r\nfunction isMediaRecorderCompatible() {\r\n if (isFirefox || isSafari || isEdge) {\r\n return true;\r\n }\r\n\r\n var nVer = navigator.appVersion;\r\n var nAgt = navigator.userAgent;\r\n var fullVersion = '' + parseFloat(navigator.appVersion);\r\n var majorVersion = parseInt(navigator.appVersion, 10);\r\n var nameOffset, verOffset, ix;\r\n\r\n if (isChrome || isOpera) {\r\n verOffset = nAgt.indexOf('Chrome');\r\n fullVersion = nAgt.substring(verOffset + 7);\r\n }\r\n\r\n // trim the fullVersion string at semicolon/space if present\r\n if ((ix = fullVersion.indexOf(';')) !== -1) {\r\n fullVersion = fullVersion.substring(0, ix);\r\n }\r\n\r\n if ((ix = fullVersion.indexOf(' ')) !== -1) {\r\n fullVersion = fullVersion.substring(0, ix);\r\n }\r\n\r\n majorVersion = parseInt('' + fullVersion, 10);\r\n\r\n if (isNaN(majorVersion)) {\r\n fullVersion = '' + parseFloat(navigator.appVersion);\r\n majorVersion = parseInt(navigator.appVersion, 10);\r\n }\r\n\r\n return majorVersion >= 49;\r\n}\n\r\n// ______________________\r\n// MediaStreamRecorder.js\r\n\r\n/**\r\n * MediaStreamRecorder is an abstraction layer for {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. It is used by {@link RecordRTC} to record MediaStream(s) in both Chrome and Firefox.\r\n * @summary Runs top over {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://github.com/muaz-khan|Muaz Khan}\r\n * @typedef MediaStreamRecorder\r\n * @class\r\n * @example\r\n * var config = {\r\n * mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis\r\n * audioBitsPerSecond : 256 * 8 * 1024,\r\n * videoBitsPerSecond : 256 * 8 * 1024,\r\n * bitsPerSecond: 256 * 8 * 1024, // if this is provided, skip above two\r\n * checkForInactiveTracks: true,\r\n * timeSlice: 1000, // concatenate intervals based blobs\r\n * ondataavailable: function() {} // get intervals based blobs\r\n * }\r\n * var recorder = new MediaStreamRecorder(mediaStream, config);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n *\r\n * // or\r\n * var blob = recorder.blob;\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {disableLogs:true, initCallback: function, mimeType: \"video/webm\", timeSlice: 1000}\r\n * @throws Will throw an error if first argument \"MediaStream\" is missing. Also throws error if \"MediaRecorder API\" are not supported by the browser.\r\n */\r\n\r\nfunction MediaStreamRecorder(mediaStream, config) {\r\n var self = this;\r\n\r\n if (typeof mediaStream === 'undefined') {\r\n throw 'First argument \"MediaStream\" is required.';\r\n }\r\n\r\n if (typeof MediaRecorder === 'undefined') {\r\n throw 'Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.';\r\n }\r\n\r\n config = config || {\r\n // bitsPerSecond: 256 * 8 * 1024,\r\n mimeType: 'video/webm'\r\n };\r\n\r\n if (config.type === 'audio') {\r\n if (getTracks(mediaStream, 'video').length && getTracks(mediaStream, 'audio').length) {\r\n var stream;\r\n if (!!navigator.mozGetUserMedia) {\r\n stream = new MediaStream();\r\n stream.addTrack(getTracks(mediaStream, 'audio')[0]);\r\n } else {\r\n // webkitMediaStream\r\n stream = new MediaStream(getTracks(mediaStream, 'audio'));\r\n }\r\n mediaStream = stream;\r\n }\r\n\r\n if (!config.mimeType || config.mimeType.toString().toLowerCase().indexOf('audio') === -1) {\r\n config.mimeType = isChrome ? 'audio/webm' : 'audio/ogg';\r\n }\r\n\r\n if (config.mimeType && config.mimeType.toString().toLowerCase() !== 'audio/ogg' && !!navigator.mozGetUserMedia) {\r\n // forcing better codecs on Firefox (via #166)\r\n config.mimeType = 'audio/ogg';\r\n }\r\n }\r\n\r\n var arrayOfBlobs = [];\r\n\r\n /**\r\n * This method returns array of blobs. Use only with \"timeSlice\". Its useful to preview recording anytime, without using the \"stop\" method.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var arrayOfBlobs = recorder.getArrayOfBlobs();\r\n * @returns {Array} Returns array of recorded blobs.\r\n */\r\n this.getArrayOfBlobs = function() {\r\n return arrayOfBlobs;\r\n };\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n // set defaults\r\n self.blob = null;\r\n self.clearRecordedData();\r\n self.timestamps = [];\r\n allStates = [];\r\n arrayOfBlobs = [];\r\n\r\n var recorderHints = config;\r\n\r\n if (!config.disableLogs) {\r\n console.log('Passing following config over MediaRecorder API.', recorderHints);\r\n }\r\n\r\n if (mediaRecorder) {\r\n // mandatory to make sure Firefox doesn't fails to record streams 3-4 times without reloading the page.\r\n mediaRecorder = null;\r\n }\r\n\r\n if (isChrome && !isMediaRecorderCompatible()) {\r\n // to support video-only recording on stable\r\n recorderHints = 'video/vp8';\r\n }\r\n\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && recorderHints.mimeType) {\r\n if (!MediaRecorder.isTypeSupported(recorderHints.mimeType)) {\r\n if (!config.disableLogs) {\r\n console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType);\r\n }\r\n\r\n recorderHints.mimeType = config.type === 'audio' ? 'audio/webm' : 'video/webm';\r\n }\r\n }\r\n\r\n // using MediaRecorder API here\r\n try {\r\n mediaRecorder = new MediaRecorder(mediaStream, recorderHints);\r\n\r\n // reset\r\n config.mimeType = recorderHints.mimeType;\r\n } catch (e) {\r\n // chrome-based fallback\r\n mediaRecorder = new MediaRecorder(mediaStream);\r\n }\r\n\r\n // old hack?\r\n if (recorderHints.mimeType && !MediaRecorder.isTypeSupported && 'canRecordMimeType' in mediaRecorder && mediaRecorder.canRecordMimeType(recorderHints.mimeType) === false) {\r\n if (!config.disableLogs) {\r\n console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType);\r\n }\r\n }\r\n\r\n // Dispatching OnDataAvailable Handler\r\n mediaRecorder.ondataavailable = function(e) {\r\n if (e.data) {\r\n allStates.push('ondataavailable: ' + bytesToSize(e.data.size));\r\n }\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n if (e.data && e.data.size) {\r\n arrayOfBlobs.push(e.data);\r\n updateTimeStamp();\r\n\r\n if (typeof config.ondataavailable === 'function') {\r\n // intervals based blobs\r\n var blob = config.getNativeBlob ? e.data : new Blob([e.data], {\r\n type: getMimeType(recorderHints)\r\n });\r\n config.ondataavailable(blob);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n if (!e.data || !e.data.size || e.data.size < 100 || self.blob) {\r\n // make sure that stopRecording always getting fired\r\n // even if there is invalid data\r\n if (self.recordingCallback) {\r\n self.recordingCallback(new Blob([], {\r\n type: getMimeType(recorderHints)\r\n }));\r\n self.recordingCallback = null;\r\n }\r\n return;\r\n }\r\n\r\n self.blob = config.getNativeBlob ? e.data : new Blob([e.data], {\r\n type: getMimeType(recorderHints)\r\n });\r\n\r\n if (self.recordingCallback) {\r\n self.recordingCallback(self.blob);\r\n self.recordingCallback = null;\r\n }\r\n };\r\n\r\n mediaRecorder.onstart = function() {\r\n allStates.push('started');\r\n };\r\n\r\n mediaRecorder.onpause = function() {\r\n allStates.push('paused');\r\n };\r\n\r\n mediaRecorder.onresume = function() {\r\n allStates.push('resumed');\r\n };\r\n\r\n mediaRecorder.onstop = function() {\r\n allStates.push('stopped');\r\n };\r\n\r\n mediaRecorder.onerror = function(error) {\r\n if (!error) {\r\n return;\r\n }\r\n\r\n if (!error.name) {\r\n error.name = 'UnknownError';\r\n }\r\n\r\n allStates.push('error: ' + error);\r\n\r\n if (!config.disableLogs) {\r\n // via: https://w3c.github.io/mediacapture-record/MediaRecorder.html#exception-summary\r\n if (error.name.toString().toLowerCase().indexOf('invalidstate') !== -1) {\r\n console.error('The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.', error);\r\n } else if (error.name.toString().toLowerCase().indexOf('notsupported') !== -1) {\r\n console.error('MIME type (', recorderHints.mimeType, ') is not supported.', error);\r\n } else if (error.name.toString().toLowerCase().indexOf('security') !== -1) {\r\n console.error('MediaRecorder security error', error);\r\n }\r\n\r\n // older code below\r\n else if (error.name === 'OutOfMemory') {\r\n console.error('The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'IllegalStreamModification') {\r\n console.error('A modification to the stream has occurred that makes it impossible to continue recording. An example would be the addition of a Track while recording is occurring. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'OtherRecordingError') {\r\n console.error('Used for an fatal error other than those listed above. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'GenericError') {\r\n console.error('The UA cannot provide the codec or recording option that has been requested.', error);\r\n } else {\r\n console.error('MediaRecorder Error', error);\r\n }\r\n }\r\n\r\n (function(looper) {\r\n if (!self.manuallyStopped && mediaRecorder && mediaRecorder.state === 'inactive') {\r\n delete config.timeslice;\r\n\r\n // 10 minutes, enough?\r\n mediaRecorder.start(10 * 60 * 1000);\r\n return;\r\n }\r\n\r\n setTimeout(looper, 1000);\r\n })();\r\n\r\n if (mediaRecorder.state !== 'inactive' && mediaRecorder.state !== 'stopped') {\r\n mediaRecorder.stop();\r\n }\r\n };\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n updateTimeStamp();\r\n mediaRecorder.start(config.timeSlice);\r\n } else {\r\n // default is 60 minutes; enough?\r\n // use config => {timeSlice: 1000} otherwise\r\n\r\n mediaRecorder.start(3.6e+6);\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback(); // old code\r\n }\r\n };\r\n\r\n /**\r\n * @property {Array} timestamps - Array of time stamps\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * console.log(recorder.timestamps);\r\n */\r\n this.timestamps = [];\r\n\r\n function updateTimeStamp() {\r\n self.timestamps.push(new Date().getTime());\r\n\r\n if (typeof config.onTimeStamp === 'function') {\r\n config.onTimeStamp(self.timestamps[self.timestamps.length - 1], self.timestamps);\r\n }\r\n }\r\n\r\n function getMimeType(secondObject) {\r\n if (mediaRecorder && mediaRecorder.mimeType) {\r\n return mediaRecorder.mimeType;\r\n }\r\n\r\n return secondObject.mimeType || 'video/webm';\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n self.manuallyStopped = true; // used inside the mediaRecorder.onerror\r\n\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n this.recordingCallback = callback;\r\n\r\n if (mediaRecorder.state === 'recording') {\r\n mediaRecorder.stop();\r\n }\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n setTimeout(function() {\r\n self.blob = new Blob(arrayOfBlobs, {\r\n type: getMimeType(config)\r\n });\r\n\r\n self.recordingCallback(self.blob);\r\n }, 100);\r\n }\r\n };\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n if (mediaRecorder.state === 'recording') {\r\n mediaRecorder.pause();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n if (mediaRecorder.state === 'paused') {\r\n mediaRecorder.resume();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (mediaRecorder && mediaRecorder.state === 'recording') {\r\n self.stop(clearRecordedDataCB);\r\n }\r\n\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n arrayOfBlobs = [];\r\n mediaRecorder = null;\r\n self.timestamps = [];\r\n }\r\n\r\n // Reference to \"MediaRecorder\" object\r\n var mediaRecorder;\r\n\r\n /**\r\n * Access to native MediaRecorder API\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @instance\r\n * @example\r\n * var internal = recorder.getInternalRecorder();\r\n * internal.ondataavailable = function() {}; // override\r\n * internal.stream, internal.onpause, internal.onstop, etc.\r\n * @returns {Object} Returns internal recording object.\r\n */\r\n this.getInternalRecorder = function() {\r\n return mediaRecorder;\r\n };\r\n\r\n function isMediaStreamActive() {\r\n if ('active' in mediaStream) {\r\n if (!mediaStream.active) {\r\n return false;\r\n }\r\n } else if ('ended' in mediaStream) { // old hack\r\n if (mediaStream.ended) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * @property {Blob} blob - Recorded data as \"Blob\" object.\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = null;\r\n\r\n\r\n /**\r\n * Get MediaRecorder readonly state.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var state = recorder.getState();\r\n * @returns {String} Returns recording state.\r\n */\r\n this.getState = function() {\r\n if (!mediaRecorder) {\r\n return 'inactive';\r\n }\r\n\r\n return mediaRecorder.state || 'inactive';\r\n };\r\n\r\n // list of all recording states\r\n var allStates = [];\r\n\r\n /**\r\n * Get MediaRecorder all recording states.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var state = recorder.getAllStates();\r\n * @returns {Array} Returns all recording states\r\n */\r\n this.getAllStates = function() {\r\n return allStates;\r\n };\r\n\r\n // if any Track within the MediaStream is muted or not enabled at any time, \r\n // the browser will only record black frames \r\n // or silence since that is the content produced by the Track\r\n // so we need to stopRecording as soon as any single track ends.\r\n if (typeof config.checkForInactiveTracks === 'undefined') {\r\n config.checkForInactiveTracks = false; // disable to minimize CPU usage\r\n }\r\n\r\n var self = this;\r\n\r\n // this method checks if media stream is stopped\r\n // or if any track is ended.\r\n (function looper() {\r\n if (!mediaRecorder || config.checkForInactiveTracks === false) {\r\n return;\r\n }\r\n\r\n if (isMediaStreamActive() === false) {\r\n if (!config.disableLogs) {\r\n console.log('MediaStream seems stopped.');\r\n }\r\n self.stop();\r\n return;\r\n }\r\n\r\n setTimeout(looper, 1000); // check every second\r\n })();\r\n\r\n // for debugging\r\n this.name = 'MediaStreamRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MediaStreamRecorder = MediaStreamRecorder;\r\n}\r\n\r\n// source code from: http://typedarray.org/wp-content/projects/WebAudioRecorder/script.js\r\n// https://github.com/mattdiamond/Recorderjs#license-mit\r\n// ______________________\r\n// StereoAudioRecorder.js\r\n\r\n/**\r\n * StereoAudioRecorder is a standalone class used by {@link RecordRTC} to bring \"stereo\" audio-recording in chrome.\r\n * @summary JavaScript standalone object for stereo audio recording.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef StereoAudioRecorder\r\n * @class\r\n * @example\r\n * var recorder = new StereoAudioRecorder(MediaStream, {\r\n * sampleRate: 44100,\r\n * bufferSize: 4096\r\n * });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {sampleRate: 44100, bufferSize: 4096, numberOfAudioChannels: 1, etc.}\r\n */\r\n\r\nfunction StereoAudioRecorder(mediaStream, config) {\r\n if (!getTracks(mediaStream, 'audio').length) {\r\n throw 'Your stream has no audio tracks.';\r\n }\r\n\r\n config = config || {};\r\n\r\n var self = this;\r\n\r\n // variables\r\n var leftchannel = [];\r\n var rightchannel = [];\r\n var recording = false;\r\n var recordingLength = 0;\r\n var jsAudioNode;\r\n\r\n var numberOfAudioChannels = 2;\r\n\r\n /**\r\n * Set sample rates such as 8K or 16K. Reference: http://stackoverflow.com/a/28977136/552182\r\n * @property {number} desiredSampRate - Desired Bits per sample * 1000\r\n * @memberof StereoAudioRecorder\r\n * @instance\r\n * @example\r\n * var recorder = StereoAudioRecorder(mediaStream, {\r\n * desiredSampRate: 16 * 1000 // bits-per-sample * 1000\r\n * });\r\n */\r\n var desiredSampRate = config.desiredSampRate;\r\n\r\n // backward compatibility\r\n if (config.leftChannel === true) {\r\n numberOfAudioChannels = 1;\r\n }\r\n\r\n if (config.numberOfAudioChannels === 1) {\r\n numberOfAudioChannels = 1;\r\n }\r\n\r\n if (!numberOfAudioChannels || numberOfAudioChannels < 1) {\r\n numberOfAudioChannels = 2;\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('StereoAudioRecorder is set to record number of channels: ' + numberOfAudioChannels);\r\n }\r\n\r\n // if any Track within the MediaStream is muted or not enabled at any time, \r\n // the browser will only record black frames \r\n // or silence since that is the content produced by the Track\r\n // so we need to stopRecording as soon as any single track ends.\r\n if (typeof config.checkForInactiveTracks === 'undefined') {\r\n config.checkForInactiveTracks = true;\r\n }\r\n\r\n function isMediaStreamActive() {\r\n if (config.checkForInactiveTracks === false) {\r\n // always return \"true\"\r\n return true;\r\n }\r\n\r\n if ('active' in mediaStream) {\r\n if (!mediaStream.active) {\r\n return false;\r\n }\r\n } else if ('ended' in mediaStream) { // old hack\r\n if (mediaStream.ended) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (isMediaStreamActive() === false) {\r\n throw 'Please make sure MediaStream is active.';\r\n }\r\n\r\n resetVariables();\r\n\r\n isAudioProcessStarted = isPaused = false;\r\n recording = true;\r\n\r\n if (typeof config.timeSlice !== 'undefined') {\r\n looper();\r\n }\r\n };\r\n\r\n function mergeLeftRightBuffers(config, callback) {\r\n function mergeAudioBuffers(config, cb) {\r\n var numberOfAudioChannels = config.numberOfAudioChannels;\r\n\r\n // todo: \"slice(0)\" --- is it causes loop? Should be removed?\r\n var leftBuffers = config.leftBuffers.slice(0);\r\n var rightBuffers = config.rightBuffers.slice(0);\r\n var sampleRate = config.sampleRate;\r\n var internalInterleavedLength = config.internalInterleavedLength;\r\n var desiredSampRate = config.desiredSampRate;\r\n\r\n if (numberOfAudioChannels === 2) {\r\n leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);\r\n rightBuffers = mergeBuffers(rightBuffers, internalInterleavedLength);\r\n\r\n if (desiredSampRate) {\r\n leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate);\r\n rightBuffers = interpolateArray(rightBuffers, desiredSampRate, sampleRate);\r\n }\r\n }\r\n\r\n if (numberOfAudioChannels === 1) {\r\n leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);\r\n\r\n if (desiredSampRate) {\r\n leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate);\r\n }\r\n }\r\n\r\n // set sample rate as desired sample rate\r\n if (desiredSampRate) {\r\n sampleRate = desiredSampRate;\r\n }\r\n\r\n // for changing the sampling rate, reference:\r\n // http://stackoverflow.com/a/28977136/552182\r\n function interpolateArray(data, newSampleRate, oldSampleRate) {\r\n var fitCount = Math.round(data.length * (newSampleRate / oldSampleRate));\r\n var newData = [];\r\n var springFactor = Number((data.length - 1) / (fitCount - 1));\r\n newData[0] = data[0];\r\n for (var i = 1; i < fitCount - 1; i++) {\r\n var tmp = i * springFactor;\r\n var before = Number(Math.floor(tmp)).toFixed();\r\n var after = Number(Math.ceil(tmp)).toFixed();\r\n var atPoint = tmp - before;\r\n newData[i] = linearInterpolate(data[before], data[after], atPoint);\r\n }\r\n newData[fitCount - 1] = data[data.length - 1];\r\n return newData;\r\n }\r\n\r\n function linearInterpolate(before, after, atPoint) {\r\n return before + (after - before) * atPoint;\r\n }\r\n\r\n function mergeBuffers(channelBuffer, rLength) {\r\n var result = new Float64Array(rLength);\r\n var offset = 0;\r\n var lng = channelBuffer.length;\r\n\r\n for (var i = 0; i < lng; i++) {\r\n var buffer = channelBuffer[i];\r\n result.set(buffer, offset);\r\n offset += buffer.length;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n function interleave(leftChannel, rightChannel) {\r\n var length = leftChannel.length + rightChannel.length;\r\n\r\n var result = new Float64Array(length);\r\n\r\n var inputIndex = 0;\r\n\r\n for (var index = 0; index < length;) {\r\n result[index++] = leftChannel[inputIndex];\r\n result[index++] = rightChannel[inputIndex];\r\n inputIndex++;\r\n }\r\n return result;\r\n }\r\n\r\n function writeUTFBytes(view, offset, string) {\r\n var lng = string.length;\r\n for (var i = 0; i < lng; i++) {\r\n view.setUint8(offset + i, string.charCodeAt(i));\r\n }\r\n }\r\n\r\n // interleave both channels together\r\n var interleaved;\r\n\r\n if (numberOfAudioChannels === 2) {\r\n interleaved = interleave(leftBuffers, rightBuffers);\r\n }\r\n\r\n if (numberOfAudioChannels === 1) {\r\n interleaved = leftBuffers;\r\n }\r\n\r\n var interleavedLength = interleaved.length;\r\n\r\n // create wav file\r\n var resultingBufferLength = 44 + interleavedLength * 2;\r\n\r\n var buffer = new ArrayBuffer(resultingBufferLength);\r\n\r\n var view = new DataView(buffer);\r\n\r\n // RIFF chunk descriptor/identifier \r\n writeUTFBytes(view, 0, 'RIFF');\r\n\r\n // RIFF chunk length\r\n // changed \"44\" to \"36\" via #401\r\n view.setUint32(4, 36 + interleavedLength * 2, true);\r\n\r\n // RIFF type \r\n writeUTFBytes(view, 8, 'WAVE');\r\n\r\n // format chunk identifier \r\n // FMT sub-chunk\r\n writeUTFBytes(view, 12, 'fmt ');\r\n\r\n // format chunk length \r\n view.setUint32(16, 16, true);\r\n\r\n // sample format (raw)\r\n view.setUint16(20, 1, true);\r\n\r\n // stereo (2 channels)\r\n view.setUint16(22, numberOfAudioChannels, true);\r\n\r\n // sample rate \r\n view.setUint32(24, sampleRate, true);\r\n\r\n // byte rate (sample rate * block align)\r\n view.setUint32(28, sampleRate * numberOfAudioChannels * 2, true);\r\n\r\n // block align (channel count * bytes per sample) \r\n view.setUint16(32, numberOfAudioChannels * 2, true);\r\n\r\n // bits per sample \r\n view.setUint16(34, 16, true);\r\n\r\n // data sub-chunk\r\n // data chunk identifier \r\n writeUTFBytes(view, 36, 'data');\r\n\r\n // data chunk length \r\n view.setUint32(40, interleavedLength * 2, true);\r\n\r\n // write the PCM samples\r\n var lng = interleavedLength;\r\n var index = 44;\r\n var volume = 1;\r\n for (var i = 0; i < lng; i++) {\r\n view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);\r\n index += 2;\r\n }\r\n\r\n if (cb) {\r\n return cb({\r\n buffer: buffer,\r\n view: view\r\n });\r\n }\r\n\r\n postMessage({\r\n buffer: buffer,\r\n view: view\r\n });\r\n }\r\n\r\n if (config.noWorker) {\r\n mergeAudioBuffers(config, function(data) {\r\n callback(data.buffer, data.view);\r\n });\r\n return;\r\n }\r\n\r\n\r\n var webWorker = processInWebWorker(mergeAudioBuffers);\r\n\r\n webWorker.onmessage = function(event) {\r\n callback(event.data.buffer, event.data.view);\r\n\r\n // release memory\r\n URL.revokeObjectURL(webWorker.workerURL);\r\n\r\n // kill webworker (or Chrome will kill your page after ~25 calls)\r\n webWorker.terminate();\r\n };\r\n\r\n webWorker.postMessage(config);\r\n }\r\n\r\n function processInWebWorker(_function) {\r\n var workerURL = URL.createObjectURL(new Blob([_function.toString(),\r\n ';this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(workerURL);\r\n worker.workerURL = workerURL;\r\n return worker;\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n // stop recording\r\n recording = false;\r\n\r\n mergeLeftRightBuffers({\r\n desiredSampRate: desiredSampRate,\r\n sampleRate: sampleRate,\r\n numberOfAudioChannels: numberOfAudioChannels,\r\n internalInterleavedLength: recordingLength,\r\n leftBuffers: leftchannel,\r\n rightBuffers: numberOfAudioChannels === 1 ? [] : rightchannel,\r\n noWorker: config.noWorker\r\n }, function(buffer, view) {\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n self.blob = new Blob([view], {\r\n type: 'audio/wav'\r\n });\r\n\r\n /**\r\n * @property {ArrayBuffer} buffer - The recorded buffer object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var buffer = recorder.buffer;\r\n * });\r\n */\r\n self.buffer = new ArrayBuffer(view.buffer.byteLength);\r\n\r\n /**\r\n * @property {DataView} view - The recorded data-view object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var view = recorder.view;\r\n * });\r\n */\r\n self.view = view;\r\n\r\n self.sampleRate = desiredSampRate || sampleRate;\r\n self.bufferSize = bufferSize;\r\n\r\n // recorded audio length\r\n self.length = recordingLength;\r\n\r\n isAudioProcessStarted = false;\r\n\r\n if (callback) {\r\n callback(self.blob);\r\n }\r\n });\r\n };\r\n\r\n if (typeof RecordRTC.Storage === 'undefined') {\r\n RecordRTC.Storage = {\r\n AudioContextConstructor: null,\r\n AudioContext: window.AudioContext || window.webkitAudioContext\r\n };\r\n }\r\n\r\n if (!RecordRTC.Storage.AudioContextConstructor || RecordRTC.Storage.AudioContextConstructor.state === 'closed') {\r\n RecordRTC.Storage.AudioContextConstructor = new RecordRTC.Storage.AudioContext();\r\n }\r\n\r\n var context = RecordRTC.Storage.AudioContextConstructor;\r\n\r\n // creates an audio node from the microphone incoming stream\r\n var audioInput = context.createMediaStreamSource(mediaStream);\r\n\r\n var legalBufferValues = [0, 256, 512, 1024, 2048, 4096, 8192, 16384];\r\n\r\n /**\r\n * From the spec: This value controls how frequently the audioprocess event is\r\n * dispatched and how many sample-frames need to be processed each call.\r\n * Lower values for buffer size will result in a lower (better) latency.\r\n * Higher values will be necessary to avoid audio breakup and glitches\r\n * The size of the buffer (in sample-frames) which needs to\r\n * be processed each time onprocessaudio is called.\r\n * Legal values are (256, 512, 1024, 2048, 4096, 8192, 16384).\r\n * @property {number} bufferSize - Buffer-size for how frequently the audioprocess event is dispatched.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder = new StereoAudioRecorder(mediaStream, {\r\n * bufferSize: 4096\r\n * });\r\n */\r\n\r\n // \"0\" means, let chrome decide the most accurate buffer-size for current platform.\r\n var bufferSize = typeof config.bufferSize === 'undefined' ? 4096 : config.bufferSize;\r\n\r\n if (legalBufferValues.indexOf(bufferSize) === -1) {\r\n if (!config.disableLogs) {\r\n console.log('Legal values for buffer-size are ' + JSON.stringify(legalBufferValues, null, '\\t'));\r\n }\r\n }\r\n\r\n if (context.createJavaScriptNode) {\r\n jsAudioNode = context.createJavaScriptNode(bufferSize, numberOfAudioChannels, numberOfAudioChannels);\r\n } else if (context.createScriptProcessor) {\r\n jsAudioNode = context.createScriptProcessor(bufferSize, numberOfAudioChannels, numberOfAudioChannels);\r\n } else {\r\n throw 'WebAudio API has no support on this browser.';\r\n }\r\n\r\n // connect the stream to the script processor\r\n audioInput.connect(jsAudioNode);\r\n\r\n if (!config.bufferSize) {\r\n bufferSize = jsAudioNode.bufferSize; // device buffer-size\r\n }\r\n\r\n /**\r\n * The sample rate (in sample-frames per second) at which the\r\n * AudioContext handles audio. It is assumed that all AudioNodes\r\n * in the context run at this rate. In making this assumption,\r\n * sample-rate converters or \"varispeed\" processors are not supported\r\n * in real-time processing.\r\n * The sampleRate parameter describes the sample-rate of the\r\n * linear PCM audio data in the buffer in sample-frames per second.\r\n * An implementation must support sample-rates in at least\r\n * the range 22050 to 96000.\r\n * @property {number} sampleRate - Buffer-size for how frequently the audioprocess event is dispatched.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder = new StereoAudioRecorder(mediaStream, {\r\n * sampleRate: 44100\r\n * });\r\n */\r\n var sampleRate = typeof config.sampleRate !== 'undefined' ? config.sampleRate : context.sampleRate || 44100;\r\n\r\n if (sampleRate < 22050 || sampleRate > 96000) {\r\n // Ref: http://stackoverflow.com/a/26303918/552182\r\n if (!config.disableLogs) {\r\n console.log('sample-rate must be under range 22050 and 96000.');\r\n }\r\n }\r\n\r\n if (!config.disableLogs) {\r\n if (config.desiredSampRate) {\r\n console.log('Desired sample-rate: ' + config.desiredSampRate);\r\n }\r\n }\r\n\r\n var isPaused = false;\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPaused = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (isMediaStreamActive() === false) {\r\n throw 'Please make sure MediaStream is active.';\r\n }\r\n\r\n if (!recording) {\r\n if (!config.disableLogs) {\r\n console.log('Seems recording has been restarted.');\r\n }\r\n this.record();\r\n return;\r\n }\r\n\r\n isPaused = false;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n config.checkForInactiveTracks = false;\r\n\r\n if (recording) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n\r\n clearRecordedDataCB();\r\n };\r\n\r\n function resetVariables() {\r\n leftchannel = [];\r\n rightchannel = [];\r\n recordingLength = 0;\r\n isAudioProcessStarted = false;\r\n recording = false;\r\n isPaused = false;\r\n context = null;\r\n\r\n self.leftchannel = leftchannel;\r\n self.rightchannel = rightchannel;\r\n self.numberOfAudioChannels = numberOfAudioChannels;\r\n self.desiredSampRate = desiredSampRate;\r\n self.sampleRate = sampleRate;\r\n self.recordingLength = recordingLength;\r\n\r\n intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n }\r\n\r\n function clearRecordedDataCB() {\r\n if (jsAudioNode) {\r\n jsAudioNode.onaudioprocess = null;\r\n jsAudioNode.disconnect();\r\n jsAudioNode = null;\r\n }\r\n\r\n if (audioInput) {\r\n audioInput.disconnect();\r\n audioInput = null;\r\n }\r\n\r\n resetVariables();\r\n }\r\n\r\n // for debugging\r\n this.name = 'StereoAudioRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var isAudioProcessStarted = false;\r\n\r\n function onAudioProcessDataAvailable(e) {\r\n if (isPaused) {\r\n return;\r\n }\r\n\r\n if (isMediaStreamActive() === false) {\r\n if (!config.disableLogs) {\r\n console.log('MediaStream seems stopped.');\r\n }\r\n jsAudioNode.disconnect();\r\n recording = false;\r\n }\r\n\r\n if (!recording) {\r\n if (audioInput) {\r\n audioInput.disconnect();\r\n audioInput = null;\r\n }\r\n return;\r\n }\r\n\r\n /**\r\n * This method is called on \"onaudioprocess\" event's first invocation.\r\n * @method {function} onAudioProcessStarted\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.onAudioProcessStarted: function() { };\r\n */\r\n if (!isAudioProcessStarted) {\r\n isAudioProcessStarted = true;\r\n if (config.onAudioProcessStarted) {\r\n config.onAudioProcessStarted();\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n }\r\n\r\n var left = e.inputBuffer.getChannelData(0);\r\n\r\n // we clone the samples\r\n var chLeft = new Float32Array(left);\r\n leftchannel.push(chLeft);\r\n\r\n if (numberOfAudioChannels === 2) {\r\n var right = e.inputBuffer.getChannelData(1);\r\n var chRight = new Float32Array(right);\r\n rightchannel.push(chRight);\r\n }\r\n\r\n recordingLength += bufferSize;\r\n\r\n // export raw PCM\r\n self.recordingLength = recordingLength;\r\n\r\n if (typeof config.timeSlice !== 'undefined') {\r\n intervalsBasedBuffers.recordingLength += bufferSize;\r\n intervalsBasedBuffers.left.push(chLeft);\r\n\r\n if (numberOfAudioChannels === 2) {\r\n intervalsBasedBuffers.right.push(chRight);\r\n }\r\n }\r\n }\r\n\r\n jsAudioNode.onaudioprocess = onAudioProcessDataAvailable;\r\n\r\n // to prevent self audio to be connected with speakers\r\n if (context.createMediaStreamDestination) {\r\n jsAudioNode.connect(context.createMediaStreamDestination());\r\n } else {\r\n jsAudioNode.connect(context.destination);\r\n }\r\n\r\n // export raw PCM\r\n this.leftchannel = leftchannel;\r\n this.rightchannel = rightchannel;\r\n this.numberOfAudioChannels = numberOfAudioChannels;\r\n this.desiredSampRate = desiredSampRate;\r\n this.sampleRate = sampleRate;\r\n self.recordingLength = recordingLength;\r\n\r\n // helper for intervals based blobs\r\n var intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n\r\n // this looper is used to support intervals based blobs (via timeSlice+ondataavailable)\r\n function looper() {\r\n if (!recording || typeof config.ondataavailable !== 'function' || typeof config.timeSlice === 'undefined') {\r\n return;\r\n }\r\n\r\n if (intervalsBasedBuffers.left.length) {\r\n mergeLeftRightBuffers({\r\n desiredSampRate: desiredSampRate,\r\n sampleRate: sampleRate,\r\n numberOfAudioChannels: numberOfAudioChannels,\r\n internalInterleavedLength: intervalsBasedBuffers.recordingLength,\r\n leftBuffers: intervalsBasedBuffers.left,\r\n rightBuffers: numberOfAudioChannels === 1 ? [] : intervalsBasedBuffers.right\r\n }, function(buffer, view) {\r\n var blob = new Blob([view], {\r\n type: 'audio/wav'\r\n });\r\n config.ondataavailable(blob);\r\n\r\n setTimeout(looper, config.timeSlice);\r\n });\r\n\r\n intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n } else {\r\n setTimeout(looper, config.timeSlice);\r\n }\r\n }\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.StereoAudioRecorder = StereoAudioRecorder;\r\n}\r\n\r\n// _________________\r\n// CanvasRecorder.js\r\n\r\n/**\r\n * CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}.\r\n * @summary HTML2Canvas recording into video WebM.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef CanvasRecorder\r\n * @class\r\n * @example\r\n * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc.\r\n * @param {object} config - {disableLogs:true, initCallback: function}\r\n */\r\n\r\nfunction CanvasRecorder(htmlElement, config) {\r\n if (typeof html2canvas === 'undefined') {\r\n throw 'Please link: https://www.webrtc-experiment.com/screenshot.js';\r\n }\r\n\r\n config = config || {};\r\n if (!config.frameInterval) {\r\n config.frameInterval = 10;\r\n }\r\n\r\n // via DetectRTC.js\r\n var isCanvasSupportsStreamCapturing = false;\r\n ['captureStream', 'mozCaptureStream', 'webkitCaptureStream'].forEach(function(item) {\r\n if (item in document.createElement('canvas')) {\r\n isCanvasSupportsStreamCapturing = true;\r\n }\r\n });\r\n\r\n var _isChrome = (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) && !!window.chrome;\r\n\r\n var chromeVersion = 50;\r\n var matchArray = navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\r\n if (_isChrome && matchArray && matchArray[2]) {\r\n chromeVersion = parseInt(matchArray[2], 10);\r\n }\r\n\r\n if (_isChrome && chromeVersion < 52) {\r\n isCanvasSupportsStreamCapturing = false;\r\n }\r\n\r\n if (config.useWhammyRecorder) {\r\n isCanvasSupportsStreamCapturing = false;\r\n }\r\n\r\n var globalCanvas, mediaStreamRecorder;\r\n\r\n if (isCanvasSupportsStreamCapturing) {\r\n if (!config.disableLogs) {\r\n console.log('Your browser supports both MediRecorder API and canvas.captureStream!');\r\n }\r\n\r\n if (htmlElement instanceof HTMLCanvasElement) {\r\n globalCanvas = htmlElement;\r\n } else if (htmlElement instanceof CanvasRenderingContext2D) {\r\n globalCanvas = htmlElement.canvas;\r\n } else {\r\n throw 'Please pass either HTMLCanvasElement or CanvasRenderingContext2D.';\r\n }\r\n } else if (!!navigator.mozGetUserMedia) {\r\n if (!config.disableLogs) {\r\n console.error('Canvas recording is NOT supported in Firefox.');\r\n }\r\n }\r\n\r\n var isRecording;\r\n\r\n /**\r\n * This method records Canvas.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n isRecording = true;\r\n\r\n if (isCanvasSupportsStreamCapturing && !config.useWhammyRecorder) {\r\n // CanvasCaptureMediaStream\r\n var canvasMediaStream;\r\n if ('captureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.captureStream(25); // 25 FPS\r\n } else if ('mozCaptureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.mozCaptureStream(25);\r\n } else if ('webkitCaptureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.webkitCaptureStream(25);\r\n }\r\n\r\n try {\r\n var mdStream = new MediaStream();\r\n mdStream.addTrack(getTracks(canvasMediaStream, 'video')[0]);\r\n canvasMediaStream = mdStream;\r\n } catch (e) {}\r\n\r\n if (!canvasMediaStream) {\r\n throw 'captureStream API are NOT available.';\r\n }\r\n\r\n // Note: Jan 18, 2016 status is that, \r\n // Firefox MediaRecorder API can't record CanvasCaptureMediaStream object.\r\n mediaStreamRecorder = new MediaStreamRecorder(canvasMediaStream, {\r\n mimeType: config.mimeType || 'video/webm'\r\n });\r\n mediaStreamRecorder.record();\r\n } else {\r\n whammy.frames = [];\r\n lastTime = new Date().getTime();\r\n drawCanvasFrame();\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n this.getWebPImages = function(callback) {\r\n if (htmlElement.nodeName.toLowerCase() !== 'canvas') {\r\n callback();\r\n return;\r\n }\r\n\r\n var framesLength = whammy.frames.length;\r\n whammy.frames.forEach(function(frame, idx) {\r\n var framesRemaining = framesLength - idx;\r\n if (!config.disableLogs) {\r\n console.log(framesRemaining + '/' + framesLength + ' frames remaining');\r\n }\r\n\r\n if (config.onEncodingCallback) {\r\n config.onEncodingCallback(framesRemaining, framesLength);\r\n }\r\n\r\n var webp = frame.image.toDataURL('image/webp', 1);\r\n whammy.frames[idx].image = webp;\r\n });\r\n\r\n if (!config.disableLogs) {\r\n console.log('Generating WebM');\r\n }\r\n\r\n callback();\r\n };\r\n\r\n /**\r\n * This method stops recording Canvas.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n isRecording = false;\r\n\r\n var that = this;\r\n\r\n if (isCanvasSupportsStreamCapturing && mediaStreamRecorder) {\r\n mediaStreamRecorder.stop(callback);\r\n return;\r\n }\r\n\r\n this.getWebPImages(function() {\r\n /**\r\n * @property {Blob} blob - Recorded frames in video/webm blob.\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n whammy.compile(function(blob) {\r\n if (!config.disableLogs) {\r\n console.log('Recording finished!');\r\n }\r\n\r\n that.blob = blob;\r\n\r\n if (that.blob.forEach) {\r\n that.blob = new Blob([], {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n if (callback) {\r\n callback(that.blob);\r\n }\r\n\r\n whammy.frames = [];\r\n });\r\n });\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n\r\n if (mediaStreamRecorder instanceof MediaStreamRecorder) {\r\n mediaStreamRecorder.pause();\r\n return;\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n\r\n if (mediaStreamRecorder instanceof MediaStreamRecorder) {\r\n mediaStreamRecorder.resume();\r\n return;\r\n }\r\n\r\n if (!isRecording) {\r\n this.record();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (isRecording) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n whammy.frames = [];\r\n isRecording = false;\r\n isPausedRecording = false;\r\n }\r\n\r\n // for debugging\r\n this.name = 'CanvasRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n function cloneCanvas() {\r\n //create a new canvas\r\n var newCanvas = document.createElement('canvas');\r\n var context = newCanvas.getContext('2d');\r\n\r\n //set dimensions\r\n newCanvas.width = htmlElement.width;\r\n newCanvas.height = htmlElement.height;\r\n\r\n //apply the old canvas to the new one\r\n context.drawImage(htmlElement, 0, 0);\r\n\r\n //return the new canvas\r\n return newCanvas;\r\n }\r\n\r\n function drawCanvasFrame() {\r\n if (isPausedRecording) {\r\n lastTime = new Date().getTime();\r\n return setTimeout(drawCanvasFrame, 500);\r\n }\r\n\r\n if (htmlElement.nodeName.toLowerCase() === 'canvas') {\r\n var duration = new Date().getTime() - lastTime;\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n whammy.frames.push({\r\n image: cloneCanvas(),\r\n duration: duration\r\n });\r\n\r\n if (isRecording) {\r\n setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n return;\r\n }\r\n\r\n html2canvas(htmlElement, {\r\n grabMouse: typeof config.showMousePointer === 'undefined' || config.showMousePointer,\r\n onrendered: function(canvas) {\r\n var duration = new Date().getTime() - lastTime;\r\n if (!duration) {\r\n return setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n whammy.frames.push({\r\n image: canvas.toDataURL('image/webp', 1),\r\n duration: duration\r\n });\r\n\r\n if (isRecording) {\r\n setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n }\r\n });\r\n }\r\n\r\n var lastTime = new Date().getTime();\r\n\r\n var whammy = new Whammy.Video(100);\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.CanvasRecorder = CanvasRecorder;\r\n}\n\r\n// _________________\r\n// WhammyRecorder.js\r\n\r\n/**\r\n * WhammyRecorder is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It runs top over {@link Whammy}.\r\n * @summary Video recording feature in Chrome.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef WhammyRecorder\r\n * @class\r\n * @example\r\n * var recorder = new WhammyRecorder(mediaStream);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {disableLogs: true, initCallback: function, video: HTMLVideoElement, etc.}\r\n */\r\n\r\nfunction WhammyRecorder(mediaStream, config) {\r\n\r\n config = config || {};\r\n\r\n if (!config.frameInterval) {\r\n config.frameInterval = 10;\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('Using frames-interval:', config.frameInterval);\r\n }\r\n\r\n /**\r\n * This method records video.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (!config.width) {\r\n config.width = 320;\r\n }\r\n\r\n if (!config.height) {\r\n config.height = 240;\r\n }\r\n\r\n if (!config.video) {\r\n config.video = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n if (!config.canvas) {\r\n config.canvas = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n canvas.width = config.canvas.width || 320;\r\n canvas.height = config.canvas.height || 240;\r\n\r\n context = canvas.getContext('2d');\r\n\r\n // setting defaults\r\n if (config.video && config.video instanceof HTMLVideoElement) {\r\n video = config.video.cloneNode();\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n } else {\r\n video = document.createElement('video');\r\n\r\n setSrcObject(mediaStream, video);\r\n\r\n video.onloadedmetadata = function() { // \"onloadedmetadata\" may NOT work in FF?\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n video.width = config.video.width;\r\n video.height = config.video.height;\r\n }\r\n\r\n video.muted = true;\r\n video.play();\r\n\r\n lastTime = new Date().getTime();\r\n whammy = new Whammy.Video();\r\n\r\n if (!config.disableLogs) {\r\n console.log('canvas resolutions', canvas.width, '*', canvas.height);\r\n console.log('video width/height', video.width || canvas.width, '*', video.height || canvas.height);\r\n }\r\n\r\n drawFrames(config.frameInterval);\r\n };\r\n\r\n /**\r\n * Draw and push frames to Whammy\r\n * @param {integer} frameInterval - set minimum interval (in milliseconds) between each time we push a frame to Whammy\r\n */\r\n function drawFrames(frameInterval) {\r\n frameInterval = typeof frameInterval !== 'undefined' ? frameInterval : 10;\r\n\r\n var duration = new Date().getTime() - lastTime;\r\n if (!duration) {\r\n return setTimeout(drawFrames, frameInterval, frameInterval);\r\n }\r\n\r\n if (isPausedRecording) {\r\n lastTime = new Date().getTime();\r\n return setTimeout(drawFrames, 100);\r\n }\r\n\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n if (video.paused) {\r\n // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316\r\n // Tweak for Android Chrome\r\n video.play();\r\n }\r\n\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n whammy.frames.push({\r\n duration: duration,\r\n image: canvas.toDataURL('image/webp')\r\n });\r\n\r\n if (!isStopDrawing) {\r\n setTimeout(drawFrames, frameInterval, frameInterval);\r\n }\r\n }\r\n\r\n function asyncLoop(o) {\r\n var i = -1,\r\n length = o.length;\r\n\r\n (function loop() {\r\n i++;\r\n if (i === length) {\r\n o.callback();\r\n return;\r\n }\r\n\r\n // \"setTimeout\" added by Jim McLeod\r\n setTimeout(function() {\r\n o.functionToLoop(loop, i);\r\n }, 1);\r\n })();\r\n }\r\n\r\n\r\n /**\r\n * remove black frames from the beginning to the specified frame\r\n * @param {Array} _frames - array of frames to be checked\r\n * @param {number} _framesToCheck - number of frame until check will be executed (-1 - will drop all frames until frame not matched will be found)\r\n * @param {number} _pixTolerance - 0 - very strict (only black pixel color) ; 1 - all\r\n * @param {number} _frameTolerance - 0 - very strict (only black frame color) ; 1 - all\r\n * @returns {Array} - array of frames\r\n */\r\n // pull#293 by @volodalexey\r\n function dropBlackFrames(_frames, _framesToCheck, _pixTolerance, _frameTolerance, callback) {\r\n var localCanvas = document.createElement('canvas');\r\n localCanvas.width = canvas.width;\r\n localCanvas.height = canvas.height;\r\n var context2d = localCanvas.getContext('2d');\r\n var resultFrames = [];\r\n\r\n var checkUntilNotBlack = _framesToCheck === -1;\r\n var endCheckFrame = (_framesToCheck && _framesToCheck > 0 && _framesToCheck <= _frames.length) ?\r\n _framesToCheck : _frames.length;\r\n var sampleColor = {\r\n r: 0,\r\n g: 0,\r\n b: 0\r\n };\r\n var maxColorDifference = Math.sqrt(\r\n Math.pow(255, 2) +\r\n Math.pow(255, 2) +\r\n Math.pow(255, 2)\r\n );\r\n var pixTolerance = _pixTolerance && _pixTolerance >= 0 && _pixTolerance <= 1 ? _pixTolerance : 0;\r\n var frameTolerance = _frameTolerance && _frameTolerance >= 0 && _frameTolerance <= 1 ? _frameTolerance : 0;\r\n var doNotCheckNext = false;\r\n\r\n asyncLoop({\r\n length: endCheckFrame,\r\n functionToLoop: function(loop, f) {\r\n var matchPixCount, endPixCheck, maxPixCount;\r\n\r\n var finishImage = function() {\r\n if (!doNotCheckNext && maxPixCount - matchPixCount <= maxPixCount * frameTolerance) {\r\n // console.log('removed black frame : ' + f + ' ; frame duration ' + _frames[f].duration);\r\n } else {\r\n // console.log('frame is passed : ' + f);\r\n if (checkUntilNotBlack) {\r\n doNotCheckNext = true;\r\n }\r\n resultFrames.push(_frames[f]);\r\n }\r\n loop();\r\n };\r\n\r\n if (!doNotCheckNext) {\r\n var image = new Image();\r\n image.onload = function() {\r\n context2d.drawImage(image, 0, 0, canvas.width, canvas.height);\r\n var imageData = context2d.getImageData(0, 0, canvas.width, canvas.height);\r\n matchPixCount = 0;\r\n endPixCheck = imageData.data.length;\r\n maxPixCount = imageData.data.length / 4;\r\n\r\n for (var pix = 0; pix < endPixCheck; pix += 4) {\r\n var currentColor = {\r\n r: imageData.data[pix],\r\n g: imageData.data[pix + 1],\r\n b: imageData.data[pix + 2]\r\n };\r\n var colorDifference = Math.sqrt(\r\n Math.pow(currentColor.r - sampleColor.r, 2) +\r\n Math.pow(currentColor.g - sampleColor.g, 2) +\r\n Math.pow(currentColor.b - sampleColor.b, 2)\r\n );\r\n // difference in color it is difference in color vectors (r1,g1,b1) <=> (r2,g2,b2)\r\n if (colorDifference <= maxColorDifference * pixTolerance) {\r\n matchPixCount++;\r\n }\r\n }\r\n finishImage();\r\n };\r\n image.src = _frames[f].image;\r\n } else {\r\n finishImage();\r\n }\r\n },\r\n callback: function() {\r\n resultFrames = resultFrames.concat(_frames.slice(endCheckFrame));\r\n\r\n if (resultFrames.length <= 0) {\r\n // at least one last frame should be available for next manipulation\r\n // if total duration of all frames will be < 1000 than ffmpeg doesn't work well...\r\n resultFrames.push(_frames[_frames.length - 1]);\r\n }\r\n callback(resultFrames);\r\n }\r\n });\r\n }\r\n\r\n var isStopDrawing = false;\r\n\r\n /**\r\n * This method stops recording video.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n isStopDrawing = true;\r\n\r\n var _this = this;\r\n // analyse of all frames takes some time!\r\n setTimeout(function() {\r\n // e.g. dropBlackFrames(frames, 10, 1, 1) - will cut all 10 frames\r\n // e.g. dropBlackFrames(frames, 10, 0.5, 0.5) - will analyse 10 frames\r\n // e.g. dropBlackFrames(frames, 10) === dropBlackFrames(frames, 10, 0, 0) - will analyse 10 frames with strict black color\r\n dropBlackFrames(whammy.frames, -1, null, null, function(frames) {\r\n whammy.frames = frames;\r\n\r\n // to display advertisement images!\r\n if (config.advertisement && config.advertisement.length) {\r\n whammy.frames = config.advertisement.concat(whammy.frames);\r\n }\r\n\r\n /**\r\n * @property {Blob} blob - Recorded frames in video/webm blob.\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n whammy.compile(function(blob) {\r\n _this.blob = blob;\r\n\r\n if (_this.blob.forEach) {\r\n _this.blob = new Blob([], {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n if (callback) {\r\n callback(_this.blob);\r\n }\r\n });\r\n });\r\n }, 10);\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n\r\n if (isStopDrawing) {\r\n this.record();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (!isStopDrawing) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n whammy.frames = [];\r\n isStopDrawing = true;\r\n isPausedRecording = false;\r\n }\r\n\r\n // for debugging\r\n this.name = 'WhammyRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n\r\n var video;\r\n var lastTime;\r\n var whammy;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.WhammyRecorder = WhammyRecorder;\r\n}\n\r\n// https://github.com/antimatter15/whammy/blob/master/LICENSE\r\n// _________\r\n// Whammy.js\r\n\r\n// todo: Firefox now supports webp for webm containers!\r\n// their MediaRecorder implementation works well!\r\n// should we provide an option to record via Whammy.js or MediaRecorder API is a better solution?\r\n\r\n/**\r\n * Whammy is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It is written by {@link https://github.com/antimatter15|antimatter15}\r\n * @summary A real time javascript webm encoder based on a canvas hack.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef Whammy\r\n * @class\r\n * @example\r\n * var recorder = new Whammy().Video(15);\r\n * recorder.add(context || canvas || dataURL);\r\n * var output = recorder.compile();\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\nvar Whammy = (function() {\r\n // a more abstract-ish API\r\n\r\n function WhammyVideo(duration) {\r\n this.frames = [];\r\n this.duration = duration || 1;\r\n this.quality = 0.8;\r\n }\r\n\r\n /**\r\n * Pass Canvas or Context or image/webp(string) to {@link Whammy} encoder.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * recorder.add(canvas || context || 'image/webp');\r\n * @param {string} frame - Canvas || Context || image/webp\r\n * @param {number} duration - Stick a duration (in milliseconds)\r\n */\r\n WhammyVideo.prototype.add = function(frame, duration) {\r\n if ('canvas' in frame) { //CanvasRenderingContext2D\r\n frame = frame.canvas;\r\n }\r\n\r\n if ('toDataURL' in frame) {\r\n frame = frame.toDataURL('image/webp', this.quality);\r\n }\r\n\r\n if (!(/^data:image\\/webp;base64,/ig).test(frame)) {\r\n throw 'Input must be formatted properly as a base64 encoded DataURI of type image/webp';\r\n }\r\n this.frames.push({\r\n image: frame,\r\n duration: duration || this.duration\r\n });\r\n };\r\n\r\n function processInWebWorker(_function) {\r\n var blob = URL.createObjectURL(new Blob([_function.toString(),\r\n 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(blob);\r\n URL.revokeObjectURL(blob);\r\n return worker;\r\n }\r\n\r\n function whammyInWebWorker(frames) {\r\n function ArrayToWebM(frames) {\r\n var info = checkFrames(frames);\r\n if (!info) {\r\n return [];\r\n }\r\n\r\n var clusterMaxDuration = 30000;\r\n\r\n var EBML = [{\r\n 'id': 0x1a45dfa3, // EBML\r\n 'data': [{\r\n 'data': 1,\r\n 'id': 0x4286 // EBMLVersion\r\n }, {\r\n 'data': 1,\r\n 'id': 0x42f7 // EBMLReadVersion\r\n }, {\r\n 'data': 4,\r\n 'id': 0x42f2 // EBMLMaxIDLength\r\n }, {\r\n 'data': 8,\r\n 'id': 0x42f3 // EBMLMaxSizeLength\r\n }, {\r\n 'data': 'webm',\r\n 'id': 0x4282 // DocType\r\n }, {\r\n 'data': 2,\r\n 'id': 0x4287 // DocTypeVersion\r\n }, {\r\n 'data': 2,\r\n 'id': 0x4285 // DocTypeReadVersion\r\n }]\r\n }, {\r\n 'id': 0x18538067, // Segment\r\n 'data': [{\r\n 'id': 0x1549a966, // Info\r\n 'data': [{\r\n 'data': 1e6, //do things in millisecs (num of nanosecs for duration scale)\r\n 'id': 0x2ad7b1 // TimecodeScale\r\n }, {\r\n 'data': 'whammy',\r\n 'id': 0x4d80 // MuxingApp\r\n }, {\r\n 'data': 'whammy',\r\n 'id': 0x5741 // WritingApp\r\n }, {\r\n 'data': doubleToString(info.duration),\r\n 'id': 0x4489 // Duration\r\n }]\r\n }, {\r\n 'id': 0x1654ae6b, // Tracks\r\n 'data': [{\r\n 'id': 0xae, // TrackEntry\r\n 'data': [{\r\n 'data': 1,\r\n 'id': 0xd7 // TrackNumber\r\n }, {\r\n 'data': 1,\r\n 'id': 0x73c5 // TrackUID\r\n }, {\r\n 'data': 0,\r\n 'id': 0x9c // FlagLacing\r\n }, {\r\n 'data': 'und',\r\n 'id': 0x22b59c // Language\r\n }, {\r\n 'data': 'V_VP8',\r\n 'id': 0x86 // CodecID\r\n }, {\r\n 'data': 'VP8',\r\n 'id': 0x258688 // CodecName\r\n }, {\r\n 'data': 1,\r\n 'id': 0x83 // TrackType\r\n }, {\r\n 'id': 0xe0, // Video\r\n 'data': [{\r\n 'data': info.width,\r\n 'id': 0xb0 // PixelWidth\r\n }, {\r\n 'data': info.height,\r\n 'id': 0xba // PixelHeight\r\n }]\r\n }]\r\n }]\r\n }]\r\n }];\r\n\r\n //Generate clusters (max duration)\r\n var frameNumber = 0;\r\n var clusterTimecode = 0;\r\n while (frameNumber < frames.length) {\r\n\r\n var clusterFrames = [];\r\n var clusterDuration = 0;\r\n do {\r\n clusterFrames.push(frames[frameNumber]);\r\n clusterDuration += frames[frameNumber].duration;\r\n frameNumber++;\r\n } while (frameNumber < frames.length && clusterDuration < clusterMaxDuration);\r\n\r\n var clusterCounter = 0;\r\n var cluster = {\r\n 'id': 0x1f43b675, // Cluster\r\n 'data': getClusterData(clusterTimecode, clusterCounter, clusterFrames)\r\n }; //Add cluster to segment\r\n EBML[1].data.push(cluster);\r\n clusterTimecode += clusterDuration;\r\n }\r\n\r\n return generateEBML(EBML);\r\n }\r\n\r\n function getClusterData(clusterTimecode, clusterCounter, clusterFrames) {\r\n return [{\r\n 'data': clusterTimecode,\r\n 'id': 0xe7 // Timecode\r\n }].concat(clusterFrames.map(function(webp) {\r\n var block = makeSimpleBlock({\r\n discardable: 0,\r\n frame: webp.data.slice(4),\r\n invisible: 0,\r\n keyframe: 1,\r\n lacing: 0,\r\n trackNum: 1,\r\n timecode: Math.round(clusterCounter)\r\n });\r\n clusterCounter += webp.duration;\r\n return {\r\n data: block,\r\n id: 0xa3\r\n };\r\n }));\r\n }\r\n\r\n // sums the lengths of all the frames and gets the duration\r\n\r\n function checkFrames(frames) {\r\n if (!frames[0]) {\r\n postMessage({\r\n error: 'Something went wrong. Maybe WebP format is not supported in the current browser.'\r\n });\r\n return;\r\n }\r\n\r\n var width = frames[0].width,\r\n height = frames[0].height,\r\n duration = frames[0].duration;\r\n\r\n for (var i = 1; i < frames.length; i++) {\r\n duration += frames[i].duration;\r\n }\r\n return {\r\n duration: duration,\r\n width: width,\r\n height: height\r\n };\r\n }\r\n\r\n function numToBuffer(num) {\r\n var parts = [];\r\n while (num > 0) {\r\n parts.push(num & 0xff);\r\n num = num >> 8;\r\n }\r\n return new Uint8Array(parts.reverse());\r\n }\r\n\r\n function strToBuffer(str) {\r\n return new Uint8Array(str.split('').map(function(e) {\r\n return e.charCodeAt(0);\r\n }));\r\n }\r\n\r\n function bitsToBuffer(bits) {\r\n var data = [];\r\n var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : '';\r\n bits = pad + bits;\r\n for (var i = 0; i < bits.length; i += 8) {\r\n data.push(parseInt(bits.substr(i, 8), 2));\r\n }\r\n return new Uint8Array(data);\r\n }\r\n\r\n function generateEBML(json) {\r\n var ebml = [];\r\n for (var i = 0; i < json.length; i++) {\r\n var data = json[i].data;\r\n\r\n if (typeof data === 'object') {\r\n data = generateEBML(data);\r\n }\r\n\r\n if (typeof data === 'number') {\r\n data = bitsToBuffer(data.toString(2));\r\n }\r\n\r\n if (typeof data === 'string') {\r\n data = strToBuffer(data);\r\n }\r\n\r\n var len = data.size || data.byteLength || data.length;\r\n var zeroes = Math.ceil(Math.ceil(Math.log(len) / Math.log(2)) / 8);\r\n var sizeToString = len.toString(2);\r\n var padded = (new Array((zeroes * 7 + 7 + 1) - sizeToString.length)).join('0') + sizeToString;\r\n var size = (new Array(zeroes)).join('0') + '1' + padded;\r\n\r\n ebml.push(numToBuffer(json[i].id));\r\n ebml.push(bitsToBuffer(size));\r\n ebml.push(data);\r\n }\r\n\r\n return new Blob(ebml, {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n function toBinStrOld(bits) {\r\n var data = '';\r\n var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : '';\r\n bits = pad + bits;\r\n for (var i = 0; i < bits.length; i += 8) {\r\n data += String.fromCharCode(parseInt(bits.substr(i, 8), 2));\r\n }\r\n return data;\r\n }\r\n\r\n function makeSimpleBlock(data) {\r\n var flags = 0;\r\n\r\n if (data.keyframe) {\r\n flags |= 128;\r\n }\r\n\r\n if (data.invisible) {\r\n flags |= 8;\r\n }\r\n\r\n if (data.lacing) {\r\n flags |= (data.lacing << 1);\r\n }\r\n\r\n if (data.discardable) {\r\n flags |= 1;\r\n }\r\n\r\n if (data.trackNum > 127) {\r\n throw 'TrackNumber > 127 not supported';\r\n }\r\n\r\n var out = [data.trackNum | 0x80, data.timecode >> 8, data.timecode & 0xff, flags].map(function(e) {\r\n return String.fromCharCode(e);\r\n }).join('') + data.frame;\r\n\r\n return out;\r\n }\r\n\r\n function parseWebP(riff) {\r\n var VP8 = riff.RIFF[0].WEBP[0];\r\n\r\n var frameStart = VP8.indexOf('\\x9d\\x01\\x2a'); // A VP8 keyframe starts with the 0x9d012a header\r\n for (var i = 0, c = []; i < 4; i++) {\r\n c[i] = VP8.charCodeAt(frameStart + 3 + i);\r\n }\r\n\r\n var width, height, tmp;\r\n\r\n //the code below is literally copied verbatim from the bitstream spec\r\n tmp = (c[1] << 8) | c[0];\r\n width = tmp & 0x3FFF;\r\n tmp = (c[3] << 8) | c[2];\r\n height = tmp & 0x3FFF;\r\n return {\r\n width: width,\r\n height: height,\r\n data: VP8,\r\n riff: riff\r\n };\r\n }\r\n\r\n function getStrLength(string, offset) {\r\n return parseInt(string.substr(offset + 4, 4).split('').map(function(i) {\r\n var unpadded = i.charCodeAt(0).toString(2);\r\n return (new Array(8 - unpadded.length + 1)).join('0') + unpadded;\r\n }).join(''), 2);\r\n }\r\n\r\n function parseRIFF(string) {\r\n var offset = 0;\r\n var chunks = {};\r\n\r\n while (offset < string.length) {\r\n var id = string.substr(offset, 4);\r\n var len = getStrLength(string, offset);\r\n var data = string.substr(offset + 4 + 4, len);\r\n offset += 4 + 4 + len;\r\n chunks[id] = chunks[id] || [];\r\n\r\n if (id === 'RIFF' || id === 'LIST') {\r\n chunks[id].push(parseRIFF(data));\r\n } else {\r\n chunks[id].push(data);\r\n }\r\n }\r\n return chunks;\r\n }\r\n\r\n function doubleToString(num) {\r\n return [].slice.call(\r\n new Uint8Array((new Float64Array([num])).buffer), 0).map(function(e) {\r\n return String.fromCharCode(e);\r\n }).reverse().join('');\r\n }\r\n\r\n var webm = new ArrayToWebM(frames.map(function(frame) {\r\n var webp = parseWebP(parseRIFF(atob(frame.image.slice(23))));\r\n webp.duration = frame.duration;\r\n return webp;\r\n }));\r\n\r\n postMessage(webm);\r\n }\r\n\r\n /**\r\n * Encodes frames in WebM container. It uses WebWorkinvoke to invoke 'ArrayToWebM' method.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * recorder.compile(function(blob) {\r\n * // blob.size - blob.type\r\n * });\r\n */\r\n WhammyVideo.prototype.compile = function(callback) {\r\n var webWorker = processInWebWorker(whammyInWebWorker);\r\n\r\n webWorker.onmessage = function(event) {\r\n if (event.data.error) {\r\n console.error(event.data.error);\r\n return;\r\n }\r\n callback(event.data);\r\n };\r\n\r\n webWorker.postMessage(this.frames);\r\n };\r\n\r\n return {\r\n /**\r\n * A more abstract-ish API.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * @param {?number} speed - 0.8\r\n * @param {?number} quality - 100\r\n */\r\n Video: WhammyVideo\r\n };\r\n})();\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.Whammy = Whammy;\r\n}\n\r\n// ______________ (indexed-db)\r\n// DiskStorage.js\r\n\r\n/**\r\n * DiskStorage is a standalone object used by {@link RecordRTC} to store recorded blobs in IndexedDB storage.\r\n * @summary Writing blobs into IndexedDB.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @example\r\n * DiskStorage.Store({\r\n * audioBlob: yourAudioBlob,\r\n * videoBlob: yourVideoBlob,\r\n * gifBlob : yourGifBlob\r\n * });\r\n * DiskStorage.Fetch(function(dataURL, type) {\r\n * if(type === 'audioBlob') { }\r\n * if(type === 'videoBlob') { }\r\n * if(type === 'gifBlob') { }\r\n * });\r\n * // DiskStorage.dataStoreName = 'recordRTC';\r\n * // DiskStorage.onError = function(error) { };\r\n * @property {function} init - This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally.\r\n * @property {function} Fetch - This method fetches stored blobs from IndexedDB.\r\n * @property {function} Store - This method stores blobs in IndexedDB.\r\n * @property {function} onError - This function is invoked for any known/unknown error.\r\n * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage.\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\n\r\nvar DiskStorage = {\r\n /**\r\n * This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.init();\r\n */\r\n init: function() {\r\n var self = this;\r\n\r\n if (typeof indexedDB === 'undefined' || typeof indexedDB.open === 'undefined') {\r\n console.error('IndexedDB API are not available in this browser.');\r\n return;\r\n }\r\n\r\n var dbVersion = 1;\r\n var dbName = this.dbName || location.href.replace(/\\/|:|#|%|\\.|\\[|\\]/g, ''),\r\n db;\r\n var request = indexedDB.open(dbName, dbVersion);\r\n\r\n function createObjectStore(dataBase) {\r\n dataBase.createObjectStore(self.dataStoreName);\r\n }\r\n\r\n function putInDB() {\r\n var transaction = db.transaction([self.dataStoreName], 'readwrite');\r\n\r\n if (self.videoBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.videoBlob, 'videoBlob');\r\n }\r\n\r\n if (self.gifBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.gifBlob, 'gifBlob');\r\n }\r\n\r\n if (self.audioBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.audioBlob, 'audioBlob');\r\n }\r\n\r\n function getFromStore(portionName) {\r\n transaction.objectStore(self.dataStoreName).get(portionName).onsuccess = function(event) {\r\n if (self.callback) {\r\n self.callback(event.target.result, portionName);\r\n }\r\n };\r\n }\r\n\r\n getFromStore('audioBlob');\r\n getFromStore('videoBlob');\r\n getFromStore('gifBlob');\r\n }\r\n\r\n request.onerror = self.onError;\r\n\r\n request.onsuccess = function() {\r\n db = request.result;\r\n db.onerror = self.onError;\r\n\r\n if (db.setVersion) {\r\n if (db.version !== dbVersion) {\r\n var setVersion = db.setVersion(dbVersion);\r\n setVersion.onsuccess = function() {\r\n createObjectStore(db);\r\n putInDB();\r\n };\r\n } else {\r\n putInDB();\r\n }\r\n } else {\r\n putInDB();\r\n }\r\n };\r\n request.onupgradeneeded = function(event) {\r\n createObjectStore(event.target.result);\r\n };\r\n },\r\n /**\r\n * This method fetches stored blobs from IndexedDB.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.Fetch(function(dataURL, type) {\r\n * if(type === 'audioBlob') { }\r\n * if(type === 'videoBlob') { }\r\n * if(type === 'gifBlob') { }\r\n * });\r\n */\r\n Fetch: function(callback) {\r\n this.callback = callback;\r\n this.init();\r\n\r\n return this;\r\n },\r\n /**\r\n * This method stores blobs in IndexedDB.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.Store({\r\n * audioBlob: yourAudioBlob,\r\n * videoBlob: yourVideoBlob,\r\n * gifBlob : yourGifBlob\r\n * });\r\n */\r\n Store: function(config) {\r\n this.audioBlob = config.audioBlob;\r\n this.videoBlob = config.videoBlob;\r\n this.gifBlob = config.gifBlob;\r\n\r\n this.init();\r\n\r\n return this;\r\n },\r\n /**\r\n * This function is invoked for any known/unknown error.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.onError = function(error){\r\n * alerot( JSON.stringify(error) );\r\n * };\r\n */\r\n onError: function(error) {\r\n console.error(JSON.stringify(error, null, '\\t'));\r\n },\r\n\r\n /**\r\n * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage.\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.dataStoreName = 'recordRTC';\r\n */\r\n dataStoreName: 'recordRTC',\r\n dbName: null\r\n};\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.DiskStorage = DiskStorage;\r\n}\n\r\n// ______________\r\n// GifRecorder.js\r\n\r\n/**\r\n * GifRecorder is standalone calss used by {@link RecordRTC} to record video or canvas into animated gif.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef GifRecorder\r\n * @class\r\n * @example\r\n * var recorder = new GifRecorder(mediaStream || canvas || context, { onGifPreview: function, onGifRecordingStarted: function, width: 1280, height: 720, frameRate: 200, quality: 10 });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * img.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object or HTMLCanvasElement or CanvasRenderingContext2D.\r\n * @param {object} config - {disableLogs:true, initCallback: function, width: 320, height: 240, frameRate: 200, quality: 10}\r\n */\r\n\r\nfunction GifRecorder(mediaStream, config) {\r\n if (typeof GIFEncoder === 'undefined') {\r\n var script = document.createElement('script');\r\n script.src = 'https://www.webrtc-experiment.com/gif-recorder.js';\r\n (document.body || document.documentElement).appendChild(script);\r\n }\r\n\r\n config = config || {};\r\n\r\n var isHTMLObject = mediaStream instanceof CanvasRenderingContext2D || mediaStream instanceof HTMLCanvasElement;\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (typeof GIFEncoder === 'undefined') {\r\n setTimeout(self.record, 1000);\r\n return;\r\n }\r\n\r\n if (!isLoadedMetaData) {\r\n setTimeout(self.record, 1000);\r\n return;\r\n }\r\n\r\n if (!isHTMLObject) {\r\n if (!config.width) {\r\n config.width = video.offsetWidth || 320;\r\n }\r\n\r\n if (!config.height) {\r\n config.height = video.offsetHeight || 240;\r\n }\r\n\r\n if (!config.video) {\r\n config.video = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n if (!config.canvas) {\r\n config.canvas = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n canvas.width = config.canvas.width || 320;\r\n canvas.height = config.canvas.height || 240;\r\n\r\n video.width = config.video.width || 320;\r\n video.height = config.video.height || 240;\r\n }\r\n\r\n // external library to record as GIF images\r\n gifEncoder = new GIFEncoder();\r\n\r\n // void setRepeat(int iter) \r\n // Sets the number of times the set of GIF frames should be played. \r\n // Default is 1; 0 means play indefinitely.\r\n gifEncoder.setRepeat(0);\r\n\r\n // void setFrameRate(Number fps) \r\n // Sets frame rate in frames per second. \r\n // Equivalent to setDelay(1000/fps).\r\n // Using \"setDelay\" instead of \"setFrameRate\"\r\n gifEncoder.setDelay(config.frameRate || 200);\r\n\r\n // void setQuality(int quality) \r\n // Sets quality of color quantization (conversion of images to the \r\n // maximum 256 colors allowed by the GIF specification). \r\n // Lower values (minimum = 1) produce better colors, \r\n // but slow processing significantly. 10 is the default, \r\n // and produces good color mapping at reasonable speeds. \r\n // Values greater than 20 do not yield significant improvements in speed.\r\n gifEncoder.setQuality(config.quality || 10);\r\n\r\n // Boolean start() \r\n // This writes the GIF Header and returns false if it fails.\r\n gifEncoder.start();\r\n\r\n if (typeof config.onGifRecordingStarted === 'function') {\r\n config.onGifRecordingStarted();\r\n }\r\n\r\n startTime = Date.now();\r\n\r\n function drawVideoFrame(time) {\r\n if (self.clearedRecordedData === true) {\r\n return;\r\n }\r\n\r\n if (isPausedRecording) {\r\n return setTimeout(function() {\r\n drawVideoFrame(time);\r\n }, 100);\r\n }\r\n\r\n lastAnimationFrame = requestAnimationFrame(drawVideoFrame);\r\n\r\n if (typeof lastFrameTime === undefined) {\r\n lastFrameTime = time;\r\n }\r\n\r\n // ~10 fps\r\n if (time - lastFrameTime < 90) {\r\n return;\r\n }\r\n\r\n if (!isHTMLObject && video.paused) {\r\n // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316\r\n // Tweak for Android Chrome\r\n video.play();\r\n }\r\n\r\n if (!isHTMLObject) {\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n if (config.onGifPreview) {\r\n config.onGifPreview(canvas.toDataURL('image/png'));\r\n }\r\n\r\n gifEncoder.addFrame(context);\r\n lastFrameTime = time;\r\n }\r\n\r\n lastAnimationFrame = requestAnimationFrame(drawVideoFrame);\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * img.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n if (lastAnimationFrame) {\r\n cancelAnimationFrame(lastAnimationFrame);\r\n }\r\n\r\n endTime = Date.now();\r\n\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = new Blob([new Uint8Array(gifEncoder.stream().bin)], {\r\n type: 'image/gif'\r\n });\r\n\r\n callback(this.blob);\r\n\r\n // bug: find a way to clear old recorded blobs\r\n gifEncoder.stream().bin = [];\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n self.clearedRecordedData = true;\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n if (gifEncoder) {\r\n gifEncoder.stream().bin = [];\r\n }\r\n }\r\n\r\n // for debugging\r\n this.name = 'GifRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n\r\n if (isHTMLObject) {\r\n if (mediaStream instanceof CanvasRenderingContext2D) {\r\n context = mediaStream;\r\n canvas = context.canvas;\r\n } else if (mediaStream instanceof HTMLCanvasElement) {\r\n context = mediaStream.getContext('2d');\r\n canvas = mediaStream;\r\n }\r\n }\r\n\r\n var isLoadedMetaData = true;\r\n\r\n if (!isHTMLObject) {\r\n var video = document.createElement('video');\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.playsInline = true;\r\n\r\n isLoadedMetaData = false;\r\n video.onloadedmetadata = function() {\r\n isLoadedMetaData = true;\r\n };\r\n\r\n setSrcObject(mediaStream, video);\r\n\r\n video.play();\r\n }\r\n\r\n var lastAnimationFrame = null;\r\n var startTime, endTime, lastFrameTime;\r\n\r\n var gifEncoder;\r\n\r\n var self = this;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.GifRecorder = GifRecorder;\r\n}\n\r\n// Last time updated: 2019-06-21 4:09:42 AM UTC\r\n\r\n// ________________________\r\n// MultiStreamsMixer v1.2.2\r\n\r\n// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer\r\n\r\n// --------------------------------------------------\r\n// Muaz Khan - www.MuazKhan.com\r\n// MIT License - www.WebRTC-Experiment.com/licence\r\n// --------------------------------------------------\r\n\r\nfunction MultiStreamsMixer(arrayOfMediaStreams, elementClass) {\r\n\r\n var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45';\r\n\r\n (function(that) {\r\n if (typeof RecordRTC !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (!that) {\r\n return;\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (typeof global === 'undefined') {\r\n return;\r\n }\r\n\r\n global.navigator = {\r\n userAgent: browserFakeUserAgent,\r\n getUserMedia: function() {}\r\n };\r\n\r\n if (!global.console) {\r\n global.console = {};\r\n }\r\n\r\n if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') {\r\n global.console.error = global.console.log = global.console.log || function() {\r\n console.log(arguments);\r\n };\r\n }\r\n\r\n if (typeof document === 'undefined') {\r\n /*global document:true */\r\n that.document = {\r\n documentElement: {\r\n appendChild: function() {\r\n return '';\r\n }\r\n }\r\n };\r\n\r\n document.createElement = document.captureStream = document.mozCaptureStream = function() {\r\n var obj = {\r\n getContext: function() {\r\n return obj;\r\n },\r\n play: function() {},\r\n pause: function() {},\r\n drawImage: function() {},\r\n toDataURL: function() {\r\n return '';\r\n },\r\n style: {}\r\n };\r\n return obj;\r\n };\r\n\r\n that.HTMLVideoElement = function() {};\r\n }\r\n\r\n if (typeof location === 'undefined') {\r\n /*global location:true */\r\n that.location = {\r\n protocol: 'file:',\r\n href: '',\r\n hash: ''\r\n };\r\n }\r\n\r\n if (typeof screen === 'undefined') {\r\n /*global screen:true */\r\n that.screen = {\r\n width: 0,\r\n height: 0\r\n };\r\n }\r\n\r\n if (typeof URL === 'undefined') {\r\n /*global screen:true */\r\n that.URL = {\r\n createObjectURL: function() {\r\n return '';\r\n },\r\n revokeObjectURL: function() {\r\n return '';\r\n }\r\n };\r\n }\r\n\r\n /*global window:true */\r\n that.window = global;\r\n })(typeof global !== 'undefined' ? global : null);\r\n\r\n // requires: chrome://flags/#enable-experimental-web-platform-features\r\n\r\n elementClass = elementClass || 'multi-streams-mixer';\r\n\r\n var videos = [];\r\n var isStopDrawingFrames = false;\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n canvas.style.opacity = 0;\r\n canvas.style.position = 'absolute';\r\n canvas.style.zIndex = -1;\r\n canvas.style.top = '-1000em';\r\n canvas.style.left = '-1000em';\r\n canvas.className = elementClass;\r\n (document.body || document.documentElement).appendChild(canvas);\r\n\r\n this.disableLogs = false;\r\n this.frameInterval = 10;\r\n\r\n this.width = 360;\r\n this.height = 240;\r\n\r\n // use gain node to prevent echo\r\n this.useGainNode = true;\r\n\r\n var self = this;\r\n\r\n // _____________________________\r\n // Cross-Browser-Declarations.js\r\n\r\n // WebAudio API representer\r\n var AudioContext = window.AudioContext;\r\n\r\n if (typeof AudioContext === 'undefined') {\r\n if (typeof webkitAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = webkitAudioContext;\r\n }\r\n\r\n if (typeof mozAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = mozAudioContext;\r\n }\r\n }\r\n\r\n /*jshint -W079 */\r\n var URL = window.URL;\r\n\r\n if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {\r\n /*global URL:true */\r\n URL = webkitURL;\r\n }\r\n\r\n if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?\r\n if (typeof navigator.webkitGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.webkitGetUserMedia;\r\n }\r\n\r\n if (typeof navigator.mozGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.mozGetUserMedia;\r\n }\r\n }\r\n\r\n var MediaStream = window.MediaStream;\r\n\r\n if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {\r\n MediaStream = webkitMediaStream;\r\n }\r\n\r\n /*global MediaStream:true */\r\n if (typeof MediaStream !== 'undefined') {\r\n // override \"stop\" method for all browsers\r\n if (typeof MediaStream.prototype.stop === 'undefined') {\r\n MediaStream.prototype.stop = function() {\r\n this.getTracks().forEach(function(track) {\r\n track.stop();\r\n });\r\n };\r\n }\r\n }\r\n\r\n var Storage = {};\r\n\r\n if (typeof AudioContext !== 'undefined') {\r\n Storage.AudioContext = AudioContext;\r\n } else if (typeof webkitAudioContext !== 'undefined') {\r\n Storage.AudioContext = webkitAudioContext;\r\n }\r\n\r\n function setSrcObject(stream, element) {\r\n if ('srcObject' in element) {\r\n element.srcObject = stream;\r\n } else if ('mozSrcObject' in element) {\r\n element.mozSrcObject = stream;\r\n } else {\r\n element.srcObject = stream;\r\n }\r\n }\r\n\r\n this.startDrawingFrames = function() {\r\n drawVideosToCanvas();\r\n };\r\n\r\n function drawVideosToCanvas() {\r\n if (isStopDrawingFrames) {\r\n return;\r\n }\r\n\r\n var videosLength = videos.length;\r\n\r\n var fullcanvas = false;\r\n var remaining = [];\r\n videos.forEach(function(video) {\r\n if (!video.stream) {\r\n video.stream = {};\r\n }\r\n\r\n if (video.stream.fullcanvas) {\r\n fullcanvas = video;\r\n } else {\r\n // todo: video.stream.active or video.stream.live to fix blank frames issues?\r\n remaining.push(video);\r\n }\r\n });\r\n\r\n if (fullcanvas) {\r\n canvas.width = fullcanvas.stream.width;\r\n canvas.height = fullcanvas.stream.height;\r\n } else if (remaining.length) {\r\n canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;\r\n\r\n var height = 1;\r\n if (videosLength === 3 || videosLength === 4) {\r\n height = 2;\r\n }\r\n if (videosLength === 5 || videosLength === 6) {\r\n height = 3;\r\n }\r\n if (videosLength === 7 || videosLength === 8) {\r\n height = 4;\r\n }\r\n if (videosLength === 9 || videosLength === 10) {\r\n height = 5;\r\n }\r\n canvas.height = remaining[0].height * height;\r\n } else {\r\n canvas.width = self.width || 360;\r\n canvas.height = self.height || 240;\r\n }\r\n\r\n if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {\r\n drawImage(fullcanvas);\r\n }\r\n\r\n remaining.forEach(function(video, idx) {\r\n drawImage(video, idx);\r\n });\r\n\r\n setTimeout(drawVideosToCanvas, self.frameInterval);\r\n }\r\n\r\n function drawImage(video, idx) {\r\n if (isStopDrawingFrames) {\r\n return;\r\n }\r\n\r\n var x = 0;\r\n var y = 0;\r\n var width = video.width;\r\n var height = video.height;\r\n\r\n if (idx === 1) {\r\n x = video.width;\r\n }\r\n\r\n if (idx === 2) {\r\n y = video.height;\r\n }\r\n\r\n if (idx === 3) {\r\n x = video.width;\r\n y = video.height;\r\n }\r\n\r\n if (idx === 4) {\r\n y = video.height * 2;\r\n }\r\n\r\n if (idx === 5) {\r\n x = video.width;\r\n y = video.height * 2;\r\n }\r\n\r\n if (idx === 6) {\r\n y = video.height * 3;\r\n }\r\n\r\n if (idx === 7) {\r\n x = video.width;\r\n y = video.height * 3;\r\n }\r\n\r\n if (typeof video.stream.left !== 'undefined') {\r\n x = video.stream.left;\r\n }\r\n\r\n if (typeof video.stream.top !== 'undefined') {\r\n y = video.stream.top;\r\n }\r\n\r\n if (typeof video.stream.width !== 'undefined') {\r\n width = video.stream.width;\r\n }\r\n\r\n if (typeof video.stream.height !== 'undefined') {\r\n height = video.stream.height;\r\n }\r\n\r\n context.drawImage(video, x, y, width, height);\r\n\r\n if (typeof video.stream.onRender === 'function') {\r\n video.stream.onRender(context, x, y, width, height, idx);\r\n }\r\n }\r\n\r\n function getMixedStream() {\r\n isStopDrawingFrames = false;\r\n var mixedVideoStream = getMixedVideoStream();\r\n\r\n var mixedAudioStream = getMixedAudioStream();\r\n if (mixedAudioStream) {\r\n mixedAudioStream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).forEach(function(track) {\r\n mixedVideoStream.addTrack(track);\r\n });\r\n }\r\n\r\n var fullcanvas;\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n if (stream.fullcanvas) {\r\n fullcanvas = true;\r\n }\r\n });\r\n\r\n // mixedVideoStream.prototype.appendStreams = appendStreams;\r\n // mixedVideoStream.prototype.resetVideoStreams = resetVideoStreams;\r\n // mixedVideoStream.prototype.clearRecordedData = clearRecordedData;\r\n\r\n return mixedVideoStream;\r\n }\r\n\r\n function getMixedVideoStream() {\r\n resetVideoStreams();\r\n\r\n var capturedStream;\r\n\r\n if ('captureStream' in canvas) {\r\n capturedStream = canvas.captureStream();\r\n } else if ('mozCaptureStream' in canvas) {\r\n capturedStream = canvas.mozCaptureStream();\r\n } else if (!self.disableLogs) {\r\n console.error('Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features');\r\n }\r\n\r\n var videoStream = new MediaStream();\r\n\r\n capturedStream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).forEach(function(track) {\r\n videoStream.addTrack(track);\r\n });\r\n\r\n canvas.stream = videoStream;\r\n\r\n return videoStream;\r\n }\r\n\r\n function getMixedAudioStream() {\r\n // via: @pehrsons\r\n if (!Storage.AudioContextConstructor) {\r\n Storage.AudioContextConstructor = new Storage.AudioContext();\r\n }\r\n\r\n self.audioContext = Storage.AudioContextConstructor;\r\n\r\n self.audioSources = [];\r\n\r\n if (self.useGainNode === true) {\r\n self.gainNode = self.audioContext.createGain();\r\n self.gainNode.connect(self.audioContext.destination);\r\n self.gainNode.gain.value = 0; // don't hear self\r\n }\r\n\r\n var audioTracksLength = 0;\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n if (!stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).length) {\r\n return;\r\n }\r\n\r\n audioTracksLength++;\r\n\r\n var audioSource = self.audioContext.createMediaStreamSource(stream);\r\n\r\n if (self.useGainNode === true) {\r\n audioSource.connect(self.gainNode);\r\n }\r\n\r\n self.audioSources.push(audioSource);\r\n });\r\n\r\n if (!audioTracksLength) {\r\n // because \"self.audioContext\" is not initialized\r\n // that's why we've to ignore rest of the code\r\n return;\r\n }\r\n\r\n self.audioDestination = self.audioContext.createMediaStreamDestination();\r\n self.audioSources.forEach(function(audioSource) {\r\n audioSource.connect(self.audioDestination);\r\n });\r\n return self.audioDestination.stream;\r\n }\r\n\r\n function getVideo(stream) {\r\n var video = document.createElement('video');\r\n\r\n setSrcObject(stream, video);\r\n\r\n video.className = elementClass;\r\n\r\n video.muted = true;\r\n video.volume = 0;\r\n\r\n video.width = stream.width || self.width || 360;\r\n video.height = stream.height || self.height || 240;\r\n\r\n video.play();\r\n\r\n return video;\r\n }\r\n\r\n this.appendStreams = function(streams) {\r\n if (!streams) {\r\n throw 'First parameter is required.';\r\n }\r\n\r\n if (!(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n streams.forEach(function(stream) {\r\n var newStream = new MediaStream();\r\n\r\n if (stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).length) {\r\n var video = getVideo(stream);\r\n video.stream = stream;\r\n videos.push(video);\r\n\r\n newStream.addTrack(stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n })[0]);\r\n }\r\n\r\n if (stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).length) {\r\n var audioSource = self.audioContext.createMediaStreamSource(stream);\r\n self.audioDestination = self.audioContext.createMediaStreamDestination();\r\n audioSource.connect(self.audioDestination);\r\n\r\n newStream.addTrack(self.audioDestination.stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n })[0]);\r\n }\r\n\r\n arrayOfMediaStreams.push(newStream);\r\n });\r\n };\r\n\r\n this.releaseStreams = function() {\r\n videos = [];\r\n isStopDrawingFrames = true;\r\n\r\n if (self.gainNode) {\r\n self.gainNode.disconnect();\r\n self.gainNode = null;\r\n }\r\n\r\n if (self.audioSources.length) {\r\n self.audioSources.forEach(function(source) {\r\n source.disconnect();\r\n });\r\n self.audioSources = [];\r\n }\r\n\r\n if (self.audioDestination) {\r\n self.audioDestination.disconnect();\r\n self.audioDestination = null;\r\n }\r\n\r\n if (self.audioContext) {\r\n self.audioContext.close();\r\n }\r\n\r\n self.audioContext = null;\r\n\r\n context.clearRect(0, 0, canvas.width, canvas.height);\r\n\r\n if (canvas.stream) {\r\n canvas.stream.stop();\r\n canvas.stream = null;\r\n }\r\n };\r\n\r\n this.resetVideoStreams = function(streams) {\r\n if (streams && !(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n resetVideoStreams(streams);\r\n };\r\n\r\n function resetVideoStreams(streams) {\r\n videos = [];\r\n streams = streams || arrayOfMediaStreams;\r\n\r\n // via: @adrian-ber\r\n streams.forEach(function(stream) {\r\n if (!stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).length) {\r\n return;\r\n }\r\n\r\n var video = getVideo(stream);\r\n video.stream = stream;\r\n videos.push(video);\r\n });\r\n }\r\n\r\n // for debugging\r\n this.name = 'MultiStreamsMixer';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n this.getMixedStream = getMixedStream;\r\n\r\n}\r\n\r\nif (typeof RecordRTC === 'undefined') {\r\n if (typeof module !== 'undefined' /* && !!module.exports*/ ) {\r\n module.exports = MultiStreamsMixer;\r\n }\r\n\r\n if (typeof define === 'function' && define.amd) {\r\n define('MultiStreamsMixer', [], function() {\r\n return MultiStreamsMixer;\r\n });\r\n }\r\n}\n\r\n// ______________________\r\n// MultiStreamRecorder.js\r\n\r\n/*\r\n * Video conference recording, using captureStream API along with WebAudio and Canvas2D API.\r\n */\r\n\r\n/**\r\n * MultiStreamRecorder can record multiple videos in single container.\r\n * @summary Multi-videos recorder.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef MultiStreamRecorder\r\n * @class\r\n * @example\r\n * var options = {\r\n * mimeType: 'video/webm'\r\n * }\r\n * var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n *\r\n * // or\r\n * var blob = recorder.blob;\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams.\r\n * @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: \"video/webm\"}\r\n */\r\n\r\nfunction MultiStreamRecorder(arrayOfMediaStreams, options) {\r\n arrayOfMediaStreams = arrayOfMediaStreams || [];\r\n var self = this;\r\n\r\n var mixer;\r\n var mediaRecorder;\r\n\r\n options = options || {\r\n elementClass: 'multi-streams-mixer',\r\n mimeType: 'video/webm',\r\n video: {\r\n width: 360,\r\n height: 240\r\n }\r\n };\r\n\r\n if (!options.frameInterval) {\r\n options.frameInterval = 10;\r\n }\r\n\r\n if (!options.video) {\r\n options.video = {};\r\n }\r\n\r\n if (!options.video.width) {\r\n options.video.width = 360;\r\n }\r\n\r\n if (!options.video.height) {\r\n options.video.height = 240;\r\n }\r\n\r\n /**\r\n * This method records all MediaStreams.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n // github/muaz-khan/MultiStreamsMixer\r\n mixer = new MultiStreamsMixer(arrayOfMediaStreams, options.elementClass || 'multi-streams-mixer');\r\n\r\n if (getAllVideoTracks().length) {\r\n mixer.frameInterval = options.frameInterval || 10;\r\n mixer.width = options.video.width || 360;\r\n mixer.height = options.video.height || 240;\r\n mixer.startDrawingFrames();\r\n }\r\n\r\n if (options.previewStream && typeof options.previewStream === 'function') {\r\n options.previewStream(mixer.getMixedStream());\r\n }\r\n\r\n // record using MediaRecorder API\r\n mediaRecorder = new MediaStreamRecorder(mixer.getMixedStream(), options);\r\n mediaRecorder.record();\r\n };\r\n\r\n function getAllVideoTracks() {\r\n var tracks = [];\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n getTracks(stream, 'video').forEach(function(track) {\r\n tracks.push(track);\r\n });\r\n });\r\n return tracks;\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n mediaRecorder.stop(function(blob) {\r\n self.blob = blob;\r\n\r\n callback(blob);\r\n\r\n self.clearRecordedData();\r\n });\r\n };\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.pause();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.resume();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.clearRecordedData();\r\n mediaRecorder = null;\r\n }\r\n\r\n if (mixer) {\r\n mixer.releaseStreams();\r\n mixer = null;\r\n }\r\n };\r\n\r\n /**\r\n * Add extra media-streams to existing recordings.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams\r\n * @example\r\n * recorder.addStreams([newAudioStream, newVideoStream]);\r\n */\r\n this.addStreams = function(streams) {\r\n if (!streams) {\r\n throw 'First parameter is required.';\r\n }\r\n\r\n if (!(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n arrayOfMediaStreams.concat(streams);\r\n\r\n if (!mediaRecorder || !mixer) {\r\n return;\r\n }\r\n\r\n mixer.appendStreams(streams);\r\n\r\n if (options.previewStream && typeof options.previewStream === 'function') {\r\n options.previewStream(mixer.getMixedStream());\r\n }\r\n };\r\n\r\n /**\r\n * Reset videos during live recording. Replace old videos e.g. replace cameras with full-screen.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams\r\n * @example\r\n * recorder.resetVideoStreams([newVideo1, newVideo2]);\r\n */\r\n this.resetVideoStreams = function(streams) {\r\n if (!mixer) {\r\n return;\r\n }\r\n\r\n if (streams && !(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n mixer.resetVideoStreams(streams);\r\n };\r\n\r\n /**\r\n * Returns MultiStreamsMixer\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * let mixer = recorder.getMixer();\r\n * mixer.appendStreams([newStream]);\r\n */\r\n this.getMixer = function() {\r\n return mixer;\r\n };\r\n\r\n // for debugging\r\n this.name = 'MultiStreamRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MultiStreamRecorder = MultiStreamRecorder;\r\n}\n\r\n// _____________________\r\n// RecordRTC.promises.js\r\n\r\n/**\r\n * RecordRTCPromisesHandler adds promises support in {@link RecordRTC}. Try a {@link https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/RecordRTCPromisesHandler.html|demo here}\r\n * @summary Promises for {@link RecordRTC}\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef RecordRTCPromisesHandler\r\n * @class\r\n * @example\r\n * var recorder = new RecordRTCPromisesHandler(mediaStream, options);\r\n * recorder.startRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n * // Note: You can access all RecordRTC API using \"recorder.recordRTC\" e.g. \r\n * recorder.recordRTC.onStateChanged = function(state) {};\r\n * recorder.recordRTC.setRecordingDuration(5000);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc.\r\n * @param {object} config - {type:\"video\", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}\r\n * @throws Will throw an error if \"new\" keyword is not used to initiate \"RecordRTCPromisesHandler\". Also throws error if first argument \"MediaStream\" is missing.\r\n * @requires {@link RecordRTC}\r\n */\r\n\r\nfunction RecordRTCPromisesHandler(mediaStream, options) {\r\n if (!this) {\r\n throw 'Use \"new RecordRTCPromisesHandler()\"';\r\n }\r\n\r\n if (typeof mediaStream === 'undefined') {\r\n throw 'First argument \"MediaStream\" is required.';\r\n }\r\n\r\n var self = this;\r\n\r\n /**\r\n * @property {Blob} blob - Access/reach the native {@link RecordRTC} object.\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let internal = recorder.recordRTC.getInternalRecorder();\r\n * alert(internal instanceof MediaStreamRecorder);\r\n * recorder.recordRTC.onStateChanged = function(state) {};\r\n */\r\n self.recordRTC = new RecordRTC(mediaStream, options);\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.startRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.startRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.startRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method stops the recording.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * var blob = recorder.getBlob();\r\n * }).catch(errorCB);\r\n */\r\n this.stopRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.stopRecording(function(url) {\r\n self.blob = self.recordRTC.getBlob();\r\n\r\n if (!self.blob || !self.blob.size) {\r\n reject('Empty blob.', self.blob);\r\n return;\r\n }\r\n\r\n resolve(url);\r\n });\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method pauses the recording. You can resume recording using \"resumeRecording\" method.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.pauseRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.pauseRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.pauseRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method resumes the recording.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.resumeRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.resumeRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.resumeRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns data-url for the recorded blob.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * recorder.getDataURL().then(function(dataURL) {\r\n * window.open(dataURL);\r\n * }).catch(errorCB);;\r\n * }).catch(errorCB);\r\n */\r\n this.getDataURL = function(callback) {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.getDataURL(function(dataURL) {\r\n resolve(dataURL);\r\n });\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns the recorded blob.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * recorder.getBlob().then(function(blob) {})\r\n * }).catch(errorCB);\r\n */\r\n this.getBlob = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getBlob());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns the internal recording object.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let internalRecorder = await recorder.getInternalRecorder();\r\n * if(internalRecorder instanceof MultiStreamRecorder) {\r\n * internalRecorder.addStreams([newAudioStream]);\r\n * internalRecorder.resetVideoStreams([screenStream]);\r\n * }\r\n * @returns {Object} \r\n */\r\n this.getInternalRecorder = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getInternalRecorder());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method resets the recorder. So that you can reuse single recorder instance many times.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * await recorder.reset();\r\n * recorder.startRecording(); // record again\r\n */\r\n this.reset = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.reset());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * Destroy RecordRTC instance. Clear all recorders and objects.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.destroy().then(successCB).catch(errorCB);\r\n */\r\n this.destroy = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.destroy());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * Get recorder's readonly state.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let state = await recorder.getState();\r\n * // or\r\n * recorder.getState().then(state => { console.log(state); })\r\n * @returns {String} Returns recording state.\r\n */\r\n this.getState = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getState());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * @property {Blob} blob - Recorded data as \"Blob\" object.\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * await recorder.stopRecording();\r\n * let blob = recorder.getBlob(); // or \"recorder.recordRTC.blob\"\r\n * invokeSaveAsDialog(blob);\r\n */\r\n this.blob = null;\r\n\r\n /**\r\n * RecordRTC version number\r\n * @property {String} version - Release version number.\r\n * @memberof RecordRTCPromisesHandler\r\n * @static\r\n * @readonly\r\n * @example\r\n * alert(recorder.version);\r\n */\r\n this.version = '5.6.2';\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.RecordRTCPromisesHandler = RecordRTCPromisesHandler;\r\n}\n\r\n// ______________________\r\n// WebAssemblyRecorder.js\r\n\r\n/**\r\n * WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos.\r\n * @summary Video recording feature in Chrome, Firefox and maybe Edge.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef WebAssemblyRecorder\r\n * @class\r\n * @example\r\n * var recorder = new WebAssemblyRecorder(mediaStream);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', frameRate: 30, width: 1920, height: 1080, bitrate: 1024, realtime: true}\r\n */\r\nfunction WebAssemblyRecorder(stream, config) {\r\n // based on: github.com/GoogleChromeLabs/webm-wasm\r\n\r\n if (typeof ReadableStream === 'undefined' || typeof WritableStream === 'undefined') {\r\n // because it fixes readable/writable streams issues\r\n console.error('Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js');\r\n }\r\n\r\n config = config || {};\r\n\r\n config.width = config.width || 640;\r\n config.height = config.height || 480;\r\n config.frameRate = config.frameRate || 30;\r\n config.bitrate = config.bitrate || 1200;\r\n config.realtime = config.realtime || true;\r\n\r\n function createBufferURL(buffer, type) {\r\n return URL.createObjectURL(new Blob([buffer], {\r\n type: type || ''\r\n }));\r\n }\r\n\r\n var finished;\r\n\r\n function cameraStream() {\r\n return new ReadableStream({\r\n start: function(controller) {\r\n var cvs = document.createElement('canvas');\r\n var video = document.createElement('video');\r\n var first = true;\r\n video.srcObject = stream;\r\n video.muted = true;\r\n video.height = config.height;\r\n video.width = config.width;\r\n video.volume = 0;\r\n video.onplaying = function() {\r\n cvs.width = config.width;\r\n cvs.height = config.height;\r\n var ctx = cvs.getContext('2d');\r\n var frameTimeout = 1000 / config.frameRate;\r\n var cameraTimer = setInterval(function f() {\r\n if (finished) {\r\n clearInterval(cameraTimer);\r\n controller.close();\r\n }\r\n\r\n if (first) {\r\n first = false;\r\n if (config.onVideoProcessStarted) {\r\n config.onVideoProcessStarted();\r\n }\r\n }\r\n\r\n ctx.drawImage(video, 0, 0);\r\n if (controller._controlledReadableStream.state !== 'closed') {\r\n try {\r\n controller.enqueue(\r\n ctx.getImageData(0, 0, config.width, config.height)\r\n );\r\n } catch (e) {}\r\n }\r\n }, frameTimeout);\r\n };\r\n video.play();\r\n }\r\n });\r\n }\r\n\r\n var worker;\r\n\r\n function startRecording(stream, buffer) {\r\n if (!config.workerPath && !buffer) {\r\n finished = false;\r\n\r\n // is it safe to use @latest ?\r\n\r\n fetch(\r\n 'https://unpkg.com/webm-wasm@latest/dist/webm-worker.js'\r\n ).then(function(r) {\r\n r.arrayBuffer().then(function(buffer) {\r\n startRecording(stream, buffer);\r\n });\r\n });\r\n return;\r\n }\r\n\r\n if (!config.workerPath && buffer instanceof ArrayBuffer) {\r\n var blob = new Blob([buffer], {\r\n type: 'text/javascript'\r\n });\r\n config.workerPath = URL.createObjectURL(blob);\r\n }\r\n\r\n if (!config.workerPath) {\r\n console.error('workerPath parameter is missing.');\r\n }\r\n\r\n worker = new Worker(config.workerPath);\r\n\r\n worker.postMessage(config.webAssemblyPath || 'https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm');\r\n worker.addEventListener('message', function(event) {\r\n if (event.data === 'READY') {\r\n worker.postMessage({\r\n width: config.width,\r\n height: config.height,\r\n bitrate: config.bitrate || 1200,\r\n timebaseDen: config.frameRate || 30,\r\n realtime: config.realtime\r\n });\r\n\r\n cameraStream().pipeTo(new WritableStream({\r\n write: function(image) {\r\n if (finished) {\r\n console.error('Got image, but recorder is finished!');\r\n return;\r\n }\r\n\r\n worker.postMessage(image.data.buffer, [image.data.buffer]);\r\n }\r\n }));\r\n } else if (!!event.data) {\r\n if (!isPaused) {\r\n arrayOfBuffers.push(event.data);\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * This method records video.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n arrayOfBuffers = [];\r\n isPaused = false;\r\n this.blob = null;\r\n startRecording(stream);\r\n\r\n if (typeof config.initCallback === 'function') {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n var isPaused;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPaused = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPaused = false;\r\n };\r\n\r\n function terminate(callback) {\r\n if (!worker) {\r\n if (callback) {\r\n callback();\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Wait for null event data to indicate that the encoding is complete\r\n worker.addEventListener('message', function(event) {\r\n if (event.data === null) {\r\n worker.terminate();\r\n worker = null;\r\n\r\n if (callback) {\r\n callback();\r\n }\r\n }\r\n });\r\n\r\n worker.postMessage(null);\r\n }\r\n\r\n var arrayOfBuffers = [];\r\n\r\n /**\r\n * This method stops recording video.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n finished = true;\r\n\r\n var recorder = this;\r\n\r\n terminate(function() {\r\n recorder.blob = new Blob(arrayOfBuffers, {\r\n type: 'video/webm'\r\n });\r\n\r\n callback(recorder.blob);\r\n });\r\n };\r\n\r\n // for debugging\r\n this.name = 'WebAssemblyRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n arrayOfBuffers = [];\r\n isPaused = false;\r\n this.blob = null;\r\n\r\n // todo: if recording-ON then STOP it first\r\n };\r\n\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = null;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.WebAssemblyRecorder = WebAssemblyRecorder;\r\n}\n", "/*!\nTurbo 8.0.12\nCopyright \u00A9 2024 37signals LLC\n */\n/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Javan Makhmali\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n(function (prototype) {\n if (typeof prototype.requestSubmit == \"function\") return\n\n prototype.requestSubmit = function (submitter) {\n if (submitter) {\n validateSubmitter(submitter, this);\n submitter.click();\n } else {\n submitter = document.createElement(\"input\");\n submitter.type = \"submit\";\n submitter.hidden = true;\n this.appendChild(submitter);\n submitter.click();\n this.removeChild(submitter);\n }\n };\n\n function validateSubmitter(submitter, form) {\n submitter instanceof HTMLElement || raise(TypeError, \"parameter 1 is not of type 'HTMLElement'\");\n submitter.type == \"submit\" || raise(TypeError, \"The specified element is not a submit button\");\n submitter.form == form ||\n raise(DOMException, \"The specified element is not owned by this form element\", \"NotFoundError\");\n }\n\n function raise(errorConstructor, message, name) {\n throw new errorConstructor(\"Failed to execute 'requestSubmit' on 'HTMLFormElement': \" + message + \".\", name)\n }\n})(HTMLFormElement.prototype);\n\nconst submittersByForm = new WeakMap();\n\nfunction findSubmitterFromClickTarget(target) {\n const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n const candidate = element ? element.closest(\"input, button\") : null;\n return candidate?.type == \"submit\" ? candidate : null\n}\n\nfunction clickCaptured(event) {\n const submitter = findSubmitterFromClickTarget(event.target);\n\n if (submitter && submitter.form) {\n submittersByForm.set(submitter.form, submitter);\n }\n}\n\n(function () {\n if (\"submitter\" in Event.prototype) return\n\n let prototype = window.Event.prototype;\n // Certain versions of Safari 15 have a bug where they won't\n // populate the submitter. This hurts TurboDrive's enable/disable detection.\n // See https://bugs.webkit.org/show_bug.cgi?id=229660\n if (\"SubmitEvent\" in window) {\n const prototypeOfSubmitEvent = window.SubmitEvent.prototype;\n\n if (/Apple Computer/.test(navigator.vendor) && !(\"submitter\" in prototypeOfSubmitEvent)) {\n prototype = prototypeOfSubmitEvent;\n } else {\n return // polyfill not needed\n }\n }\n\n addEventListener(\"click\", clickCaptured, true);\n\n Object.defineProperty(prototype, \"submitter\", {\n get() {\n if (this.type == \"submit\" && this.target instanceof HTMLFormElement) {\n return submittersByForm.get(this.target)\n }\n }\n });\n})();\n\nconst FrameLoadingStyle = {\n eager: \"eager\",\n lazy: \"lazy\"\n};\n\n/**\n * Contains a fragment of HTML which is updated based on navigation within\n * it (e.g. via links or form submissions).\n *\n * @customElement turbo-frame\n * @example\n * (props: P, final?: boolean): Pick