forked from BRNSystems/bosca-ceoil-js
1284 lines
800 KiB
JavaScript
1284 lines
800 KiB
JavaScript
|
/******/ (function(modules) { // webpackBootstrap
|
||
|
/******/ // The module cache
|
||
|
/******/ var installedModules = {};
|
||
|
/******/
|
||
|
/******/ // The require function
|
||
|
/******/ function __webpack_require__(moduleId) {
|
||
|
/******/
|
||
|
/******/ // Check if module is in cache
|
||
|
/******/ if(installedModules[moduleId]) {
|
||
|
/******/ return installedModules[moduleId].exports;
|
||
|
/******/ }
|
||
|
/******/ // Create a new module (and put it into the cache)
|
||
|
/******/ var module = installedModules[moduleId] = {
|
||
|
/******/ i: moduleId,
|
||
|
/******/ l: false,
|
||
|
/******/ exports: {}
|
||
|
/******/ };
|
||
|
/******/
|
||
|
/******/ // Execute the module function
|
||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||
|
/******/
|
||
|
/******/ // Flag the module as loaded
|
||
|
/******/ module.l = true;
|
||
|
/******/
|
||
|
/******/ // Return the exports of the module
|
||
|
/******/ return module.exports;
|
||
|
/******/ }
|
||
|
/******/
|
||
|
/******/
|
||
|
/******/ // expose the modules object (__webpack_modules__)
|
||
|
/******/ __webpack_require__.m = modules;
|
||
|
/******/
|
||
|
/******/ // expose the module cache
|
||
|
/******/ __webpack_require__.c = installedModules;
|
||
|
/******/
|
||
|
/******/ // define getter function for harmony exports
|
||
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
||
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||
|
/******/ }
|
||
|
/******/ };
|
||
|
/******/
|
||
|
/******/ // define __esModule on exports
|
||
|
/******/ __webpack_require__.r = function(exports) {
|
||
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||
|
/******/ }
|
||
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||
|
/******/ };
|
||
|
/******/
|
||
|
/******/ // create a fake namespace object
|
||
|
/******/ // mode & 1: value is a module id, require it
|
||
|
/******/ // mode & 2: merge all properties of value into the ns
|
||
|
/******/ // mode & 4: return value when already ns object
|
||
|
/******/ // mode & 8|1: behave like require
|
||
|
/******/ __webpack_require__.t = function(value, mode) {
|
||
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
||
|
/******/ if(mode & 8) return value;
|
||
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||
|
/******/ var ns = Object.create(null);
|
||
|
/******/ __webpack_require__.r(ns);
|
||
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||
|
/******/ return ns;
|
||
|
/******/ };
|
||
|
/******/
|
||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||
|
/******/ __webpack_require__.n = function(module) {
|
||
|
/******/ var getter = module && module.__esModule ?
|
||
|
/******/ function getDefault() { return module['default']; } :
|
||
|
/******/ function getModuleExports() { return module; };
|
||
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
||
|
/******/ return getter;
|
||
|
/******/ };
|
||
|
/******/
|
||
|
/******/ // Object.prototype.hasOwnProperty.call
|
||
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||
|
/******/
|
||
|
/******/ // __webpack_public_path__
|
||
|
/******/ __webpack_require__.p = "";
|
||
|
/******/
|
||
|
/******/
|
||
|
/******/ // Load entry module and return exports
|
||
|
/******/ return __webpack_require__(__webpack_require__.s = "./src/player.ts");
|
||
|
/******/ })
|
||
|
/************************************************************************/
|
||
|
/******/ ({
|
||
|
|
||
|
/***/ "./instruments.yaml":
|
||
|
/*!**************************!*\
|
||
|
!*** ./instruments.yaml ***!
|
||
|
\**************************/
|
||
|
/*! no static exports found */
|
||
|
/***/ (function(module, exports) {
|
||
|
|
||
|
const doc = [({"midi.piano1":({"index":0, "duration":"short", "category":["MIDI", "Piano", "Grand Piano"]}), "midi.chrom1":({"index":8, "duration":"constant", "category":["MIDI", "Bells", "Celesta"]}), "midi.organ1":({"index":16, "duration":"instant", "category":["MIDI", "Organ", "Drawbar Organ"]}), "midi.guitar1":({"index":24, "duration":"short", "category":["MIDI", "Guitar", "Nylon Guitar"]}), "midi.bass1":({"index":32, "duration":"instant", "category":["MIDI", "Bass", "Acoustic Bass"]}), "midi.strings1":({"index":40, "duration":"mini", "category":["MIDI", "Strings", "Violin"]}), "midi.ensemble1":({"index":48, "duration":"mid", "category":["MIDI", "Ensemble", "String Ensemble 1"]}), "midi.brass1":({"index":56, "duration":"mini", "category":["MIDI", "Brass", "Trumpet"]}), "midi.reed1":({"index":64, "duration":"mini", "category":["MIDI", "Reed", "Soprano Sax"]}), "midi.pipe1":({"index":72, "duration":"mini", "category":["MIDI", "Pipe", "Piccolo"]}), "midi.lead1":({"index":80, "duration":"mini", "category":["MIDI", "Lead", "Square Lead"]}), "midi.pad1":({"index":88, "duration":"long", "category":["MIDI", "Pads", "New Age Pad"]}), "midi.fx1":({"index":96, "duration":"mega", "category":["MIDI", "Synth", "Rain"]}), "midi.world1":({"index":104, "duration":"extended", "category":["MIDI", "World", "Sitar"]}), "midi.percus1":({"index":112, "duration":"long", "category":["MIDI", "Drums", "Tinkle Bell"]}), "midi.se1":({"index":120, "duration":"mini", "category":["MIDI", "Effects", "Fret Noise"]}), "square":({"index":128, "duration":"infinite", "category":["Chiptune", "Square Wave"]})})];
|
||
|
module.exports = doc.length <= 1 ? doc[0] : doc;
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./node_modules/dialog-polyfill/dist/dialog-polyfill.esm.js":
|
||
|
/*!******************************************************************!*\
|
||
|
!*** ./node_modules/dialog-polyfill/dist/dialog-polyfill.esm.js ***!
|
||
|
\******************************************************************/
|
||
|
/*! exports provided: default */
|
||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||
|
|
||
|
"use strict";
|
||
|
__webpack_require__.r(__webpack_exports__);
|
||
|
// nb. This is for IE10 and lower _only_.
|
||
|
var supportCustomEvent = window.CustomEvent;
|
||
|
if (!supportCustomEvent || typeof supportCustomEvent === 'object') {
|
||
|
supportCustomEvent = function CustomEvent(event, x) {
|
||
|
x = x || {};
|
||
|
var ev = document.createEvent('CustomEvent');
|
||
|
ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
|
||
|
return ev;
|
||
|
};
|
||
|
supportCustomEvent.prototype = window.Event.prototype;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {Element} el to check for stacking context
|
||
|
* @return {boolean} whether this el or its parents creates a stacking context
|
||
|
*/
|
||
|
function createsStackingContext(el) {
|
||
|
while (el && el !== document.body) {
|
||
|
var s = window.getComputedStyle(el);
|
||
|
var invalid = function(k, ok) {
|
||
|
return !(s[k] === undefined || s[k] === ok);
|
||
|
};
|
||
|
|
||
|
if (s.opacity < 1 ||
|
||
|
invalid('zIndex', 'auto') ||
|
||
|
invalid('transform', 'none') ||
|
||
|
invalid('mixBlendMode', 'normal') ||
|
||
|
invalid('filter', 'none') ||
|
||
|
invalid('perspective', 'none') ||
|
||
|
s['isolation'] === 'isolate' ||
|
||
|
s.position === 'fixed' ||
|
||
|
s.webkitOverflowScrolling === 'touch') {
|
||
|
return true;
|
||
|
}
|
||
|
el = el.parentElement;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Finds the nearest <dialog> from the passed element.
|
||
|
*
|
||
|
* @param {Element} el to search from
|
||
|
* @return {HTMLDialogElement} dialog found
|
||
|
*/
|
||
|
function findNearestDialog(el) {
|
||
|
while (el) {
|
||
|
if (el.localName === 'dialog') {
|
||
|
return /** @type {HTMLDialogElement} */ (el);
|
||
|
}
|
||
|
el = el.parentElement;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Blur the specified element, as long as it's not the HTML body element.
|
||
|
* This works around an IE9/10 bug - blurring the body causes Windows to
|
||
|
* blur the whole application.
|
||
|
*
|
||
|
* @param {Element} el to blur
|
||
|
*/
|
||
|
function safeBlur(el) {
|
||
|
if (el && el.blur && el !== document.body) {
|
||
|
el.blur();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!NodeList} nodeList to search
|
||
|
* @param {Node} node to find
|
||
|
* @return {boolean} whether node is inside nodeList
|
||
|
*/
|
||
|
function inNodeList(nodeList, node) {
|
||
|
for (var i = 0; i < nodeList.length; ++i) {
|
||
|
if (nodeList[i] === node) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {HTMLFormElement} el to check
|
||
|
* @return {boolean} whether this form has method="dialog"
|
||
|
*/
|
||
|
function isFormMethodDialog(el) {
|
||
|
if (!el || !el.hasAttribute('method')) {
|
||
|
return false;
|
||
|
}
|
||
|
return el.getAttribute('method').toLowerCase() === 'dialog';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!HTMLDialogElement} dialog to upgrade
|
||
|
* @constructor
|
||
|
*/
|
||
|
function dialogPolyfillInfo(dialog) {
|
||
|
this.dialog_ = dialog;
|
||
|
this.replacedStyleTop_ = false;
|
||
|
this.openAsModal_ = false;
|
||
|
|
||
|
// Set a11y role. Browsers that support dialog implicitly know this already.
|
||
|
if (!dialog.hasAttribute('role')) {
|
||
|
dialog.setAttribute('role', 'dialog');
|
||
|
}
|
||
|
|
||
|
dialog.show = this.show.bind(this);
|
||
|
dialog.showModal = this.showModal.bind(this);
|
||
|
dialog.close = this.close.bind(this);
|
||
|
|
||
|
if (!('returnValue' in dialog)) {
|
||
|
dialog.returnValue = '';
|
||
|
}
|
||
|
|
||
|
if ('MutationObserver' in window) {
|
||
|
var mo = new MutationObserver(this.maybeHideModal.bind(this));
|
||
|
mo.observe(dialog, {attributes: true, attributeFilter: ['open']});
|
||
|
} else {
|
||
|
// IE10 and below support. Note that DOMNodeRemoved etc fire _before_ removal. They also
|
||
|
// seem to fire even if the element was removed as part of a parent removal. Use the removed
|
||
|
// events to force downgrade (useful if removed/immediately added).
|
||
|
var removed = false;
|
||
|
var cb = function() {
|
||
|
removed ? this.downgradeModal() : this.maybeHideModal();
|
||
|
removed = false;
|
||
|
}.bind(this);
|
||
|
var timeout;
|
||
|
var delayModel = function(ev) {
|
||
|
if (ev.target !== dialog) { return; } // not for a child element
|
||
|
var cand = 'DOMNodeRemoved';
|
||
|
removed |= (ev.type.substr(0, cand.length) === cand);
|
||
|
window.clearTimeout(timeout);
|
||
|
timeout = window.setTimeout(cb, 0);
|
||
|
};
|
||
|
['DOMAttrModified', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument'].forEach(function(name) {
|
||
|
dialog.addEventListener(name, delayModel);
|
||
|
});
|
||
|
}
|
||
|
// Note that the DOM is observed inside DialogManager while any dialog
|
||
|
// is being displayed as a modal, to catch modal removal from the DOM.
|
||
|
|
||
|
Object.defineProperty(dialog, 'open', {
|
||
|
set: this.setOpen.bind(this),
|
||
|
get: dialog.hasAttribute.bind(dialog, 'open')
|
||
|
});
|
||
|
|
||
|
this.backdrop_ = document.createElement('div');
|
||
|
this.backdrop_.className = 'backdrop';
|
||
|
this.backdrop_.addEventListener('click', this.backdropClick_.bind(this));
|
||
|
}
|
||
|
|
||
|
dialogPolyfillInfo.prototype = {
|
||
|
|
||
|
get dialog() {
|
||
|
return this.dialog_;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Maybe remove this dialog from the modal top layer. This is called when
|
||
|
* a modal dialog may no longer be tenable, e.g., when the dialog is no
|
||
|
* longer open or is no longer part of the DOM.
|
||
|
*/
|
||
|
maybeHideModal: function() {
|
||
|
if (this.dialog_.hasAttribute('open') && document.body.contains(this.dialog_)) { return; }
|
||
|
this.downgradeModal();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Remove this dialog from the modal top layer, leaving it as a non-modal.
|
||
|
*/
|
||
|
downgradeModal: function() {
|
||
|
if (!this.openAsModal_) { return; }
|
||
|
this.openAsModal_ = false;
|
||
|
this.dialog_.style.zIndex = '';
|
||
|
|
||
|
// This won't match the native <dialog> exactly because if the user set top on a centered
|
||
|
// polyfill dialog, that top gets thrown away when the dialog is closed. Not sure it's
|
||
|
// possible to polyfill this perfectly.
|
||
|
if (this.replacedStyleTop_) {
|
||
|
this.dialog_.style.top = '';
|
||
|
this.replacedStyleTop_ = false;
|
||
|
}
|
||
|
|
||
|
// Clear the backdrop and remove from the manager.
|
||
|
this.backdrop_.parentNode && this.backdrop_.parentNode.removeChild(this.backdrop_);
|
||
|
dialogPolyfill.dm.removeDialog(this);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {boolean} value whether to open or close this dialog
|
||
|
*/
|
||
|
setOpen: function(value) {
|
||
|
if (value) {
|
||
|
this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', '');
|
||
|
} else {
|
||
|
this.dialog_.removeAttribute('open');
|
||
|
this.maybeHideModal(); // nb. redundant with MutationObserver
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Handles clicks on the fake .backdrop element, redirecting them as if
|
||
|
* they were on the dialog itself.
|
||
|
*
|
||
|
* @param {!Event} e to redirect
|
||
|
*/
|
||
|
backdropClick_: function(e) {
|
||
|
if (!this.dialog_.hasAttribute('tabindex')) {
|
||
|
// Clicking on the backdrop should move the implicit cursor, even if dialog cannot be
|
||
|
// focused. Create a fake thing to focus on. If the backdrop was _before_ the dialog, this
|
||
|
// would not be needed - clicks would move the implicit cursor there.
|
||
|
var fake = document.createElement('div');
|
||
|
this.dialog_.insertBefore(fake, this.dialog_.firstChild);
|
||
|
fake.tabIndex = -1;
|
||
|
fake.focus();
|
||
|
this.dialog_.removeChild(fake);
|
||
|
} else {
|
||
|
this.dialog_.focus();
|
||
|
}
|
||
|
|
||
|
var redirectedEvent = document.createEvent('MouseEvents');
|
||
|
redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window,
|
||
|
e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey,
|
||
|
e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
|
||
|
this.dialog_.dispatchEvent(redirectedEvent);
|
||
|
e.stopPropagation();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Focuses on the first focusable element within the dialog. This will always blur the current
|
||
|
* focus, even if nothing within the dialog is found.
|
||
|
*/
|
||
|
focus_: function() {
|
||
|
// Find element with `autofocus` attribute, or fall back to the first form/tabindex control.
|
||
|
var target = this.dialog_.querySelector('[autofocus]:not([disabled])');
|
||
|
if (!target && this.dialog_.tabIndex >= 0) {
|
||
|
target = this.dialog_;
|
||
|
}
|
||
|
if (!target) {
|
||
|
// Note that this is 'any focusable area'. This list is probably not exhaustive, but the
|
||
|
// alternative involves stepping through and trying to focus everything.
|
||
|
var opts = ['button', 'input', 'keygen', 'select', 'textarea'];
|
||
|
var query = opts.map(function(el) {
|
||
|
return el + ':not([disabled])';
|
||
|
});
|
||
|
// TODO(samthor): tabindex values that are not numeric are not focusable.
|
||
|
query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled
|
||
|
target = this.dialog_.querySelector(query.join(', '));
|
||
|
}
|
||
|
safeBlur(document.activeElement);
|
||
|
target && target.focus();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Sets the zIndex for the backdrop and dialog.
|
||
|
*
|
||
|
* @param {number} dialogZ
|
||
|
* @param {number} backdropZ
|
||
|
*/
|
||
|
updateZIndex: function(dialogZ, backdropZ) {
|
||
|
if (dialogZ < backdropZ) {
|
||
|
throw new Error('dialogZ should never be < backdropZ');
|
||
|
}
|
||
|
this.dialog_.style.zIndex = dialogZ;
|
||
|
this.backdrop_.style.zIndex = backdropZ;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Shows the dialog. If the dialog is already open, this does nothing.
|
||
|
*/
|
||
|
show: function() {
|
||
|
if (!this.dialog_.open) {
|
||
|
this.setOpen(true);
|
||
|
this.focus_();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Show this dialog modally.
|
||
|
*/
|
||
|
showModal: function() {
|
||
|
if (this.dialog_.hasAttribute('open')) {
|
||
|
throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.');
|
||
|
}
|
||
|
if (!document.body.contains(this.dialog_)) {
|
||
|
throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.');
|
||
|
}
|
||
|
if (!dialogPolyfill.dm.pushDialog(this)) {
|
||
|
throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.');
|
||
|
}
|
||
|
|
||
|
if (createsStackingContext(this.dialog_.parentElement)) {
|
||
|
console.warn('A dialog is being shown inside a stacking context. ' +
|
||
|
'This may cause it to be unusable. For more information, see this link: ' +
|
||
|
'https://github.com/GoogleChrome/dialog-polyfill/#stacking-context');
|
||
|
}
|
||
|
|
||
|
this.setOpen(true);
|
||
|
this.openAsModal_ = true;
|
||
|
|
||
|
// Optionally center vertically, relative to the current viewport.
|
||
|
if (dialogPolyfill.needsCentering(this.dialog_)) {
|
||
|
dialogPolyfill.reposition(this.dialog_);
|
||
|
this.replacedStyleTop_ = true;
|
||
|
} else {
|
||
|
this.replacedStyleTop_ = false;
|
||
|
}
|
||
|
|
||
|
// Insert backdrop.
|
||
|
this.dialog_.parentNode.insertBefore(this.backdrop_, this.dialog_.nextSibling);
|
||
|
|
||
|
// Focus on whatever inside the dialog.
|
||
|
this.focus_();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Closes this HTMLDialogElement. This is optional vs clearing the open
|
||
|
* attribute, however this fires a 'close' event.
|
||
|
*
|
||
|
* @param {string=} opt_returnValue to use as the returnValue
|
||
|
*/
|
||
|
close: function(opt_returnValue) {
|
||
|
if (!this.dialog_.hasAttribute('open')) {
|
||
|
throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.');
|
||
|
}
|
||
|
this.setOpen(false);
|
||
|
|
||
|
// Leave returnValue untouched in case it was set directly on the element
|
||
|
if (opt_returnValue !== undefined) {
|
||
|
this.dialog_.returnValue = opt_returnValue;
|
||
|
}
|
||
|
|
||
|
// Triggering "close" event for any attached listeners on the <dialog>.
|
||
|
var closeEvent = new supportCustomEvent('close', {
|
||
|
bubbles: false,
|
||
|
cancelable: false
|
||
|
});
|
||
|
this.dialog_.dispatchEvent(closeEvent);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
var dialogPolyfill = {};
|
||
|
|
||
|
dialogPolyfill.reposition = function(element) {
|
||
|
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
||
|
var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;
|
||
|
element.style.top = Math.max(scrollTop, topValue) + 'px';
|
||
|
};
|
||
|
|
||
|
dialogPolyfill.isInlinePositionSetByStylesheet = function(element) {
|
||
|
for (var i = 0; i < document.styleSheets.length; ++i) {
|
||
|
var styleSheet = document.styleSheets[i];
|
||
|
var cssRules = null;
|
||
|
// Some browsers throw on cssRules.
|
||
|
try {
|
||
|
cssRules = styleSheet.cssRules;
|
||
|
} catch (e) {}
|
||
|
if (!cssRules) { continue; }
|
||
|
for (var j = 0; j < cssRules.length; ++j) {
|
||
|
var rule = cssRules[j];
|
||
|
var selectedNodes = null;
|
||
|
// Ignore errors on invalid selector texts.
|
||
|
try {
|
||
|
selectedNodes = document.querySelectorAll(rule.selectorText);
|
||
|
} catch(e) {}
|
||
|
if (!selectedNodes || !inNodeList(selectedNodes, element)) {
|
||
|
continue;
|
||
|
}
|
||
|
var cssTop = rule.style.getPropertyValue('top');
|
||
|
var cssBottom = rule.style.getPropertyValue('bottom');
|
||
|
if ((cssTop && cssTop !== 'auto') || (cssBottom && cssBottom !== 'auto')) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
dialogPolyfill.needsCentering = function(dialog) {
|
||
|
var computedStyle = window.getComputedStyle(dialog);
|
||
|
if (computedStyle.position !== 'absolute') {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// We must determine whether the top/bottom specified value is non-auto. In
|
||
|
// WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
|
||
|
// Firefox returns the used value. So we do this crazy thing instead: check
|
||
|
// the inline style and then go through CSS rules.
|
||
|
if ((dialog.style.top !== 'auto' && dialog.style.top !== '') ||
|
||
|
(dialog.style.bottom !== 'auto' && dialog.style.bottom !== '')) {
|
||
|
return false;
|
||
|
}
|
||
|
return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {!Element} element to force upgrade
|
||
|
*/
|
||
|
dialogPolyfill.forceRegisterDialog = function(element) {
|
||
|
if (window.HTMLDialogElement || element.showModal) {
|
||
|
console.warn('This browser already supports <dialog>, the polyfill ' +
|
||
|
'may not work correctly', element);
|
||
|
}
|
||
|
if (element.localName !== 'dialog') {
|
||
|
throw new Error('Failed to register dialog: The element is not a dialog.');
|
||
|
}
|
||
|
new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {!Element} element to upgrade, if necessary
|
||
|
*/
|
||
|
dialogPolyfill.registerDialog = function(element) {
|
||
|
if (!element.showModal) {
|
||
|
dialogPolyfill.forceRegisterDialog(element);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @constructor
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager = function() {
|
||
|
/** @type {!Array<!dialogPolyfillInfo>} */
|
||
|
this.pendingDialogStack = [];
|
||
|
|
||
|
var checkDOM = this.checkDOM_.bind(this);
|
||
|
|
||
|
// The overlay is used to simulate how a modal dialog blocks the document.
|
||
|
// The blocking dialog is positioned on top of the overlay, and the rest of
|
||
|
// the dialogs on the pending dialog stack are positioned below it. In the
|
||
|
// actual implementation, the modal dialog stacking is controlled by the
|
||
|
// top layer, where z-index has no effect.
|
||
|
this.overlay = document.createElement('div');
|
||
|
this.overlay.className = '_dialog_overlay';
|
||
|
this.overlay.addEventListener('click', function(e) {
|
||
|
this.forwardTab_ = undefined;
|
||
|
e.stopPropagation();
|
||
|
checkDOM([]); // sanity-check DOM
|
||
|
}.bind(this));
|
||
|
|
||
|
this.handleKey_ = this.handleKey_.bind(this);
|
||
|
this.handleFocus_ = this.handleFocus_.bind(this);
|
||
|
|
||
|
this.zIndexLow_ = 100000;
|
||
|
this.zIndexHigh_ = 100000 + 150;
|
||
|
|
||
|
this.forwardTab_ = undefined;
|
||
|
|
||
|
if ('MutationObserver' in window) {
|
||
|
this.mo_ = new MutationObserver(function(records) {
|
||
|
var removed = [];
|
||
|
records.forEach(function(rec) {
|
||
|
for (var i = 0, c; c = rec.removedNodes[i]; ++i) {
|
||
|
if (!(c instanceof Element)) {
|
||
|
continue;
|
||
|
} else if (c.localName === 'dialog') {
|
||
|
removed.push(c);
|
||
|
}
|
||
|
removed = removed.concat(c.querySelectorAll('dialog'));
|
||
|
}
|
||
|
});
|
||
|
removed.length && checkDOM(removed);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Called on the first modal dialog being shown. Adds the overlay and related
|
||
|
* handlers.
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.blockDocument = function() {
|
||
|
document.documentElement.addEventListener('focus', this.handleFocus_, true);
|
||
|
document.addEventListener('keydown', this.handleKey_);
|
||
|
this.mo_ && this.mo_.observe(document, {childList: true, subtree: true});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Called on the first modal dialog being removed, i.e., when no more modal
|
||
|
* dialogs are visible.
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.unblockDocument = function() {
|
||
|
document.documentElement.removeEventListener('focus', this.handleFocus_, true);
|
||
|
document.removeEventListener('keydown', this.handleKey_);
|
||
|
this.mo_ && this.mo_.disconnect();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Updates the stacking of all known dialogs.
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.updateStacking = function() {
|
||
|
var zIndex = this.zIndexHigh_;
|
||
|
|
||
|
for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {
|
||
|
dpi.updateZIndex(--zIndex, --zIndex);
|
||
|
if (i === 0) {
|
||
|
this.overlay.style.zIndex = --zIndex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Make the overlay a sibling of the dialog itself.
|
||
|
var last = this.pendingDialogStack[0];
|
||
|
if (last) {
|
||
|
var p = last.dialog.parentNode || document.body;
|
||
|
p.appendChild(this.overlay);
|
||
|
} else if (this.overlay.parentNode) {
|
||
|
this.overlay.parentNode.removeChild(this.overlay);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {Element} candidate to check if contained or is the top-most modal dialog
|
||
|
* @return {boolean} whether candidate is contained in top dialog
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.containedByTopDialog_ = function(candidate) {
|
||
|
while (candidate = findNearestDialog(candidate)) {
|
||
|
for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {
|
||
|
if (dpi.dialog === candidate) {
|
||
|
return i === 0; // only valid if top-most
|
||
|
}
|
||
|
}
|
||
|
candidate = candidate.parentElement;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) {
|
||
|
if (this.containedByTopDialog_(event.target)) { return; }
|
||
|
|
||
|
if (document.activeElement === document.documentElement) { return; }
|
||
|
|
||
|
event.preventDefault();
|
||
|
event.stopPropagation();
|
||
|
safeBlur(/** @type {Element} */ (event.target));
|
||
|
|
||
|
if (this.forwardTab_ === undefined) { return; } // move focus only from a tab key
|
||
|
|
||
|
var dpi = this.pendingDialogStack[0];
|
||
|
var dialog = dpi.dialog;
|
||
|
var position = dialog.compareDocumentPosition(event.target);
|
||
|
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
||
|
if (this.forwardTab_) {
|
||
|
// forward
|
||
|
dpi.focus_();
|
||
|
} else if (event.target !== document.documentElement) {
|
||
|
// backwards if we're not already focused on <html>
|
||
|
document.documentElement.focus();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
dialogPolyfill.DialogManager.prototype.handleKey_ = function(event) {
|
||
|
this.forwardTab_ = undefined;
|
||
|
if (event.keyCode === 27) {
|
||
|
event.preventDefault();
|
||
|
event.stopPropagation();
|
||
|
var cancelEvent = new supportCustomEvent('cancel', {
|
||
|
bubbles: false,
|
||
|
cancelable: true
|
||
|
});
|
||
|
var dpi = this.pendingDialogStack[0];
|
||
|
if (dpi && dpi.dialog.dispatchEvent(cancelEvent)) {
|
||
|
dpi.dialog.close();
|
||
|
}
|
||
|
} else if (event.keyCode === 9) {
|
||
|
this.forwardTab_ = !event.shiftKey;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Finds and downgrades any known modal dialogs that are no longer displayed. Dialogs that are
|
||
|
* removed and immediately readded don't stay modal, they become normal.
|
||
|
*
|
||
|
* @param {!Array<!HTMLDialogElement>} removed that have definitely been removed
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.checkDOM_ = function(removed) {
|
||
|
// This operates on a clone because it may cause it to change. Each change also calls
|
||
|
// updateStacking, which only actually needs to happen once. But who removes many modal dialogs
|
||
|
// at a time?!
|
||
|
var clone = this.pendingDialogStack.slice();
|
||
|
clone.forEach(function(dpi) {
|
||
|
if (removed.indexOf(dpi.dialog) !== -1) {
|
||
|
dpi.downgradeModal();
|
||
|
} else {
|
||
|
dpi.maybeHideModal();
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {!dialogPolyfillInfo} dpi
|
||
|
* @return {boolean} whether the dialog was allowed
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) {
|
||
|
var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1;
|
||
|
if (this.pendingDialogStack.length >= allowed) {
|
||
|
return false;
|
||
|
}
|
||
|
if (this.pendingDialogStack.unshift(dpi) === 1) {
|
||
|
this.blockDocument();
|
||
|
}
|
||
|
this.updateStacking();
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {!dialogPolyfillInfo} dpi
|
||
|
*/
|
||
|
dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) {
|
||
|
var index = this.pendingDialogStack.indexOf(dpi);
|
||
|
if (index === -1) { return; }
|
||
|
|
||
|
this.pendingDialogStack.splice(index, 1);
|
||
|
if (this.pendingDialogStack.length === 0) {
|
||
|
this.unblockDocument();
|
||
|
}
|
||
|
this.updateStacking();
|
||
|
};
|
||
|
|
||
|
dialogPolyfill.dm = new dialogPolyfill.DialogManager();
|
||
|
dialogPolyfill.formSubmitter = null;
|
||
|
dialogPolyfill.useValue = null;
|
||
|
|
||
|
/**
|
||
|
* Installs global handlers, such as click listers and native method overrides. These are needed
|
||
|
* even if a no dialog is registered, as they deal with <form method="dialog">.
|
||
|
*/
|
||
|
if (window.HTMLDialogElement === undefined) {
|
||
|
|
||
|
/**
|
||
|
* If HTMLFormElement translates method="DIALOG" into 'get', then replace the descriptor with
|
||
|
* one that returns the correct value.
|
||
|
*/
|
||
|
var testForm = document.createElement('form');
|
||
|
testForm.setAttribute('method', 'dialog');
|
||
|
if (testForm.method !== 'dialog') {
|
||
|
var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method');
|
||
|
if (methodDescriptor) {
|
||
|
// nb. Some older iOS and older PhantomJS fail to return the descriptor. Don't do anything
|
||
|
// and don't bother to update the element.
|
||
|
var realGet = methodDescriptor.get;
|
||
|
methodDescriptor.get = function() {
|
||
|
if (isFormMethodDialog(this)) {
|
||
|
return 'dialog';
|
||
|
}
|
||
|
return realGet.call(this);
|
||
|
};
|
||
|
var realSet = methodDescriptor.set;
|
||
|
methodDescriptor.set = function(v) {
|
||
|
if (typeof v === 'string' && v.toLowerCase() === 'dialog') {
|
||
|
return this.setAttribute('method', v);
|
||
|
}
|
||
|
return realSet.call(this, v);
|
||
|
};
|
||
|
Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Global 'click' handler, to capture the <input type="submit"> or <button> element which has
|
||
|
* submitted a <form method="dialog">. Needed as Safari and others don't report this inside
|
||
|
* document.activeElement.
|
||
|
*/
|
||
|
document.addEventListener('click', function(ev) {
|
||
|
dialogPolyfill.formSubmitter = null;
|
||
|
dialogPolyfill.useValue = null;
|
||
|
if (ev.defaultPrevented) { return; } // e.g. a submit which prevents default submission
|
||
|
|
||
|
var target = /** @type {Element} */ (ev.target);
|
||
|
if (!target || !isFormMethodDialog(target.form)) { return; }
|
||
|
|
||
|
var valid = (target.type === 'submit' && ['button', 'input'].indexOf(target.localName) > -1);
|
||
|
if (!valid) {
|
||
|
if (!(target.localName === 'input' && target.type === 'image')) { return; }
|
||
|
// this is a <input type="image">, which can submit forms
|
||
|
dialogPolyfill.useValue = ev.offsetX + ',' + ev.offsetY;
|
||
|
}
|
||
|
|
||
|
var dialog = findNearestDialog(target);
|
||
|
if (!dialog) { return; }
|
||
|
|
||
|
dialogPolyfill.formSubmitter = target;
|
||
|
|
||
|
}, false);
|
||
|
|
||
|
/**
|
||
|
* Replace the native HTMLFormElement.submit() method, as it won't fire the
|
||
|
* submit event and give us a chance to respond.
|
||
|
*/
|
||
|
var nativeFormSubmit = HTMLFormElement.prototype.submit;
|
||
|
var replacementFormSubmit = function () {
|
||
|
if (!isFormMethodDialog(this)) {
|
||
|
return nativeFormSubmit.call(this);
|
||
|
}
|
||
|
var dialog = findNearestDialog(this);
|
||
|
dialog && dialog.close();
|
||
|
};
|
||
|
HTMLFormElement.prototype.submit = replacementFormSubmit;
|
||
|
|
||
|
/**
|
||
|
* Global form 'dialog' method handler. Closes a dialog correctly on submit
|
||
|
* and possibly sets its return value.
|
||
|
*/
|
||
|
document.addEventListener('submit', function(ev) {
|
||
|
var form = /** @type {HTMLFormElement} */ (ev.target);
|
||
|
if (!isFormMethodDialog(form)) { return; }
|
||
|
ev.preventDefault();
|
||
|
|
||
|
var dialog = findNearestDialog(form);
|
||
|
if (!dialog) { return; }
|
||
|
|
||
|
// Forms can only be submitted via .submit() or a click (?), but anyway: sanity-check that
|
||
|
// the submitter is correct before using its value as .returnValue.
|
||
|
var s = dialogPolyfill.formSubmitter;
|
||
|
if (s && s.form === form) {
|
||
|
dialog.close(dialogPolyfill.useValue || s.value);
|
||
|
} else {
|
||
|
dialog.close();
|
||
|
}
|
||
|
dialogPolyfill.formSubmitter = null;
|
||
|
|
||
|
}, true);
|
||
|
}
|
||
|
|
||
|
/* harmony default export */ __webpack_exports__["default"] = (dialogPolyfill);
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./node_modules/tone/build/Tone.js":
|
||
|
/*!*****************************************!*\
|
||
|
!*** ./node_modules/tone/build/Tone.js ***!
|
||
|
\*****************************************/
|
||
|
/*! no static exports found */
|
||
|
/***/ (function(module, exports, __webpack_require__) {
|
||
|
|
||
|
!function(t,e){ true?module.exports=e():undefined}("undefined"!=typeof self?self:this,function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=155)}([function(t,e,i){(function(n){var o,s;
|
||
|
/**
|
||
|
* Tone.js
|
||
|
* @author Yotam Mann
|
||
|
* @license http://opensource.org/licenses/MIT MIT License
|
||
|
* @copyright 2014-2019 Yotam Mann
|
||
|
*/o=[i(153)],void 0===(s=function(t){"use strict";var e=function(){if(!(this instanceof e))throw new Error("constructor needs to be called with the 'new' keyword")};return e.prototype.toString=function(){for(var t in e){var i=t[0].match(/^[A-Z]$/),n=e[t]===this.constructor;if(e.isFunction(e[t])&&i&&n)return t}return"Tone"},e.prototype.dispose=function(){return this},e.prototype.set=function(t,i,n){if(e.isObject(t))n=i;else if(e.isString(t)){var o={};o[t]=i,t=o}t:for(var s in t){i=t[s];var r=this;if(-1!==s.indexOf(".")){for(var a=s.split("."),l=0;l<a.length-1;l++)if((r=r[a[l]])instanceof e){a.splice(0,l+1);var h=a.join(".");r.set(h,i);continue t}s=a[a.length-1]}var u=r[s];e.isUndef(u)||(e.Signal&&u instanceof e.Signal||e.Param&&u instanceof e.Param?u.value!==i&&(e.isUndef(n)?u.value=i:u.rampTo(i,n)):u instanceof AudioParam?u.value!==i&&(u.value=i):e.TimeBase&&u instanceof e.TimeBase?r[s]=i:u instanceof e?u.set(i):u!==i&&(r[s]=i))}return this},e.prototype.get=function(t){e.isUndef(t)?t=this._collectDefaults(this.constructor):e.isString(t)&&(t=[t]);for(var i={},n=0;n<t.length;n++){var o=t[n],s=this,r=i;if(-1!==o.indexOf(".")){for(var a=o.split("."),l=0;l<a.length-1;l++){var h=a[l];r[h]=r[h]||{},r=r[h],s=s[h]}o=a[a.length-1]}var u=s[o];e.isObject(t[o])?r[o]=u.get():e.Signal&&u instanceof e.Signal?r[o]=u.value:e.Param&&u instanceof e.Param?r[o]=u.value:u instanceof AudioParam?r[o]=u.value:u instanceof e?r[o]=u.get():!e.isFunction(u)&&e.isDefined(u)&&(r[o]=u)}return i},e.prototype._collectDefaults=function(t){var i=[];if(e.isDefined(t.defaults)&&(i=Object.keys(t.defaults)),e.isDefined(t._super))for(var n=this._collectDefaults(t._super),o=0;o<n.length;o++)-1===i.indexOf(n[o])&&i.push(n[o]);return i},e.defaults=function(t,i,n){var o={};if(1===t.length&&e.isObject(t[0]))o=t[0];else for(var s=0;s<i.length;s++)o[i[s]]=t[s];return e.isDefined(n.defaults)?e.defaultArg(o,n.defaults):e.isObject(n)?e.defaultArg(o,n):o},e.defaultArg=function(t,i){if(e.isObject(t)&&e.isObject(i)){var n={};for(var o in t)n[o]=e.defaultArg(i[o],t[o]);for(var s in i)n[s]=e.defaultArg(t[s],i[s]);return n}return e.isUndef(t)?i:t},e.prototype.log=function(){if(this.debug||this.toString()===e.global.TONE_DEBUG_CLASS){var t=Array.from(arguments);t.unshift(this.toString()+":"),console.log.apply(void 0,t)}},e.prototype.assert=function(t,e){if(!t)throw new Error(e)},e.connectSeries=function(){for(var t=arguments[0],i=1;i<arguments.length;i++){var n=arguments[i];t.connect(n),t=n}return e},e.isUndef=function(t){return void 0===t},e.isDefined=function(t){return!e.isUndef(t)},e.isFunction=function(t){return"function"==typeof t},e.isNumber=function(t){return"number"==typeof t},e.isObject=function(t){return"[object Object]"===Object.prototype.toString.call(t)&&t.constructor===Object},e.isBoolean=function(t){return"boolean"==typeof t},e.isArray=function(t){return Array.isArray(t)},e.isString=function(t){return"string"==typeof t},e.isNote=function(t){return e.isString(t)&&/^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i.test(t)},e.noOp=function(){},e.prototype._readOnly=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._readOnly(t[e]);else Object.defineProperty(this,t,{writable:!1,enumerable:!0})},e.prototype._writable=function(t){if(Array.isArray(t))for(var e=0;e<t.length;e++)this._writable(t[e]);else Object.defineProperty(this,t,{writable:!0})},e.State={Started:"started",Stopped:"stopped",Paused:"paused"},e.global=e.isUndef(n)?window:n,e.equalPowerScale=function(t){var e=.5*Math.PI;return Math.sin(t*e)},e.dbToGain=function(t){return Math.pow(10,t/20)},e.gainToDb=function(t){return Math.log(t)/Math.LN10*20},e.intervalToFrequencyRatio=function(t){return Math.pow(2,t/12)},e.prototype.now=function(){return e.context.now()},e.now=function(){return e.context.now()},e.prototype.immediate=function(){return e.context.currentTime},e.immediate=function(){return e.context.currentTime},e.extend=function(t,i){function n(){}e.isUndef(i)&&(i=e),n.prototype=i.prototype,t.prototype=new n,t.prototype.constructor=t,t._super=i},e._audioContext=null,e.start=function(){return e.context.res
|
||
|
//# sourceMappingURL=Tone.js.map
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./src/audio.ts":
|
||
|
/*!**********************!*\
|
||
|
!*** ./src/audio.ts ***!
|
||
|
\**********************/
|
||
|
/*! exports provided: getSampler, changeSampler */
|
||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||
|
|
||
|
"use strict";
|
||
|
__webpack_require__.r(__webpack_exports__);
|
||
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getSampler", function() { return getSampler; });
|
||
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "changeSampler", function() { return changeSampler; });
|
||
|
/* harmony import */ var tone__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tone */ "./node_modules/tone/build/Tone.js");
|
||
|
/* harmony import */ var tone__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tone__WEBPACK_IMPORTED_MODULE_0__);
|
||
|
/* harmony import */ var _index__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index */ "./src/index.ts");
|
||
|
/* harmony import */ var _data__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./data */ "./src/data.ts");
|
||
|
|
||
|
|
||
|
|
||
|
function setSamplerRelease(sampler, instrument) {
|
||
|
const instrumentDuration = _data__WEBPACK_IMPORTED_MODULE_2__["instrumentData"][instrument]["duration"];
|
||
|
switch (instrumentDuration) {
|
||
|
case "instant":
|
||
|
sampler.release = 0.05;
|
||
|
break;
|
||
|
case "mini":
|
||
|
sampler.release = 0.125;
|
||
|
break;
|
||
|
case "short":
|
||
|
sampler.release = 0.25;
|
||
|
break;
|
||
|
case "mid":
|
||
|
sampler.release = 0.4;
|
||
|
break;
|
||
|
case "long":
|
||
|
sampler.release = 1;
|
||
|
break;
|
||
|
case "extended":
|
||
|
sampler.release = 1.5;
|
||
|
break;
|
||
|
case "mega":
|
||
|
sampler.release = 5;
|
||
|
break;
|
||
|
case "constant":
|
||
|
sampler.release = 30;
|
||
|
break;
|
||
|
case "infinite":
|
||
|
sampler.release = 0.1;
|
||
|
break;
|
||
|
default:
|
||
|
Object(_index__WEBPACK_IMPORTED_MODULE_1__["assertNever"])(instrumentDuration);
|
||
|
}
|
||
|
}
|
||
|
function setSamplerCurve(sampler) {
|
||
|
sampler.curve = "linear";
|
||
|
}
|
||
|
function getSampler(instrument, extension = "ogg", baseUrl = "/bosca-ceoil-js/audio/") {
|
||
|
let samples = {};
|
||
|
for (const note of _index__WEBPACK_IMPORTED_MODULE_1__["notes"]) {
|
||
|
samples[note] = `${instrument}/${note.toLowerCase()}.${extension}`;
|
||
|
}
|
||
|
let sampler = new tone__WEBPACK_IMPORTED_MODULE_0__["Sampler"](samples, undefined, baseUrl);
|
||
|
setSamplerCurve(sampler);
|
||
|
setSamplerRelease(sampler, instrument);
|
||
|
return sampler;
|
||
|
}
|
||
|
function changeSampler(sampler, instrument, extension = "ogg") {
|
||
|
for (const note of _index__WEBPACK_IMPORTED_MODULE_1__["notes"]) {
|
||
|
sampler.add(note, `${instrument}/${note.toLowerCase()}.${extension}`);
|
||
|
}
|
||
|
setSamplerCurve(sampler);
|
||
|
setSamplerRelease(sampler, instrument);
|
||
|
return sampler;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./src/data.ts":
|
||
|
/*!*********************!*\
|
||
|
!*** ./src/data.ts ***!
|
||
|
\*********************/
|
||
|
/*! exports provided: instrumentData */
|
||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||
|
|
||
|
"use strict";
|
||
|
__webpack_require__.r(__webpack_exports__);
|
||
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "instrumentData", function() { return instrumentData; });
|
||
|
const instrumentData = __webpack_require__(/*! ../instruments.yaml */ "./instruments.yaml");
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./src/index.ts":
|
||
|
/*!**********************!*\
|
||
|
!*** ./src/index.ts ***!
|
||
|
\**********************/
|
||
|
/*! exports provided: assertNever, notes */
|
||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||
|
|
||
|
"use strict";
|
||
|
__webpack_require__.r(__webpack_exports__);
|
||
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "assertNever", function() { return assertNever; });
|
||
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "notes", function() { return notes; });
|
||
|
function assertNever(x) {
|
||
|
throw new Error(`Unexhaustive condition leading to value: ${x}`);
|
||
|
}
|
||
|
const notes = ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9"];
|
||
|
|
||
|
|
||
|
/***/ }),
|
||
|
|
||
|
/***/ "./src/player.ts":
|
||
|
/*!***********************!*\
|
||
|
!*** ./src/player.ts ***!
|
||
|
\***********************/
|
||
|
/*! no exports provided */
|
||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||
|
|
||
|
"use strict";
|
||
|
__webpack_require__.r(__webpack_exports__);
|
||
|
/* harmony import */ var tone__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tone */ "./node_modules/tone/build/Tone.js");
|
||
|
/* harmony import */ var tone__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tone__WEBPACK_IMPORTED_MODULE_0__);
|
||
|
/* harmony import */ var _audio__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./audio */ "./src/audio.ts");
|
||
|
|
||
|
|
||
|
const dialogPolyfill = __webpack_require__(/*! dialog-polyfill */ "./node_modules/dialog-polyfill/dist/dialog-polyfill.esm.js");
|
||
|
let playing = false;
|
||
|
const letters = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
||
|
const chords = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||
|
const volume = new tone__WEBPACK_IMPORTED_MODULE_0__["Volume"](0);
|
||
|
const lowPass = new tone__WEBPACK_IMPORTED_MODULE_0__["LowpassCombFilter"](0, 0);
|
||
|
const delayEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["FeedbackDelay"](0, 0);
|
||
|
const chorusEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["Chorus"]();
|
||
|
chorusEffect.wet.value = 0;
|
||
|
const reverbEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["Freeverb"](0, 3000);
|
||
|
reverbEffect.wet.value = 0;
|
||
|
const distortionEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["BitCrusher"](4);
|
||
|
distortionEffect.wet.value = 0;
|
||
|
const lowBoostEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["Filter"](0, "lowshelf");
|
||
|
const compressorEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["Compressor"](0);
|
||
|
const highPassEffect = new tone__WEBPACK_IMPORTED_MODULE_0__["Filter"](0, "highpass");
|
||
|
let instrumentName = "midi.piano1";
|
||
|
let sampler = Object(_audio__WEBPACK_IMPORTED_MODULE_1__["getSampler"])("midi.piano1");
|
||
|
let patterns = {};
|
||
|
for (const chord of chords) {
|
||
|
patterns[chord] = {};
|
||
|
for (const letter of letters) {
|
||
|
patterns[chord][letter] = Array.from({ length: 16 }, () => { return { length: 0, scheduledEvent: null }; });
|
||
|
}
|
||
|
}
|
||
|
function toggleAudio() {
|
||
|
if (playing) {
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].stop();
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].position = "0";
|
||
|
}
|
||
|
else {
|
||
|
resumeAudioContext();
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].loopEnd = '1m';
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].loop = true;
|
||
|
}
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].toggle(0);
|
||
|
playing = !playing;
|
||
|
}
|
||
|
function resumeAudioContext() {
|
||
|
let ac = tone__WEBPACK_IMPORTED_MODULE_0__["context"];
|
||
|
if (ac.state !== "running") {
|
||
|
ac.resume();
|
||
|
}
|
||
|
}
|
||
|
// mdl-selectfield doesn't play nice with custom onchange event listeners,
|
||
|
// so we use this to handle instrument changes instead.
|
||
|
function setInstrumentLoop(instrumentField) {
|
||
|
setInstrument(instrumentField);
|
||
|
setTimeout(() => { setInstrumentLoop(instrumentField); }, 250);
|
||
|
}
|
||
|
function setInstrument(instrumentField) {
|
||
|
if (instrumentName !== instrumentField.value) {
|
||
|
instrumentName = instrumentField.value;
|
||
|
Object(_audio__WEBPACK_IMPORTED_MODULE_1__["changeSampler"])(sampler, instrumentField.value);
|
||
|
}
|
||
|
}
|
||
|
function setBpm() {
|
||
|
let bpmField = document.getElementById("bpm");
|
||
|
if (bpmField !== null && bpmField instanceof HTMLInputElement) {
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].bpm.value = parseInt(bpmField.value);
|
||
|
}
|
||
|
}
|
||
|
function setVolume() {
|
||
|
const field = document.getElementById("volume");
|
||
|
if (field !== null && field instanceof HTMLInputElement) {
|
||
|
let newValue = parseInt(field.value);
|
||
|
if (newValue === 0) {
|
||
|
volume.mute = true;
|
||
|
}
|
||
|
else {
|
||
|
volume.volume.value = (newValue - 100) / 5;
|
||
|
volume.mute = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function setSwing() {
|
||
|
const field = document.getElementById("swing");
|
||
|
if (field !== null && field instanceof HTMLInputElement) {
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].swing = parseFloat(field.value);
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].swingSubdivision = "16n";
|
||
|
}
|
||
|
}
|
||
|
function setResonance() {
|
||
|
const field = document.getElementById("resonance");
|
||
|
if (field !== null && field instanceof HTMLInputElement) {
|
||
|
lowPass.resonance.value = parseFloat(field.value);
|
||
|
}
|
||
|
}
|
||
|
function setDampening() {
|
||
|
const field = document.getElementById("dampening");
|
||
|
if (field !== null && field instanceof HTMLInputElement) {
|
||
|
lowPass.dampening.value = parseInt(field.value);
|
||
|
}
|
||
|
}
|
||
|
function togglePlayButton() {
|
||
|
let playButton = document.getElementById("playButton");
|
||
|
if (playButton !== null) {
|
||
|
if (playButton.textContent !== null && playButton.textContent.trim().toLowerCase() === "play") {
|
||
|
playButton.textContent = "Stop";
|
||
|
}
|
||
|
else {
|
||
|
playButton.textContent = "Play";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function setEffect(effect, value) {
|
||
|
switch (effect) {
|
||
|
case "delay":
|
||
|
delayEffect.delayTime.value = value === 0 ? 0 : tone__WEBPACK_IMPORTED_MODULE_0__["Time"]("8n") * 2 * value;
|
||
|
delayEffect.feedback.value = 0.15 * 2 * value;
|
||
|
break;
|
||
|
case "chorus":
|
||
|
chorusEffect.wet.value = value;
|
||
|
break;
|
||
|
case "reverb":
|
||
|
reverbEffect.roomSize.value = value * 0.9;
|
||
|
reverbEffect.wet.value = value;
|
||
|
break;
|
||
|
case "distortion":
|
||
|
distortionEffect.wet.value = value === 0 ? 0 : 1;
|
||
|
distortionEffect.bits = value;
|
||
|
break;
|
||
|
case "lowBoost":
|
||
|
lowBoostEffect.frequency.value = value;
|
||
|
lowBoostEffect.gain.value = value === 0 ? 0 : 20;
|
||
|
break;
|
||
|
case "compressor":
|
||
|
compressorEffect.threshold.value = value;
|
||
|
break;
|
||
|
case "highPass":
|
||
|
highPassEffect.frequency.value = value;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
function scheduleNote(chord, letter, index, length) {
|
||
|
unscheduleNote(chord, letter, index);
|
||
|
// console.log(`scheduleNote(chord=${chord}, letter=${letter}, index=${index}, length=${length})`);
|
||
|
patterns[chord][letter][index]["length"] = length;
|
||
|
patterns[chord][letter][index]["scheduledEvent"] = tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].schedule(time => {
|
||
|
sampler.triggerAttackRelease(`${letter}${chord}`, tone__WEBPACK_IMPORTED_MODULE_0__["Time"]("16n") * length, time);
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Draw"].schedule(() => {
|
||
|
const noteElement = document.querySelector(`#${letter.replace("#", "\\#")}-${chord}-${index}`);
|
||
|
if (noteElement !== null) {
|
||
|
if (length <= 1) {
|
||
|
noteElement.classList.add("playing");
|
||
|
}
|
||
|
else {
|
||
|
noteElement.classList.add("playingLong");
|
||
|
}
|
||
|
setTimeout(() => {
|
||
|
noteElement.classList.remove("playing");
|
||
|
noteElement.classList.remove("playingLong");
|
||
|
}, 100 * length);
|
||
|
}
|
||
|
}, time);
|
||
|
}, `0:0:${index}`);
|
||
|
}
|
||
|
function unscheduleNote(chord, letter, index) {
|
||
|
patterns[chord][letter][index]["length"] = 0;
|
||
|
const schedulee = patterns[chord][letter][index]["scheduledEvent"];
|
||
|
if (schedulee !== null) {
|
||
|
tone__WEBPACK_IMPORTED_MODULE_0__["Transport"].clear(schedulee);
|
||
|
patterns[chord][letter][index]["scheduledEvent"] = null;
|
||
|
}
|
||
|
}
|
||
|
function onClickNoteCell(event, cell, chord, letter, index) {
|
||
|
let length = patterns[chord][letter][index]["length"];
|
||
|
// console.log(`onClickNoteCell(chord=${chord}, letter=${letter}, index=${index}) | length ${length}`);
|
||
|
if (event.shiftKey && event.ctrlKey) {
|
||
|
length = Math.max(length - 1, 0);
|
||
|
}
|
||
|
else if (event.shiftKey) {
|
||
|
length = Math.max(Math.min(length + 1, 16), 2);
|
||
|
}
|
||
|
else if (length > 0) {
|
||
|
length = 0;
|
||
|
}
|
||
|
else {
|
||
|
length = 1;
|
||
|
}
|
||
|
cell.innerHTML = length.toString();
|
||
|
if (length <= 1) {
|
||
|
cell.classList.remove("noteLong");
|
||
|
}
|
||
|
else {
|
||
|
cell.classList.add("noteLong");
|
||
|
}
|
||
|
if (length > 0 && length !== patterns[chord][letter][index]["length"]) {
|
||
|
cell.classList.add("active");
|
||
|
scheduleNote(chord, letter, index, length);
|
||
|
}
|
||
|
else if (length === 0) {
|
||
|
cell.classList.remove("active");
|
||
|
unscheduleNote(chord, letter, index);
|
||
|
}
|
||
|
}
|
||
|
function onLoad() {
|
||
|
sampler.chain(volume, lowPass, delayEffect, chorusEffect, reverbEffect, distortionEffect, lowBoostEffect, compressorEffect, highPassEffect, tone__WEBPACK_IMPORTED_MODULE_0__["Master"]);
|
||
|
document.onkeypress = event => {
|
||
|
if (event.keyCode === 32) {
|
||
|
toggleAudio();
|
||
|
togglePlayButton();
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
let playButton = document.getElementById("playButton");
|
||
|
if (playButton !== null) {
|
||
|
playButton.addEventListener("click", toggleAudio);
|
||
|
playButton.addEventListener("click", togglePlayButton);
|
||
|
}
|
||
|
let helpButton = document.getElementById("helpButton");
|
||
|
let helpModal = document.getElementById("helpModal");
|
||
|
if (helpButton !== null && helpModal !== null) {
|
||
|
if (!helpModal.showModal) {
|
||
|
dialogPolyfill.default.registerDialog(helpModal);
|
||
|
}
|
||
|
helpButton.addEventListener("click", () => { helpModal.showModal(); });
|
||
|
const helpModalClose = helpModal.querySelector(".close");
|
||
|
if (helpModalClose !== null) {
|
||
|
helpModalClose.addEventListener("click", () => {
|
||
|
helpModal.close();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
let instrumentField = document.getElementById("instruments");
|
||
|
if (instrumentField !== null && instrumentField instanceof HTMLSelectElement) {
|
||
|
setInstrumentLoop(instrumentField);
|
||
|
}
|
||
|
let bpmField = document.getElementById("bpm");
|
||
|
if (bpmField !== null) {
|
||
|
bpmField.addEventListener("change", setBpm);
|
||
|
}
|
||
|
let effectsMenu = document.getElementById("effectsMenu");
|
||
|
if (effectsMenu !== null) {
|
||
|
effectsMenu.addEventListener("click", event => {
|
||
|
event.stopPropagation();
|
||
|
});
|
||
|
}
|
||
|
const effects = ["delay", "chorus", "reverb", "distortion", "lowBoost", "compressor", "highPass"];
|
||
|
for (const effect of effects) {
|
||
|
const effectField = document.getElementById(`${effect}Effect`);
|
||
|
if (effectField !== null && effectField instanceof HTMLInputElement) {
|
||
|
effectField.addEventListener("change", () => {
|
||
|
setEffect(effect, parseFloat(effectField.value));
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
let patternTable = document.getElementById("pattern");
|
||
|
if (patternTable !== null && patternTable instanceof HTMLTableElement) {
|
||
|
for (const chord of chords.slice().reverse()) {
|
||
|
let first = true;
|
||
|
for (const letter of letters.slice().reverse()) {
|
||
|
let row = patternTable.insertRow();
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
let chordHeader = document.createElement("th");
|
||
|
chordHeader.rowSpan = letters.length;
|
||
|
chordHeader.innerHTML = chord.toString();
|
||
|
row.appendChild(chordHeader);
|
||
|
}
|
||
|
let letterHeader = document.createElement("th");
|
||
|
letterHeader.innerHTML = letter;
|
||
|
row.appendChild(letterHeader);
|
||
|
for (const i of Array(16).keys()) {
|
||
|
let cell = row.insertCell();
|
||
|
cell.id = `${letter}-${chord}-${i}`;
|
||
|
cell.classList.add(`note-${letter}`);
|
||
|
cell.onclick = event => { onClickNoteCell(event, cell, chord, letter, i); };
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const centralRow = document.getElementById("F-5-0");
|
||
|
if (centralRow !== null) {
|
||
|
centralRow.scrollIntoView({ "behavior": "smooth", "block": "center" });
|
||
|
}
|
||
|
let volumeField = document.getElementById("volume");
|
||
|
if (volumeField !== null) {
|
||
|
volumeField.addEventListener("change", setVolume);
|
||
|
}
|
||
|
let swingField = document.getElementById("swing");
|
||
|
if (swingField !== null) {
|
||
|
swingField.addEventListener("change", setSwing);
|
||
|
}
|
||
|
let resonanceField = document.getElementById("resonance");
|
||
|
if (resonanceField !== null) {
|
||
|
resonanceField.addEventListener("change", setResonance);
|
||
|
}
|
||
|
let dampeningField = document.getElementById("dampening");
|
||
|
if (dampeningField !== null) {
|
||
|
dampeningField.addEventListener("change", setDampening);
|
||
|
}
|
||
|
}
|
||
|
window.onload = onLoad;
|
||
|
|
||
|
|
||
|
/***/ })
|
||
|
|
||
|
/******/ });
|
||
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vaW5zdHJ1bWVudHMueWFtbCIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvZGlhbG9nLXBvbHlmaWxsL2Rpc3QvZGlhbG9nLXBvbHlmaWxsLmVzbS5qcyIsIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvdG9uZS9idWlsZC9Ub25lLmpzIiwid2VicGFjazovLy8uL3NyYy9hdWRpby50cyIsIndlYnBhY2s6Ly8vLi9zcmMvZGF0YS50cyIsIndlYnBhY2s6Ly8vLi9zcmMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vLy4vc3JjL3BsYXllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxrREFBMEMsZ0NBQWdDO0FBQzFFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0VBQXdELGtCQUFrQjtBQUMxRTtBQUNBLHlEQUFpRCxjQUFjO0FBQy9EOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBeUMsaUNBQWlDO0FBQzFFLHdIQUFnSCxtQkFBbUIsRUFBRTtBQUNySTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1DQUEyQiwwQkFBMEIsRUFBRTtBQUN2RCx5Q0FBaUMsZUFBZTtBQUNoRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw4REFBc0QsK0RBQStEOztBQUVySDtBQUNBOzs7QUFHQTtBQUNBOzs7Ozs7Ozs7Ozs7QUNsRkEsZUFBZSxnQkFBZ0IsMkVBQTJFLG1CQUFtQiwwRUFBMEUsbUJBQW1CLGdGQUFnRixvQkFBb0IsOEVBQThFLGtCQUFrQiwrRUFBK0UscUJBQXFCLHdFQUF3RSxzQkFBc0IsbUZBQW1GLG1CQUFtQix1RUFBdUUsa0JBQWtCLDBFQUEwRSxrQkFBa0Isc0VBQXNFLGtCQUFrQiwwRUFBMEUsaUJBQWlCLDBFQUEwRSxnQkFBZ0Isb0VBQW9FLG1CQUFtQiwwRUFBMEUsb0JBQW9CLDRFQUE0RSxnQkFBZ0IsNkVBQTZFLGNBQWMsMkVBQTJFLEVBQUU7QUFDamtELGdEOzs7Ozs7Ozs7Ozs7QUNEQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWSxRQUFRO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWSxrQkFBa0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0Isa0JBQWtCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLFVBQVU7QUFDckIsV0FBVyxLQUFLO0FBQ2hCLFlBQVksUUFBUTtBQUNwQjtBQUNBO0FBQ0EsaUJBQWlCLHFCQUFxQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLGdCQUFnQjtBQUMzQixZQUFZLFFBQVE7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXLG1CQUFtQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esd0JBQXdCLDRDQUE0QztBQUNwRSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLGlDQUFpQyxRQUFRLEVBQUU7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0ZBQW9GLFFBQVE7QUFDNUY7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLFFBQVE7QUFDckM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsNEJBQTRCO0FBQzVCO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLGtFQUFrRTtBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCLGFBQWEsT0FBTztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUN
|