@internetarchive/bookreader 5.0.0-49-a1 → 5.0.0-49
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1 -1
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/CHANGELOG.md +5 -0
- package/package.json +1 -1
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"plugins/plugin.tts.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/tts/PageChunk.js","webpack://@internetarchive/bookreader/./src/plugins/tts/PageChunkIterator.js","webpack://@internetarchive/bookreader/./src/plugins/tts/AbstractTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/FestivalTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/utils.js","webpack://@internetarchive/bookreader/./src/plugins/tts/plugin.tts.js","webpack://@internetarchive/bookreader/./src/plugins/tts/WebTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/tooltip_dict.js","webpack://@internetarchive/bookreader/./src/util/browserSniffing.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.match.js","webpack://@internetarchive/bookreader/./node_modules/iso-language-codes/js/data.js","webpack://@internetarchive/bookreader/./node_modules/jquery.browser/dist/jquery.browser.js","webpack://@internetarchive/bookreader/./node_modules/soundmanager2/script/soundmanager2.js"],"sourcesContent":["/**\n * Class to manage a 'chunk' (approximately a paragraph) of text on a page.\n */\nexport default class PageChunk {\n /**\n * @param {number} leafIndex\n * @param {number} chunkIndex\n * @param {string} text\n * @param {DJVURect[]} lineRects\n */\n constructor(leafIndex, chunkIndex, text, lineRects) {\n this.leafIndex = leafIndex;\n this.chunkIndex = chunkIndex;\n this.text = text;\n this.lineRects = lineRects;\n }\n\n /**\n * @param {string} server\n * @param {string} bookPath\n * @param {number} leafIndex\n * @return {Promise<PageChunk[]>}\n */\n static async fetch(server, bookPath, leafIndex) {\n const chunks = await $.ajax({\n type: 'GET',\n url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,\n dataType:'jsonp',\n cache: true,\n data: {\n path: `${bookPath}_djvu.xml`,\n page: leafIndex\n }\n });\n return PageChunk._fromTextWrapperResponse(leafIndex, chunks);\n }\n\n /**\n * Convert the response from BookReaderGetTextWrapper.php into a {@link PageChunk} instance\n * @param {number} leafIndex\n * @param {Array<[String, ...DJVURect[]]>} chunksResponse\n * @return {PageChunk[]}\n */\n static _fromTextWrapperResponse(leafIndex, chunksResponse) {\n return chunksResponse.map((c, i) => {\n const correctedLineRects = PageChunk._fixChunkRects(c.slice(1));\n const correctedText = PageChunk._removeDanglingHyphens(c[0]);\n return new PageChunk(leafIndex, i, correctedText, correctedLineRects);\n });\n }\n\n /**\n * @private\n * Sometimes the first rectangle will be ridiculously wide/tall. Find those and fix them\n * *NOTE*: Modifies the original array and returns it.\n * *NOTE*: This should probably be fixed on the petabox side, and then removed here\n * Has 2 problems:\n * - If the rect is the last rect on the page (and hence the only rect in the array),\n * the rect's size isn't fixed\n * - Because this relies on the second rect, there's a chance it won't be the right\n * width\n * @param {DJVURect[]} rects\n * @return {DJVURect[]}\n */\n static _fixChunkRects(rects) {\n if (rects.length < 2) return rects;\n\n const [firstRect, secondRect] = rects;\n const [left, bottom, right] = firstRect;\n const width = right - left;\n const secondHeight = secondRect[1] - secondRect[3];\n const secondWidth = secondRect[2] - secondRect[0];\n const secondRight = secondRect[2];\n\n if (width > secondWidth * 30) {\n // Set the end to be the same\n firstRect[2] = secondRight;\n // And the top to be the same height\n firstRect[3] = bottom - secondHeight;\n }\n\n return rects;\n }\n\n /**\n * Remove \"dangling\" hyphens from read aloud text to avoid TTS stuttering\n * @param {string} text\n * @return {string}\n */\n static _removeDanglingHyphens(text) {\n // Some books mis-OCR a dangling hyphen as a ¬ (mathematical not sign) . Since in math\n // the not sign should not appear followed by a space, we think we can safely assume\n // this should be replaced.\n return text.replace(/[-¬]\\s+/g, '');\n }\n}\n\n/**\n * @typedef {[number, number, number, number]} DJVURect\n * coords are in l,b,r,t order\n */\n","import PageChunk from './PageChunk.js';\n\n/**\n * Class that iterates over the page chunks of a book; caching/buffering\n * as much as possible to try to ensure a smooth experience.\n */\nexport default class PageChunkIterator {\n /**\n * @param {number} pageCount total number of pages\n * @param {number} start page to start on\n * @param {PageChunkIteratorOptions} opts\n */\n constructor(pageCount, start, opts) {\n this.pageCount = pageCount;\n this.opts = Object.assign({}, DEFAULT_OPTS, opts);\n /** Position in the chunk sequence */\n this._cursor = { page: start, chunk: 0 };\n /** @type {Object<number, PageChunk[]>} leaf index -> chunks*/\n this._bufferedPages = {};\n /** @type {Object<number, PromiseLike<PageChunk[]>} leaf index -> chunks*/\n this._bufferingPages = {};\n /**\n * @type {Promise} promise that manages cursor modifications so that they\n * happen in order triggered as opposed to order the server responds\n **/\n this._cursorLock = Promise.resolve();\n }\n\n /**\n * Get the next chunk\n * @return {PromiseLike<\"__PageChunkIterator.AT_END__\" | PageChunk>}\n */\n next() {\n return this._cursorLock = this._cursorLock\n .then(() => this._nextUncontrolled());\n }\n\n /**\n * Sends the cursor back 1\n * @return {Promise}\n **/\n decrement() {\n return this._cursorLock = this._cursorLock\n .then(() => this._decrementUncontrolled());\n }\n\n /**\n * Gets without ensuring synchronization. Since this iterator has a lot of async\n * code, calling e.g. \"next\" twice (before the first call to next has finished)\n * would cause the system to be in a weird state. To avoid that, we make sure calls\n * to next and decrement (functions that modify the cursor) are synchronized,\n * so that regardless how long it takes for one to respond, they'll always be executed\n * in the correct order.\n * @return {PromiseLike<\"__PageChunkIterator.AT_END__\" | PageChunk>}\n */\n async _nextUncontrolled() {\n if (this._cursor.page == this.pageCount) {\n return Promise.resolve(PageChunkIterator.AT_END);\n }\n this._recenterBuffer(this._cursor.page);\n const chunks = await this._fetchPageChunks(this._cursor.page);\n if (this._cursor.chunk == chunks.length) {\n this._cursor.page++;\n this._cursor.chunk = 0;\n return this._nextUncontrolled();\n }\n return chunks[this._cursor.chunk++];\n }\n\n /**\n * Decrements without ensuring synchronization. (See {@link PageChunkIterator._nextUncontrolled});\n * @return {Promise}\n */\n _decrementUncontrolled() {\n let cursorChangePromise = Promise.resolve();\n\n if (this._cursor.chunk > 0) {\n this._cursor.chunk--;\n } else if (this._cursor.page > 0) {\n this._cursor.page--;\n // Go back possibly multiple pages, because pages can be blank\n cursorChangePromise = this._fetchPageChunks(this._cursor.page)\n .then(prevPageChunks => {\n if (prevPageChunks.length == 0) return this._decrementUncontrolled();\n else this._cursor.chunk = prevPageChunks.length - 1;\n });\n }\n\n return cursorChangePromise\n .then(() => this._fetchPageChunks(this._cursor.page));\n }\n\n /**\n * Recenter the buffer around the provided page index\n * @param {number} index\n */\n _recenterBuffer(index) {\n const start = Math.max(0, index - this.opts.pageBufferSize);\n const end = Math.min(this.pageCount, index + this.opts.pageBufferSize + 1);\n for (let i = start; i < end; i++) {\n this._fetchPageChunks(i);\n }\n\n this._removePageFromBuffer(start - 1);\n this._removePageFromBuffer(end + 1);\n }\n\n /**\n * @param {number} index\n */\n _removePageFromBuffer(index) {\n delete this._bufferingPages[index];\n delete this._bufferedPages[index];\n }\n\n /**\n * Fetches the chunks on a page; checks the buffer, so it won't make unnecessary\n * requests if it's called multiple times for the same index.\n * @param {number} index\n * @return {Promise<PageChunk[]>}\n */\n _fetchPageChunks(index) {\n if (index in this._bufferingPages) return this._bufferingPages[index];\n if (index in this._bufferedPages) return Promise.resolve(this._bufferedPages[index]);\n\n this._bufferingPages[index] = this._fetchPageChunksDirect(index)\n .then(chunks => {\n delete this._bufferingPages[index];\n this._bufferedPages[index] = chunks;\n return chunks;\n });\n\n return this._bufferingPages[index];\n }\n\n /**\n * Fetches a page without checking buffer\n * @param {number} index\n */\n _fetchPageChunksDirect(index) {\n return PageChunk.fetch(this.opts.server, this.opts.bookPath, index);\n }\n}\n\nPageChunkIterator.AT_END = \"__PageChunkIterator.AT_END__\";\n\n/** @type {PageChunkIteratorOptions} */\nconst DEFAULT_OPTS = {\n server: null,\n bookPath: null,\n pageBufferSize: 2,\n};\n\n/**\n * @typedef {Object} PageChunkIteratorOptions\n * @property {string} server\n * @property {string} bookPath\n * @property {number} [pageBufferSize] number of pages to buffer before/after the current page\n */\n","import PageChunkIterator from './PageChunkIterator.js';\n/** @typedef {import('./utils.js').ISO6391} ISO6391 */\n/** @typedef {import('./PageChunk.js')} PageChunk */\n\n/**\n * @export\n * @typedef {Object} TTSEngineOptions\n * @property {String} server\n * @property {String} bookPath\n * @property {ISO6391} bookLanguage\n * @property {Function} onLoadingStart\n * @property {Function} onLoadingComplete\n * @property {Function} onDone called when the entire book is done\n * @property {function(PageChunk): PromiseLike} beforeChunkPlay will delay the playing of the chunk\n * @property {function(PageChunk): void} afterChunkPlay fires once a chunk has fully finished\n */\n\n/**\n * @typedef {Object} AbstractTTSSound\n * @property {PageChunk} chunk\n * @property {boolean} loaded\n * @property {number} rate\n * @property {SpeechSynthesisVoice} voice\n * @property {(callback: Function) => void} load\n * @property {() => PromiseLike} play\n * @property {() => Promise} stop\n * @property {() => void} pause\n * @property {() => void} resume\n * @property {() => void} finish force the sound to 'finish'\n * @property {number => void} setPlaybackRate\n * @property {SpeechSynthesisVoice => void} setVoice\n **/\n\n/** Handling bookreader's text-to-speech */\nexport default class AbstractTTSEngine {\n /**\n * @protected\n * @param {TTSEngineOptions} options\n */\n constructor(options) {\n this.playing = false;\n this.paused = false;\n this.opts = options;\n /** @type {PageChunkIterator} */\n this._chunkIterator = null;\n /** @type {AbstractTTSSound} */\n this.activeSound = null;\n this.playbackRate = 1;\n /** Events we can bind to */\n this.events = $({});\n /** @type {SpeechSynthesisVoice} */\n this.voice = null;\n // Listen for voice changes (fired by subclasses)\n this.events.on('voiceschanged', this.updateBestVoice);\n this.events.trigger('voiceschanged');\n }\n\n /**\n * @abstract\n * @return {boolean}\n */\n static isSupported() { throw new Error(\"Unimplemented abstract class\"); }\n\n /**\n * @abstract\n * @return {SpeechSynthesisVoice[]}\n */\n getVoices() { throw new Error(\"Unimplemented abstract class\"); }\n\n /** @abstract */\n init() { return null; }\n\n updateBestVoice = () => {\n this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);\n }\n\n /**\n * @param {number} leafIndex\n * @param {number} numLeafs total number of leafs in the current book\n */\n start(leafIndex, numLeafs) {\n this.playing = true;\n this.opts.onLoadingStart();\n\n this._chunkIterator = new PageChunkIterator(numLeafs, leafIndex, {\n server: this.opts.server,\n bookPath: this.opts.bookPath,\n pageBufferSize: 5,\n });\n\n this.step();\n this.events.trigger('start');\n }\n\n stop() {\n if (this.activeSound) this.activeSound.stop();\n this.playing = false;\n this._chunkIterator = null;\n this.activeSound = null;\n this.events.trigger('stop');\n }\n\n /** @public */\n pause() {\n const fireEvent = !this.paused && this.activeSound;\n this.paused = true;\n if (this.activeSound) this.activeSound.pause();\n if (fireEvent) this.events.trigger('pause');\n }\n\n /** @public */\n resume() {\n const fireEvent = this.paused && this.activeSound;\n this.paused = false;\n if (this.activeSound) this.activeSound.resume();\n if (fireEvent) this.events.trigger('resume');\n }\n\n togglePlayPause() {\n if (this.paused) this.resume();\n else this.pause();\n }\n\n /** @public */\n jumpForward() {\n if (this.activeSound) this.activeSound.finish();\n }\n\n /** @public */\n async jumpBackward() {\n await Promise.all([\n this.activeSound.stop(),\n this._chunkIterator.decrement()\n .then(() => this._chunkIterator.decrement())\n ]);\n this.step();\n }\n\n /** @param {string} voiceURI */\n setVoice(voiceURI) {\n // if the user actively selects a voice, don't re-choose best voice anymore\n // MS Edge fires voices changed randomly very often\n this.events.off('voiceschanged', this.updateBestVoice);\n this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);\n if (this.activeSound) this.activeSound.setVoice(this.voice);\n }\n\n /** @param {number} newRate */\n setPlaybackRate(newRate) {\n this.playbackRate = newRate;\n if (this.activeSound) this.activeSound.setPlaybackRate(newRate);\n }\n\n /** @private */\n async step() {\n const chunk = await this._chunkIterator.next();\n if (chunk == PageChunkIterator.AT_END) {\n this.stop();\n this.opts.onDone();\n return;\n }\n this.opts.onLoadingStart();\n const sound = this.createSound(chunk);\n sound.chunk = chunk;\n sound.rate = this.playbackRate;\n sound.voice = this.voice;\n sound.load(() => this.opts.onLoadingComplete());\n\n this.opts.onLoadingComplete();\n\n await this.opts.beforeChunkPlay(chunk);\n\n if (!this.playing) return;\n\n const playPromise = await this.playSound(sound)\n .then(()=> this.opts.afterChunkPlay(sound.chunk));\n\n if (this.paused) this.pause();\n await playPromise;\n\n if (this.playing) return this.step();\n }\n\n /**\n * @abstract\n * @param {PageChunk} chunk\n * @return {AbstractTTSSound}\n */\n createSound(chunk) { throw new Error(\"Unimplemented abstract class\"); }\n\n /**\n * @param {AbstractTTSSound} sound\n * @return {PromiseLike} promise called once playing finished\n */\n playSound(sound) {\n this.activeSound = sound;\n if (!this.activeSound.loaded) this.opts.onLoadingStart();\n return this.activeSound.play();\n }\n\n /** Convenience wrapper for {@see AbstractTTSEngine.getBestVoice} */\n getBestVoice() {\n return AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);\n }\n\n /**\n * @private\n * Find the best voice to use given the available voices, the book language, and the user's\n * languages.\n * @param {SpeechSynthesisVoice[]} voices\n * @param {ISO6391} bookLanguage\n * @param {string[]} userLanguages languages in BCP47 format (e.g. en-US). Ordered by preference.\n * @return {SpeechSynthesisVoice | undefined}\n */\n static getBestBookVoice(voices, bookLanguage, userLanguages = navigator.languages) {\n const bookLangVoices = voices.filter(v => v.lang.startsWith(bookLanguage));\n // navigator.languages browser support isn't great yet, so get just 1 language otherwise\n // Sample navigator.languages: [\"en-CA\", \"fr-CA\", \"fr\", \"en-US\", \"en\", \"de-DE\", \"de\"]\n userLanguages = userLanguages || (navigator.language ? [navigator.language] : []);\n\n // user languages that match the book language\n const matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));\n\n // Try to find voices that intersect these two sets\n return AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices) ||\n // no user languages match the books; let's return the best voice for the book language\n (bookLangVoices.find(v => v.default) || bookLangVoices[0])\n // No voices match the book language? let's find a voice in the user's language\n // and ignore book lang\n || AbstractTTSEngine.getMatchingVoice(userLanguages, voices)\n // C'mon! Ok, just read with whatever we got!\n || (voices.find(v => v.default) || voices[0]);\n }\n\n /**\n * @private\n * Get the best voice that matches one of the BCP47 languages (order by preference)\n * @param {string[]} languages in BCP 47 format (e.g. 'en-US', or 'en'); ordered by preference\n * @param {SpeechSynthesisVoice[]} voices voices to choose from\n * @return {SpeechSynthesisVoice | undefined}\n */\n static getMatchingVoice(languages, voices) {\n for (const lang of languages) {\n // Chrome Android was returning voice languages like `en_US` instead of `en-US`\n const matchingVoices = voices.filter(v => v.lang.replace('_', '-').startsWith(lang));\n if (matchingVoices.length) {\n return matchingVoices.find(v => v.default) || matchingVoices[0];\n }\n }\n }\n}\n","import AbstractTTSEngine from './AbstractTTSEngine.js';\nimport { sleep } from '../../BookReader/utils.js';\n/* global soundManager */\nimport 'soundmanager2';\nimport 'jquery.browser';\n\n/** @typedef {import(\"./AbstractTTSEngine.js\").TTSEngineOptions} TTSEngineOptions */\n/** @typedef {import(\"./AbstractTTSEngine.js\").AbstractTTSSound} AbstractTTSSound */\n\n/**\n * @extends AbstractTTSEngine\n * TTS using Festival endpoint\n **/\nexport default class FestivalTTSEngine extends AbstractTTSEngine {\n /** @override */\n static isSupported() {\n return typeof(soundManager) !== 'undefined' && soundManager.supported();\n }\n\n /** @param {TTSEngineOptions} options */\n constructor(options) {\n super(options);\n // $.browsers is sometimes undefined on some Android browsers :/\n // Likely related to when $.browser was moved to npm\n /** @type {'mp3' | 'ogg'} format of audio to get */\n this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3'; //eslint-disable-line no-jquery/no-browser\n }\n\n /** @override */\n getVoices() {\n return [\n { default: true, lang: \"en-US\", localService: false, name: \"Festival - English (US)\", voiceURI: null }\n ];\n }\n\n /** @override */\n init() {\n // setup sound manager\n soundManager.setup({\n debugMode: false,\n // Note, there's a bug in Chrome regarding range requests.\n // Flash is used as a workaround.\n // See https://bugs.chromium.org/p/chromium/issues/detail?id=505707\n preferFlash: true,\n url: '/bookreader/BookReader/soundmanager/swf',\n useHTML5Audio: true,\n //flash 8 version of swf is buggy when calling play() on a sound that is still loading\n flashVersion: 9\n });\n }\n\n /**\n * @override\n * @param {number} leafIndex\n * @param {number} numLeafs total number of leafs in the current book\n */\n start(leafIndex, numLeafs) {\n let promise = null;\n\n // Hack for iOS\n if (navigator.userAgent.match(/mobile/i)) {\n promise = this.iOSCaptureUserIntentHack();\n }\n\n promise = promise || Promise.resolve();\n promise.then(() => super.start(leafIndex, numLeafs));\n }\n\n /** @override */\n createSound(chunk) {\n return new FestivalTTSSound(this.getSoundUrl(chunk.text));\n }\n\n /**\n * @private\n * Get URL for audio that says this text\n * @param {String} dataString the thing to say\n * @return {String} url\n */\n getSoundUrl(dataString) {\n return 'https://' + this.opts.server + '/BookReader/BookReaderGetTTS.php?string='\n + encodeURIComponent(dataString)\n + '&format=.' + this.audioFormat;\n }\n\n /**\n * @private\n * Security restrictions require playback to be triggered\n * by a user click/touch. This intention gets lost in the async calls\n * on iOS, but, for some reason, if we start the audio here, it works.\n * See https://stackoverflow.com/questions/12206631/html5-audio-cant-play-through-javascript-unless-triggered-manually-once\n * @return {PromiseLike}\n */\n async iOSCaptureUserIntentHack() {\n const sound = soundManager.createSound({ url: SILENCE_1MS[this.audioFormat] });\n await new Promise(res => sound.play({onfinish: res}));\n sound.destruct();\n }\n}\n\n/** @extends AbstractTTSSound */\nclass FestivalTTSSound {\n /** @param {string} soundUrl **/\n constructor(soundUrl) {\n this.soundUrl = soundUrl;\n /** @type {SMSound} */\n this.sound = null;\n this.rate = 1;\n /** @type {function} calling this resolves the \"play\" promise */\n this._finishResolver = null;\n }\n\n get loaded() {\n return this.sound && this.sound.loaded;\n }\n\n load(onload) {\n this.sound = soundManager.createSound({\n url: this.soundUrl,\n // API recommended, but only fires once play started on safari\n onload: () => {\n if (this.rate != 1) this.sound.setPlaybackRate(this.rate);\n onload();\n },\n onresume: async () => {\n await sleep(25);\n if (this.rate != 1) this.sound.setPlaybackRate(this.rate);\n }\n });\n return this.sound.load();\n }\n\n async play() {\n await new Promise(res => {\n this._finishResolver = res;\n this.sound.play({ onfinish: res });\n });\n this.sound.destruct();\n }\n\n /** @override */\n stop() {\n this.sound.stop();\n return Promise.resolve();\n }\n\n /** @override */\n pause() { this.sound.pause(); }\n /** @override */\n resume() { this.sound.resume(); }\n /** @override */\n setPlaybackRate(rate) {\n this.rate = rate;\n this.sound.setPlaybackRate(rate);\n }\n\n /** @override */\n finish() {\n this.sound.stop();\n this._finishResolver();\n }\n}\n\n/** Needed to capture the audio context for iOS hack. Generated using Audacity. */\nconst SILENCE_1MS = {\n mp3: 'data:audio/mp3;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAACAAACcQCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA//////////////////////////////////////////////////////////////////8AAAAeTEFNRTMuOTlyBJwAAAAAAAAAADUgJAaUQQABrgAAAnHIf8sZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//sQxAADwlwBKGAAACAAAD/AAAAEAAAAH///////////////+UBAMExBTUUzLjk5LjOqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDEIAPAAAGkAAAAIAAANIAAAASqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==',\n ogg: 'data:audio/ogg;base64,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',\n};\n","import langs from 'iso-language-codes/js/data.js';\n\n/**\n * Convert a EventTarget style event into a promise\n * @param {EventTarget} target\n * @param {string} eventType\n * @return {Promise<Event>}\n */\nexport function promisifyEvent(target, eventType) {\n return new Promise(res => {\n const resolver = ev => {\n target.removeEventListener(eventType, resolver);\n res(ev);\n };\n target.addEventListener(eventType, resolver);\n });\n}\n\n/**\n * Use regex to approximate word count in a string\n * @param {string} text\n * @return {number}\n */\nexport function approximateWordCount(text) {\n const m = text.match(/\\S+/g);\n return m ? m.length : 0;\n}\n\n/**\n * Checks whether the current browser is on android\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isAndroid(userAgent = navigator.userAgent) {\n return /android/i.test(userAgent);\n}\n\n/**\n * @typedef {string} ISO6391\n * Language code in ISO 639-1 format. e.g. en, fr, zh\n **/\n\n/** Each lang is an array, with each index mapping to a different property */\nconst COLUMN_TO_LANG_INDEX = {\n 'Name': 0,\n 'Endonym': 1,\n 'ISO 639-1': 2,\n 'ISO 639-2/T': 3,\n 'ISO 639-2/B': 4\n};\n\n/**\n * @param {string} language in some format\n * @return {ISO6391?}\n */\nexport function toISO6391(language) {\n if (!language) return null;\n language = language.toLowerCase();\n\n return searchForISO6391(language, ['ISO 639-1']) ||\n searchForISO6391(language, ['ISO 639-2/B']) ||\n searchForISO6391(language, ['ISO 639-2/T', 'Endonym', 'Name']);\n}\n\n/**\n * Searches for the given long in the given columns.\n * @param {string} language\n * @param {Array<keyof COLUMN_TO_LANG_INDEX>} columnsToSearch\n * @return {ISO6391?}\n */\nfunction searchForISO6391(language, columnsToSearch) {\n for (let i = 0; i < langs.length; i++) {\n for (let colI = 0; colI < columnsToSearch.length; colI++) {\n const column = columnsToSearch[colI];\n const columnValue = langs[i][COLUMN_TO_LANG_INDEX[column]];\n if (columnValue.split(', ').map(x => x.toLowerCase()).indexOf(language) != -1) {\n return langs[i][COLUMN_TO_LANG_INDEX['ISO 639-1']];\n }\n }\n }\n return null;\n}\n","/* global BookReader */\n/**\n * Plugin for Text to Speech in BookReader\n */\nimport FestivalTTSEngine from './FestivalTTSEngine.js';\nimport WebTTSEngine from './WebTTSEngine.js';\nimport { toISO6391, approximateWordCount } from './utils.js';\nimport { en as tooltips } from './tooltip_dict.js';\nimport { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';\n/** @typedef {import('./PageChunk.js').default} PageChunk */\n/** @typedef {import(\"./AbstractTTSEngine.js\").default} AbstractTTSEngine */\n\n// Default options for TTS\njQuery.extend(BookReader.defaultOptions, {\n server: 'ia600609.us.archive.org',\n bookPath: '',\n enableTtsPlugin: true,\n});\n\n// Extend the constructor to add TTS properties\nBookReader.prototype.setup = (function (super_) {\n return function (options) {\n super_.call(this, options);\n\n if (this.options.enableTtsPlugin) {\n /** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */\n this._ttsBoxesByIndex = {};\n\n let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :\n FestivalTTSEngine.isSupported() ? FestivalTTSEngine :\n null;\n\n if (/_forceTTSEngine=(festival|web)/.test(location.toString())) {\n const engineName = location.toString().match(/_forceTTSEngine=(festival|web)/)[1];\n TTSEngine = { festival: FestivalTTSEngine, web: WebTTSEngine }[engineName];\n }\n\n if (TTSEngine) {\n /** @type {AbstractTTSEngine} */\n this.ttsEngine = new TTSEngine({\n server: options.server,\n bookPath: options.bookPath,\n bookLanguage: toISO6391(options.bookLanguage),\n onLoadingStart: this.showProgressPopup.bind(this, 'Loading audio...'),\n onLoadingComplete: this.removeProgressPopup.bind(this),\n onDone: this.ttsStop.bind(this),\n beforeChunkPlay: this.ttsBeforeChunkPlay.bind(this),\n afterChunkPlay: this.ttsSendChunkFinishedAnalyticsEvent.bind(this),\n });\n }\n }\n };\n})(BookReader.prototype.setup);\n\nBookReader.prototype.init = (function(super_) {\n return function() {\n if (this.options.enableTtsPlugin) {\n // Bind to events\n\n this.bind(BookReader.eventNames.PostInit, () => {\n this.$('.BRicon.read').click(() => {\n this.ttsToggle();\n return false;\n });\n if (this.ttsEngine) {\n this.ttsEngine.init();\n if (/[?&]_autoReadAloud=show/.test(location.toString())) {\n this.ttsStart(false); // false flag is to initiate read aloud controls\n }\n }\n });\n\n // This is fired when the hash changes by one of the other plugins!\n // i.e. it will fire every time the page changes -_-\n // this.bind(BookReader.eventNames.stop, function(e, br) {\n // this.ttsStop();\n // }.bind(this));\n }\n super_.call(this);\n };\n})(BookReader.prototype.init);\n\n/** @override */\nBookReader.prototype._createPageContainer = (function (super_) {\n return function (index) {\n const pageContainer = super_.call(this, index);\n if (this.options.enableTtsPlugin && pageContainer.page && index in this._ttsBoxesByIndex) {\n const pageIndex = pageContainer.page.index;\n renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);\n }\n return pageContainer;\n };\n})(BookReader.prototype._createPageContainer);\n\n// Extend buildMobileDrawerElement\nBookReader.prototype.buildMobileDrawerElement = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (this.options.enableTtsPlugin && this.ttsEngine) {\n $el.find('.BRmobileMenu__moreInfoRow').after($(`\n <li>\n <span>\n <span class=\"DrawerIconWrapper\"><img class=\"DrawerIcon\" src=\"${this.imagesBaseURL}icon_speaker_open.svg\" alt=\"info-speaker\"/></span>\n Read Aloud\n </span>\n <div>\n <span class=\"larger\">Press to toggle read aloud</span>\n <br/>\n <button class=\"BRicon read\"></button>\n </div>\n </li>`));\n }\n return $el;\n };\n})(BookReader.prototype.buildMobileDrawerElement);\n\n// Extend initNavbar\nBookReader.prototype.initNavbar = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (this.options.enableTtsPlugin && this.ttsEngine) {\n this.refs.$BRReadAloudToolbar = $(`\n <ul class=\"read-aloud\">\n <li>\n <select class=\"playback-speed\" name=\"playback-speed\" title=\"${tooltips.playbackSpeed}\">\n <option value=\"0.25\">0.25x</option>\n <option value=\"0.5\">0.5x</option>\n <option value=\"0.75\">0.75x</option>\n <option value=\"1.0\" selected>1.0x</option>\n <option value=\"1.25\">1.25x</option>\n <option value=\"1.5\">1.5x</option>\n <option value=\"1.75\">1.75x</option>\n <option value=\"2\">2x</option>\n </select>\n </li>\n <li>\n <button type=\"button\" name=\"review\" title=\"${tooltips.review}\">\n <div class=\"icon icon-review\"></div>\n </button>\n </li>\n <li>\n <button type=\"button\" name=\"play\" title=\"${tooltips.play}\">\n <div class=\"icon icon-play\"></div>\n <div class=\"icon icon-pause\"></div>\n </button>\n </li>\n <li>\n <button type=\"button\" name=\"advance\" title=\"${tooltips.advance}\">\n <div class=\"icon icon-advance\"></div>\n </button>\n </li>\n <li>\n <select class=\"playback-voices\" name=\"playback-voice\" style=\"display: none\" title=\"Change read aloud voices\">\n </select>\n </li>\n </ul>\n `);\n\n $el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);\n\n const renderVoiceOption = (voices) => {\n return voices.map(voice =>\n `<option value=\"${voice.voiceURI}\">${voice.lang} - ${voice.name}</option>`).join('');\n };\n\n const voiceSortOrder = (a,b) => `${a.lang} - ${a.name}`.localeCompare(`${b.lang} - ${b.name}`);\n\n const renderVoicesMenu = (voicesMenu) => {\n voicesMenu.empty();\n const bookLanguage = this.ttsEngine.opts.bookLanguage;\n const bookLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);\n const otherLanguages = this.ttsEngine.getVoices().filter(v => !v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);\n\n if (this.ttsEngine.getVoices().length > 1) {\n voicesMenu.append($(`<optgroup label=\"Book Language (${bookLanguage})\"> ${renderVoiceOption(bookLanguages)} </optgroup>`));\n voicesMenu.append($(`<optgroup label=\"Other Languages\"> ${renderVoiceOption(otherLanguages)} </optgroup>`));\n\n voicesMenu.val(this.ttsEngine.voice.voiceURI);\n voicesMenu.show();\n } else {\n voicesMenu.hide();\n }\n };\n\n const voicesMenu = this.refs.$BRReadAloudToolbar.find('[name=playback-voice]');\n renderVoicesMenu(voicesMenu);\n voicesMenu.on(\"change\", ev => this.ttsEngine.setVoice(voicesMenu.val()));\n this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());\n this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));\n this.refs.$BRReadAloudToolbar.find('[name=play]').on(\"click\", this.ttsPlayPause.bind(this));\n this.refs.$BRReadAloudToolbar.find('[name=advance]').on(\"click\", this.ttsJumpForward.bind(this));\n this.refs.$BRReadAloudToolbar.find('[name=review]').on(\"click\", this.ttsJumpBackward.bind(this));\n const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name=\"playback-speed\"]');\n $rateSelector.on(\"change\", ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));\n $(`<li>\n <button class=\"BRicon read js-tooltip\" title=\"${tooltips.readAloud}\">\n <div class=\"icon icon-read-aloud\"></div>\n <span class=\"tooltip\">${tooltips.readAloud}</span>\n </button>\n </li>`).insertBefore($el.find('.BRcontrols .BRicon.zoom_out').closest('li'));\n }\n return $el;\n };\n})(BookReader.prototype.initNavbar);\n\n// ttsToggle()\n//______________________________________________________________________________\nBookReader.prototype.ttsToggle = function () {\n if (this.autoStop) this.autoStop();\n if (this.ttsEngine.playing) {\n this.ttsStop();\n } else {\n this.ttsStart();\n }\n};\n\n// ttsStart(\n//______________________________________________________________________________\nBookReader.prototype.ttsStart = function (startTTSEngine = true) {\n if (this.constModeThumb == this.mode)\n this.switchMode(this.constMode1up);\n\n this.refs.$BRReadAloudToolbar.addClass('visible');\n this.$('.BRicon.read').addClass('unread active');\n this.ttsSendAnalyticsEvent('Start');\n if (startTTSEngine)\n this.ttsEngine.start(this.currentIndex(), this.getNumLeafs());\n};\n\nBookReader.prototype.ttsJumpForward = function () {\n if (this.ttsEngine.paused) {\n this.ttsEngine.resume();\n }\n this.ttsEngine.jumpForward();\n};\n\nBookReader.prototype.ttsJumpBackward = function () {\n if (this.ttsEngine.paused) {\n this.ttsEngine.resume();\n }\n this.ttsEngine.jumpBackward();\n};\n\nBookReader.prototype.ttsUpdateState = function() {\n const isPlaying = !(this.ttsEngine.paused || !this.ttsEngine.playing);\n this.$('.read-aloud [name=play]').toggleClass('playing', isPlaying);\n};\n\nBookReader.prototype.ttsPlayPause = function() {\n if (!this.ttsEngine.playing) {\n this.ttsToggle();\n } else {\n this.ttsEngine.togglePlayPause();\n this.ttsUpdateState(this.ttsEngine.paused);\n }\n};\n\n// ttsStop()\n//______________________________________________________________________________\nBookReader.prototype.ttsStop = function () {\n this.refs.$BRReadAloudToolbar.removeClass('visible');\n this.$('.BRicon.read').removeClass('unread active');\n this.ttsSendAnalyticsEvent('Stop');\n this.ttsEngine.stop();\n this.ttsRemoveHilites();\n this.removeProgressPopup();\n};\n\n/**\n * @param {PageChunk} chunk\n * @return {PromiseLike<void>} returns once the flip is done\n */\nBookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {\n await this.ttsMaybeFlipToIndex(chunk.leafIndex);\n this.ttsHighlightChunk(chunk);\n this.ttsScrollToChunk(chunk);\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsSendChunkFinishedAnalyticsEvent = function(chunk) {\n this.ttsSendAnalyticsEvent('ChunkFinished-Words', approximateWordCount(chunk.text));\n};\n\n/**\n * Flip the page if the provided leaf index is not visible\n * @param {Number} leafIndex\n * @return {PromiseLike<void>} resolves once the flip animation has completed\n */\nBookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {\n const in2PageMode = this.constMode2up == this.mode;\n let resolve = null;\n const promise = new Promise(res => resolve = res);\n\n if (!in2PageMode) {\n this.jumpToIndex(leafIndex);\n resolve();\n } else {\n const leafVisible = leafIndex == this.twoPage.currentIndexR || leafIndex == this.twoPage.currentIndexL;\n if (leafVisible) {\n resolve();\n } else {\n this.animationFinishedCallback = resolve;\n this.jumpToIndex(leafIndex);\n }\n }\n\n return promise;\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsHighlightChunk = function(chunk) {\n // The poorly-named variable leafIndex\n const pageIndex = chunk.leafIndex;\n\n this.ttsRemoveHilites();\n\n // group by index; currently only possible to have chunks on one page :/\n this._ttsBoxesByIndex = {\n [pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t}))\n };\n\n // update any already created pages\n for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {\n const pageIndex = parseFloat(pageIndexString);\n const page = this._models.book.getPage(pageIndex);\n const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);\n pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));\n }\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsScrollToChunk = function(chunk) {\n // It behaves weird if used in thumb mode\n if (this.constModeThumb == this.mode) return;\n\n $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({\n // Only vertically center the highlight if we're in 1up or in full screen. In\n // 2up, if we're not fullscreen, the whole body gets scrolled around to try to\n // center the highlight 🙄 See:\n // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376\n // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now\n // full-width, and covers up the last line of the highlight.\n block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',\n inline: 'center',\n behavior: 'smooth',\n });\n};\n\n// ttsRemoveHilites()\n//______________________________________________________________________________\nBookReader.prototype.ttsRemoveHilites = function () {\n $(this.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();\n this._ttsBoxesByIndex = {};\n};\n\n/**\n * @private\n * Send an analytics event with an optional value. Also attaches the book's language.\n * @param {string} action\n * @param {number} [value]\n */\nBookReader.prototype.ttsSendAnalyticsEvent = function(action, value) {\n if (this.archiveAnalyticsSendEvent) {\n const extraValues = {};\n const mediaLanguage = this.ttsEngine.opts.bookLanguage;\n if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;\n this.archiveAnalyticsSendEvent('BRReadAloud', action, value, extraValues);\n }\n};\n","/* global br */\nimport { isChrome, isFirefox } from '../../util/browserSniffing.js';\nimport { promisifyEvent, isAndroid } from './utils.js';\nimport { sleep } from '../../BookReader/utils.js';\nimport AbstractTTSEngine from './AbstractTTSEngine.js';\n/** @typedef {import(\"./AbstractTTSEngine.js\").PageChunk} PageChunk */\n/** @typedef {import(\"./AbstractTTSEngine.js\").AbstractTTSSound} AbstractTTSSound */\n/** @typedef {import(\"./AbstractTTSEngine.js\").TTSEngineOptions} TTSEngineOptions */\n\n/**\n * @extends AbstractTTSEngine\n * TTS using Web Speech APIs\n **/\nexport default class WebTTSEngine extends AbstractTTSEngine {\n static isSupported() {\n return typeof(window.speechSynthesis) !== 'undefined' && !/samsungbrowser/i.test(navigator.userAgent);\n }\n\n /** @param {TTSEngineOptions} options */\n constructor(options) {\n super(options);\n\n // SAFARI doesn't have addEventListener on speechSynthesis\n if (speechSynthesis.addEventListener) {\n speechSynthesis.addEventListener('voiceschanged', () => this.events.trigger('voiceschanged'));\n }\n }\n\n /** @override */\n start(leafIndex, numLeafs) {\n // Need to run in this function to capture user intent to start playing audio\n if ('mediaSession' in navigator) {\n const audio = new Audio(SILENCE_6S_MP3);\n audio.loop = true;\n\n this.events.on('pause', () => audio.pause());\n this.events.on('resume', () => audio.play());\n // apparently this is what you need to do to make the media session notification go away\n // See https://developers.google.com/web/updates/2017/02/media-session#implementation_notes\n this.events.on('stop', () => audio.src = '');\n audio.play().then(() => {\n navigator.mediaSession.metadata = new MediaMetadata({\n title: br.bookTitle,\n artist: br.options.metadata.filter(m => m.label == 'Author').map(m => m.value)[0],\n // album: 'The Ultimate Collection (Remastered)',\n artwork: [\n { src: br.options.thumbnail, type: 'image/jpg' },\n ]\n });\n\n navigator.mediaSession.setActionHandler('play', () => {\n audio.play();\n this.resume();\n });\n navigator.mediaSession.setActionHandler('pause', () => {\n audio.pause();\n this.pause();\n });\n\n // navigator.mediaSession.setActionHandler('seekbackward', () => this.jumpBackward());\n // navigator.mediaSession.setActionHandler('seekforward', () => this.jumpForward());\n // Some devices only support the previoustrack/nexttrack (e.g. Win10), so show those.\n // Android devices do support the seek actions, but we don't want to show both buttons\n // and have them do the same thing.\n navigator.mediaSession.setActionHandler('previoustrack', () => this.jumpBackward());\n navigator.mediaSession.setActionHandler('nexttrack', () => this.jumpForward());\n });\n }\n\n return super.start(leafIndex, numLeafs);\n }\n\n /** @override */\n getVoices() { return speechSynthesis.getVoices(); }\n\n /** @override */\n createSound(chunk) {\n return new WebTTSSound(chunk.text);\n }\n}\n\n/** @extends AbstractTTSSound */\nexport class WebTTSSound {\n /** @param {string} text **/\n constructor(text) {\n this.text = text;\n this.loaded = false;\n this.paused = false;\n this.started = false;\n /** Whether the audio was stopped with a .stop() call */\n this.stopped = false;\n this.rate = 1;\n\n /** @type {SpeechSynthesisUtterance} */\n this.utterance = null;\n\n /** @type {SpeechSynthesisVoice} */\n this.voice = null;\n\n this._lastEvents = {\n /** @type {SpeechSynthesisEvent} */\n pause: null,\n /** @type {SpeechSynthesisEvent} */\n boundary: null,\n /** @type {SpeechSynthesisEvent} */\n start: null,\n };\n\n /** Store where we are in the text. Only works on some browsers. */\n this._charIndex = 0;\n\n /** @type {Function} resolve function called when playback finished */\n this._finishResolver = null;\n\n /** @type {Promise} promise resolved by _finishResolver */\n this._finishPromise = null;\n }\n\n /** @override **/\n load(onload) {\n this.loaded = false;\n this.started = false;\n\n this.utterance = new SpeechSynthesisUtterance(this.text.slice(this._charIndex));\n this.utterance.voice = this.voice;\n // Need to also set lang (for some reason); won't set voice on Chrome@Android otherwise\n if (this.voice) this.utterance.lang = this.voice.lang;\n this.utterance.rate = this.rate;\n\n // Useful for debugging things\n if (location.toString().indexOf('_debugReadAloud=true') != -1) {\n this.utterance.addEventListener('pause', () => console.log('pause'));\n this.utterance.addEventListener('resume', () => console.log('resume'));\n this.utterance.addEventListener('start', () => console.log('start'));\n this.utterance.addEventListener('end', () => console.log('end'));\n this.utterance.addEventListener('error', () => console.log('error'));\n this.utterance.addEventListener('boundary', () => console.log('boundary'));\n this.utterance.addEventListener('mark', () => console.log('mark'));\n this.utterance.addEventListener('finish', () => console.log('finish'));\n }\n\n // Keep track of the speech synthesis events that come in; they have useful info\n // about progress (like charIndex)\n this.utterance.addEventListener('start', ev => this._lastEvents.start = ev);\n this.utterance.addEventListener('boundary', ev => this._lastEvents.boundary = ev);\n this.utterance.addEventListener('pause', ev => this._lastEvents.pause = ev);\n\n // Update our state\n this.utterance.addEventListener('start', () => {\n this.started = true;\n this.stopped = false;\n this.paused = false;\n });\n this.utterance.addEventListener('pause', () => this.paused = true);\n this.utterance.addEventListener('resume', () => this.paused = false);\n this.utterance.addEventListener('end', ev => {\n if (!this.paused && !this.stopped) {\n // Trigger a new event, finish, which only fires when audio fully completed\n this.utterance.dispatchEvent(new CustomEvent('finish', ev));\n }\n });\n this.loaded = true;\n onload && onload();\n }\n\n /**\n * Run whenever properties have changed. Tries to restart in the same spot it\n * left off.\n * @return {Promise<void>}\n */\n async reload() {\n // We'll restore the pause state, so copy it here\n const wasPaused = this.paused;\n // Use recent event to determine where we'll restart from\n // Browser support for this is mixed, but it degrades to restarting the chunk\n // and that's ok\n const recentEvent = this._lastEvents.boundary || this._lastEvents.pause;\n if (recentEvent) {\n this._charIndex = this.text.indexOf(recentEvent.target.text) + recentEvent.charIndex;\n }\n\n // We can't modify the utterance object, so we have to make a new one\n await this.stop();\n this.load();\n // Instead of playing and immediately pausing, we don't start playing. Note\n // this is a requirement because pause doesn't work consistently across\n // browsers.\n if (!wasPaused) this.play();\n }\n\n play() {\n this._finishPromise = this._finishPromise || new Promise(res => this._finishResolver = res);\n this.utterance.addEventListener('finish', this._finishResolver);\n\n // clear the queue\n speechSynthesis.cancel();\n // reset pause state\n speechSynthesis.resume();\n // Speak\n speechSynthesis.speak(this.utterance);\n\n const isLocalVoice = this.utterance.voice && this.utterance.voice.localService;\n if (isChrome() && !isLocalVoice) this._chromePausingBugFix();\n\n return this._finishPromise;\n }\n\n /** @return {Promise} */\n stop() {\n // 'end' won't fire if already stopped\n let endPromise = Promise.resolve();\n if (!this.stopped) {\n endPromise = Promise.race([\n promisifyEvent(this.utterance, 'end'),\n // Safari triggers an error when you call cancel mid-sound\n promisifyEvent(this.utterance, 'error'),\n ]);\n }\n this.stopped = true;\n speechSynthesis.cancel();\n return endPromise;\n }\n\n async finish() {\n await this.stop();\n this.utterance.dispatchEvent(new Event('finish'));\n }\n\n /**\n * @override\n * Will fire a pause event unless already paused\n **/\n async pause() {\n if (this.paused) return;\n\n const pausePromise = promisifyEvent(this.utterance, 'pause');\n speechSynthesis.pause();\n\n // There are a few awful browser cases:\n // 1. Pause works and fires\n // 2. Pause doesn't work and doesn't fire\n // 3. Pause works but doesn't fire\n const pauseMightNotWork = (isFirefox() && isAndroid());\n const pauseMightNotFire = isChrome() || pauseMightNotWork;\n\n if (pauseMightNotFire) {\n // wait for it just in case\n const timeoutPromise = sleep(100).then(() => 'timeout');\n const result = await Promise.race([pausePromise, timeoutPromise]);\n // We got our pause event; nothing to do!\n if (result != 'timeout') return;\n\n this.utterance.dispatchEvent(new CustomEvent('pause', this._lastEvents.start));\n\n // if pause might not work, then we'll stop entirely and restart later\n if (pauseMightNotWork) this.stop();\n }\n }\n\n async resume() {\n if (!this.started) {\n this.play();\n return;\n }\n\n if (!this.paused) return;\n\n // Browser cases:\n // 1. Resume works + fires\n // 2. Resume works + doesn't fire (Chrome Desktop)\n // 3. Resume doesn't work + doesn't fire (Chrome/FF Android)\n const resumeMightNotWork = (isChrome() && isAndroid()) || (isFirefox() && isAndroid());\n const resumeMightNotFire = isChrome() || resumeMightNotWork;\n\n // Try resume\n const resumePromise = promisifyEvent(this.utterance, 'resume');\n speechSynthesis.resume();\n\n if (resumeMightNotFire) {\n const result = await Promise.race([resumePromise, sleep(100).then(() => 'timeout')]);\n\n if (result != 'timeout') return;\n\n this.utterance.dispatchEvent(new CustomEvent('resume', {}));\n if (resumeMightNotWork) {\n await this.reload();\n this.play();\n }\n }\n }\n\n setPlaybackRate(rate) {\n this.rate = rate;\n this.reload();\n }\n\n /** @param {SpeechSynthesisVoice} voice */\n setVoice(voice) {\n this.voice = voice;\n this.reload();\n }\n /**\n * @private\n * Chrome has a bug where it only plays 15 seconds of TTS and then\n * suddenly stops (see https://bugs.chromium.org/p/chromium/issues/detail?id=679437 )\n * We avoid this (as described here: https://bugs.chromium.org/p/chromium/issues/detail?id=679437#c15 )\n * by pausing after 14 seconds and ~instantly resuming.\n */\n async _chromePausingBugFix() {\n const timeoutPromise = sleep(14000).then(() => 'timeout');\n const pausePromise = promisifyEvent(this.utterance, 'pause').then(() => 'paused');\n const endPromise = promisifyEvent(this.utterance, 'end').then(() => 'ended');\n const result = await Promise.race([timeoutPromise, pausePromise, endPromise]);\n if (location.toString().indexOf('_debugReadAloud=true') != -1) {\n console.log(`CHROME-PAUSE-HACK: ${result}`);\n }\n switch (result) {\n case 'ended':\n // audio was stopped/finished; nothing to do\n break;\n case 'paused':\n // audio was paused; wait for resume\n // Chrome won't let you resume the audio if 14s have passed 🤷\n // We could do the same as before (but resume+pause instead of pause+resume),\n // but that means we'd _constantly_ be running in the background. So in that\n // case, let's just restart the chunk\n await Promise.race([\n promisifyEvent(this.utterance, 'resume'),\n sleep(14000).then(() => 'timeout'),\n ]);\n result == 'timeout' ? this.reload() : this._chromePausingBugFix();\n break;\n case 'timeout':\n // We hit Chrome's secret cut off time. Pause/resume\n // to be able to keep TTS-ing\n speechSynthesis.pause();\n await sleep(25);\n speechSynthesis.resume();\n this._chromePausingBugFix();\n break;\n }\n }\n}\n\n/**\n * According to https://developers.google.com/web/updates/2017/02/media-session#implementation_notes , it needs to be at least 5 seconds\n * long to allow usage of the media sessions api\n */\nconst SILENCE_6S_MP3 = 'data:audio/mp3;base64,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';\n","export const en = {\n advance: 'Advance 10 seconds',\n play: 'Play',\n playbackSpeed: 'Playback speed',\n readAloud: 'Read this book aloud',\n review: 'Review 10 seconds',\n};\n\nexport const es = {\n advance: 'Avance 10 segundos',\n play: 'Jugar',\n playbackSpeed: 'Velocidad de reproducción',\n readAloud: 'Lee este libro en voz alta',\n review: 'Revisar 10 segundos',\n};\n","\n/**\n * Checks whether the current browser is a Chrome/Chromium browser\n * Code from https://stackoverflow.com/a/4565120/2317712\n * @param {string} [userAgent]\n * @param {string} [vendor]\n * @return {boolean}\n */\nexport function isChrome(userAgent = navigator.userAgent, vendor = navigator.vendor) {\n return /chrome/i.test(userAgent) && /google inc/i.test(vendor);\n}\n\n/**\n * Checks whether the current browser is firefox\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isFirefox(userAgent = navigator.userAgent) {\n return /firefox/i.test(userAgent);\n}\n\n/**\n * Checks whether the current browser is safari\n * https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#Browser_Name\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isSafari(userAgent = navigator.userAgent) {\n return /safari/i.test(userAgent) && !/chrome|chromium/i.test(userAgent);\n}\n","var global = require('../internals/global');\nvar fails = require('../internals/fails');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar toString = require('../internals/to-string');\nvar trim = require('../internals/string-trim').trim;\nvar whitespaces = require('../internals/whitespaces');\n\nvar charAt = uncurryThis(''.charAt);\nvar n$ParseFloat = global.parseFloat;\nvar Symbol = global.Symbol;\nvar ITERATOR = Symbol && Symbol.iterator;\nvar FORCED = 1 / n$ParseFloat(whitespaces + '-0') !== -Infinity\n // MS Edge 18- broken with boxed symbols\n || (ITERATOR && !fails(function () { n$ParseFloat(Object(ITERATOR)); }));\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\nmodule.exports = FORCED ? function parseFloat(string) {\n var trimmedString = trim(toString(string));\n var result = n$ParseFloat(trimmedString);\n return result === 0 && charAt(trimmedString, 0) == '-' ? -0 : result;\n} : n$ParseFloat;\n","var $ = require('../internals/export');\nvar $entries = require('../internals/object-to-array').entries;\n\n// `Object.entries` method\n// https://tc39.es/ecma262/#sec-object.entries\n$({ target: 'Object', stat: true }, {\n entries: function entries(O) {\n return $entries(O);\n }\n});\n","var $ = require('../internals/export');\nvar $parseFloat = require('../internals/number-parse-float');\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\n$({ global: true, forced: parseFloat != $parseFloat }, {\n parseFloat: $parseFloat\n});\n","'use strict';\nvar call = require('../internals/function-call');\nvar fixRegExpWellKnownSymbolLogic = require('../internals/fix-regexp-well-known-symbol-logic');\nvar anObject = require('../internals/an-object');\nvar toLength = require('../internals/to-length');\nvar toString = require('../internals/to-string');\nvar requireObjectCoercible = require('../internals/require-object-coercible');\nvar getMethod = require('../internals/get-method');\nvar advanceStringIndex = require('../internals/advance-string-index');\nvar regExpExec = require('../internals/regexp-exec-abstract');\n\n// @@match logic\nfixRegExpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {\n return [\n // `String.prototype.match` method\n // https://tc39.es/ecma262/#sec-string.prototype.match\n function match(regexp) {\n var O = requireObjectCoercible(this);\n var matcher = regexp == undefined ? undefined : getMethod(regexp, MATCH);\n return matcher ? call(matcher, regexp, O) : new RegExp(regexp)[MATCH](toString(O));\n },\n // `RegExp.prototype[@@match]` method\n // https://tc39.es/ecma262/#sec-regexp.prototype-@@match\n function (string) {\n var rx = anObject(this);\n var S = toString(string);\n var res = maybeCallNative(nativeMatch, rx, S);\n\n if (res.done) return res.value;\n\n if (!rx.global) return regExpExec(rx, S);\n\n var fullUnicode = rx.unicode;\n rx.lastIndex = 0;\n var A = [];\n var n = 0;\n var result;\n while ((result = regExpExec(rx, S)) !== null) {\n var matchStr = toString(result[0]);\n A[n] = matchStr;\n if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);\n n++;\n }\n return n === 0 ? null : A;\n }\n ];\n});\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports[\"default\"] = void 0;\nvar _default = [['Serbian', 'српски језик', 'sr', 'srp', 'srp'], ['Romanian, Moldavian, Moldovan', 'Română', 'ro', 'ron', 'rum'], ['Sichuan Yi, Nuosu', 'ꆈꌠ꒿ Nuosuhxop', 'ii', 'iii', 'iii'], ['Tahitian', 'Reo Tahiti', 'ty', 'tah', 'tah'], ['Tagalog', 'Wikang Tagalog', 'tl', 'tgl', 'tgl'], ['Yiddish', 'ייִדיש', 'yi', 'yid', 'yid'], ['Akan', 'Akan', 'ak', 'aka', 'aka'], ['Malay', 'Bahasa Melayu, بهاس ملايو', 'ms', 'msa', 'may'], ['Arabic', 'العربية', 'ar', 'ara', 'ara'], ['Norwegian', 'Norsk', 'no', 'nor', 'nor'], ['Ojibwa', 'ᐊᓂᔑᓈᐯᒧᐎᓐ', 'oj', 'oji', 'oji'], ['Fulah', 'Fulfulde, Pulaar, Pular', 'ff', 'ful', 'ful'], ['Persian', 'فارسی', 'fa', 'fas', 'per'], ['Albanian', 'Shqip', 'sq', 'sqi', 'alb'], ['Aymara', 'aymar aru', 'ay', 'aym', 'aym'], ['Azerbaijani', 'azərbaycan dili', 'az', 'aze', 'aze'], ['Chinese', '中文 (Zhōngwén), 汉语, 漢語', 'zh', 'zho', 'chi'], ['Cree', 'ᓀᐦᐃᔭᐍᐏᐣ', 'cr', 'cre', 'cre'], ['Estonian', 'eesti, eesti keel', 'et', 'est', 'est'], ['Guaraní', 'Avañe\\'ẽ', 'gn', 'grn', 'grn'], ['Inupiaq', 'Iñupiaq, Iñupiatun', 'ik', 'ipk', 'ipk'], ['Inuktitut', 'ᐃᓄᒃᑎᑐᑦ', 'iu', 'iku', 'iku'], ['Kanuri', 'Kanuri', 'kr', 'kau', 'kau'], ['Komi', 'коми кыв', 'kv', 'kom', 'kom'], ['Kongo', 'Kikongo', 'kg', 'kon', 'kon'], ['Kurdish', 'Kurdî, کوردی', 'ku', 'kur', 'kur'], ['Latvian', 'latviešu valoda', 'lv', 'lav', 'lav'], ['Malagasy', 'fiteny malagasy', 'mg', 'mlg', 'mlg'], ['Mongolian', 'Монгол хэл', 'mn', 'mon', 'mon'], ['Oromo', 'Afaan Oromoo', 'om', 'orm', 'orm'], ['Pashto, Pushto', 'پښتو', 'ps', 'pus', 'pus'], ['Quechua', 'Runa Simi, Kichwa', 'qu', 'que', 'que'], ['Sardinian', 'sardu', 'sc', 'srd', 'srd'], ['Swahili', 'Kiswahili', 'sw', 'swa', 'swa'], ['Uzbek', 'Oʻzbek, Ўзбек, أۇزبېك', 'uz', 'uzb', 'uzb'], ['Zhuang, Chuang', 'Saɯ cueŋƅ, Saw cuengh', 'za', 'zha', 'zha'], ['Bislama', 'Bislama', 'bi', 'bis', 'bis'], ['Norwegian Bokmål', 'Norsk Bokmål', 'nb', 'nob', 'nob'], ['Norwegian Nynorsk', 'Norsk Nynorsk', 'nn', 'nno', 'nno'], ['Indonesian', 'Bahasa Indonesia', 'id', 'ind', 'ind'], ['Twi', 'Twi', 'tw', 'twi', 'twi'], ['Esperanto', 'Esperanto', 'eo', 'epo', 'epo'], ['Interlingua', 'Interlingua', 'ia', 'ina', 'ina'], ['Interlingue', 'Originally called Occidental; then Interlingue after WWII', 'ie', 'ile', 'ile'], ['Ido', 'Ido', 'io', 'ido', 'ido'], ['Volapük', 'Volapük', 'vo', 'vol', 'vol'], ['Bihari languages', 'भोजपुरी', 'bh', 'bih', 'bih'], ['Hebrew (modern)', 'עברית', 'he', 'heb', 'heb'], ['Sanskrit', 'संस्कृतम्', 'sa', 'san', 'san'], ['Church Slavic, Church Slavonic, Old Church Slavonic, Old Slavonic, Old Bulgarian', 'ѩзыкъ словѣньскъ', 'cu', 'chu', 'chu'], ['Pali', 'पाऴि', 'pi', 'pli', 'pli'], ['Avestan', 'avesta', 'ae', 'ave', 'ave'], ['Latin', 'latine, lingua latina', 'la', 'lat', 'lat'], ['Armenian', 'Հայերեն', 'hy', 'hye', 'arm'], ['Swati', 'SiSwati', 'ss', 'ssw', 'ssw'], ['Tibetan', 'བོད་ཡིག', 'bo', 'bod', 'tib'], ['South Ndebele', 'isiNdebele', 'nr', 'nbl', 'nbl'], ['Slovene', 'Slovenski Jezik, Slovenščina', 'sl', 'slv', 'slv'], ['Oriya', 'ଓଡ଼ିଆ', 'or', 'ori', 'ori'], ['North Ndebele', 'isiNdebele', 'nd', 'nde', 'nde'], ['Nauru', 'Dorerin Naoero', 'na', 'nau', 'nau'], ['Maori', 'te reo Māori', 'mi', 'mri', 'mao'], ['Marathi', 'मराठी', 'mr', 'mar', 'mar'], ['Luba-Katanga', 'Kiluba', 'lu', 'lub', 'lub'], ['Rundi', 'Ikirundi', 'rn', 'run', 'run'], ['Central Khmer', 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ', 'km', 'khm', 'khm'], ['Western Frisian', 'Frysk', 'fy', 'fry', 'fry'], ['Bengali', 'বাংলা', 'bn', 'ben', 'ben'], ['Avaric', 'авар мацӀ, магӀарул мацӀ', 'av', 'ava', 'ava'], ['Abkhazian', 'аҧсуа бызшәа, аҧсшәа', 'ab', 'abk', 'abk'], ['Afar', 'Afaraf', 'aa', 'aar', 'aar'], ['Afrikaans', 'Afrikaans', 'af', 'afr', 'afr'], ['Amharic', 'አማርኛ', 'am', 'amh', 'amh'], ['Aragonese', 'aragonés', 'an', 'arg', 'arg'], ['Assamese', 'অসমীয়া', 'as', 'asm', 'asm'], ['Bambara', 'bamanankan', 'bm', 'bam', 'bam'], ['Bashkir', 'башҡорт теле', 'ba', 'bak', 'bak'], ['Basque', 'euskara, euskera', 'eu', 'eus', 'baq'], ['Belarusian', 'беларуская мова', 'be', 'bel', 'bel'], ['Bosnian', 'bosanski jezik', 'bs', 'bos', 'bos'], ['Breton', 'brezhoneg', 'br', 'bre', 'bre'], ['Bulgarian', 'български език', 'bg', 'bul', 'bul'], ['Burmese', 'ဗမာစာ', 'my', 'mya', 'bur'], ['Catalan, Valencian', 'català, valencià', 'ca', 'cat', 'cat'], ['Chamorro', 'Chamoru', 'ch', 'cha', 'cha'], ['Chechen', 'нохчийн мотт', 'ce', 'che', 'che'], ['Chichewa, Chewa, Nyanja', 'chiCheŵa, chinyanja', 'ny', 'nya', 'nya'], ['Chuvash', 'чӑваш чӗлхи', 'cv', 'chv', 'chv'], ['Cornish', 'Kernewek', 'kw', 'cor', 'cor'], ['Corsican', 'corsu, lingua corsa', 'co', 'cos', 'cos'], ['Croatian', 'hrvatski jezik', 'hr', 'hrv', 'hrv'], ['Czech', 'čeština, český jazyk', 'cs', 'ces', 'cze'], ['Danish', 'dansk', 'da', 'dan', 'dan'], ['Divehi, Dhivehi, Maldivian', 'ދިވެހި', 'dv', 'div', 'div'], ['Dutch, Flemish', 'Nederlands, Vlaams', 'nl', 'nld', 'dut'], ['Dzongkha', 'རྫོང་ཁ', 'dz', 'dzo', 'dzo'], ['English', 'English', 'en', 'eng', 'eng'], ['Ewe', 'Eʋegbe', 'ee', 'ewe', 'ewe'], ['Faroese', 'føroyskt', 'fo', 'fao', 'fao'], ['Fijian', 'vosa Vakaviti', 'fj', 'fij', 'fij'], ['Finnish', 'suomi, suomen kieli', 'fi', 'fin', 'fin'], ['French', 'français, langue française', 'fr', 'fra', 'fre'], ['Galician', 'Galego', 'gl', 'glg', 'glg'], ['Georgian', 'ქართული', 'ka', 'kat', 'geo'], ['German', 'Deutsch', 'de', 'deu', 'ger'], ['Greek (modern)', 'ελληνικά', 'el', 'ell', 'gre'], ['Gujarati', 'ગુજરાતી', 'gu', 'guj', 'guj'], ['Haitian, Haitian Creole', 'Kreyòl ayisyen', 'ht', 'hat', 'hat'], ['Hausa', '(Hausa) هَوُسَ', 'ha', 'hau', 'hau'], ['Herero', 'Otjiherero', 'hz', 'her', 'her'], ['Hindi', 'हिन्दी, हिंदी', 'hi', 'hin', 'hin'], ['Hiri Motu', 'Hiri Motu', 'ho', 'hmo', 'hmo'], ['Hungarian', 'magyar', 'hu', 'hun', 'hun'], ['Irish', 'Gaeilge', 'ga', 'gle', 'gle'], ['Igbo', 'Asụsụ Igbo', 'ig', 'ibo', 'ibo'], ['Icelandic', 'Íslenska', 'is', 'isl', 'ice'], ['Italian', 'Italiano', 'it', 'ita', 'ita'], ['Japanese', '日本語 (にほんご)', 'ja', 'jpn', 'jpn'], ['Javanese', 'ꦧꦱꦗꦮ, Basa Jawa', 'jv', 'jav', 'jav'], ['Kalaallisut, Greenlandic', 'kalaallisut, kalaallit oqaasii', 'kl', 'kal', 'kal'], ['Kannada', 'ಕನ್ನಡ', 'kn', 'kan', 'kan'], ['Kashmiri', 'कश्मीरी, كشميري', 'ks', 'kas', 'kas'], ['Kazakh', 'қазақ тілі', 'kk', 'kaz', 'kaz'], ['Kikuyu, Gikuyu', 'Gĩkũyũ', 'ki', 'kik', 'kik'], ['Kinyarwanda', 'Ikinyarwanda', 'rw', 'kin', 'kin'], ['Kirghiz, Kyrgyz', 'Кыргызча, Кыргыз тили', 'ky', 'kir', 'kir'], ['Korean', '한국어', 'ko', 'kor', 'kor'], ['Kuanyama, Kwanyama', 'Kuanyama', 'kj', 'kua', 'kua'], ['Luxembourgish, Letzeburgesch', 'Lëtzebuergesch', 'lb', 'ltz', 'ltz'], ['Ganda', 'Luganda', 'lg', 'lug', 'lug'], ['Limburgan, Limburger, Limburgish', 'Limburgs', 'li', 'lim', 'lim'], ['Lingala', 'Lingála', 'ln', 'lin', 'lin'], ['Lao', 'ພາສາລາວ', 'lo', 'lao', 'lao'], ['Lithuanian', 'lietuvių kalba', 'lt', 'lit', 'lit'], ['Manx', 'Gaelg, Gailck', 'gv', 'glv', 'glv'], ['Macedonian', 'македонски јазик', 'mk', 'mkd', 'mac'], ['Malayalam', 'മലയാളം', 'ml', 'mal', 'mal'], ['Maltese', 'Malti', 'mt', 'mlt', 'mlt'], ['Marshallese', 'Kajin M̧ajeļ', 'mh', 'mah', 'mah'], ['Navajo, Navaho', 'Diné bizaad', 'nv', 'nav', 'nav'], ['Nepali', 'नेपाली', 'ne', 'nep', 'nep'], ['Ndonga', 'Owambo', 'ng', 'ndo', 'ndo'], ['Occitan', 'occitan, lenga d\\'òc', 'oc', 'oci', 'oci'], ['Ossetian, Ossetic', 'ирон æвзаг', 'os', 'oss', 'oss'], ['Panjabi, Punjabi', 'ਪੰਜਾਬੀ', 'pa', 'pan', 'pan'], ['Polish', 'język polski, polszczyzna', 'pl', 'pol', 'pol'], ['Portuguese', 'Português', 'pt', 'por', 'por'], ['Romansh', 'Rumantsch Grischun', 'rm', 'roh', 'roh'], ['Russian', 'русский', 'ru', 'rus', 'rus'], ['Sindhi', 'सिन्धी, سنڌي، سندھی', 'sd', 'snd', 'snd'], ['Northern Sami', 'Davvisámegiella', 'se', 'sme', 'sme'], ['Samoan', 'gagana fa\\'a Samoa', 'sm', 'smo', 'smo'], ['Sango', 'yângâ tî sängö', 'sg', 'sag', 'sag'], ['Gaelic, Scottish Gaelic', 'Gàidhlig', 'gd', 'gla', 'gla'], ['Shona', 'chiShona', 'sn', 'sna', 'sna'], ['Sinhala, Sinhalese', 'සිංහල', 'si', 'sin', 'sin'], ['Slovak', 'Slovenčina, Slovenský Jazyk', 'sk', 'slk', 'slo'], ['Somali', 'Soomaaliga, af Soomaali', 'so', 'som', 'som'], ['Southern Sotho', 'Sesotho', 'st', 'sot', 'sot'], ['Spanish, Castilian', 'Español', 'es', 'spa', 'spa'], ['Sundanese', 'Basa Sunda', 'su', 'sun', 'sun'], ['Swedish', 'Svenska', 'sv', 'swe', 'swe'], ['Tamil', 'தமிழ்', 'ta', 'tam', 'tam'], ['Telugu', 'తెలుగు', 'te', 'tel', 'tel'], ['Tajik', 'тоҷикӣ, toçikī, تاجیکی', 'tg', 'tgk', 'tgk'], ['Thai', 'ไทย', 'th', 'tha', 'tha'], ['Tigrinya', 'ትግርኛ', 'ti', 'tir', 'tir'], ['Turkmen', 'Türkmen, Түркмен', 'tk', 'tuk', 'tuk'], ['Tswana', 'Setswana', 'tn', 'tsn', 'tsn'], ['Tongan (Tonga Islands)', 'Faka Tonga', 'to', 'ton', 'ton'], ['Turkish', 'Türkçe', 'tr', 'tur', 'tur'], ['Tsonga', 'Xitsonga', 'ts', 'tso', 'tso'], ['Tatar', 'татар теле, tatar tele', 'tt', 'tat', 'tat'], ['Uighur, Uyghur', 'ئۇيغۇرچە, Uyghurche', 'ug', 'uig', 'uig'], ['Ukrainian', 'Українська', 'uk', 'ukr', 'ukr'], ['Urdu', 'اردو', 'ur', 'urd', 'urd'], ['Venda', 'Tshivenḓa', 've', 'ven', 'ven'], ['Vietnamese', 'Tiếng Việt', 'vi', 'vie', 'vie'], ['Walloon', 'Walon', 'wa', 'wln', 'wln'], ['Welsh', 'Cymraeg', 'cy', 'cym', 'wel'], ['Wolof', 'Wollof', 'wo', 'wol', 'wol'], ['Xhosa', 'isiXhosa', 'xh', 'xho', 'xho'], ['Yoruba', 'Yorùbá', 'yo', 'yor', 'yor'], ['Zulu', 'isiZulu', 'zu', 'zul', 'zul']];\nexports[\"default\"] = _default;","/*!\n * jQuery Browser Plugin 0.1.0\n * https://github.com/gabceb/jquery-browser-plugin\n *\n * Original jquery-browser code Copyright 2005, 2015 jQuery Foundation, Inc. and other contributors\n * http://jquery.org/license\n *\n * Modifications Copyright 2015 Gabriel Cebrian\n * https://github.com/gabceb\n *\n * Released under the MIT license\n *\n * Date: 05-07-2015\n */\n/*global window: false */\n\n(function (factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['jquery'], function ($) {\n return factory($);\n });\n } else if (typeof module === 'object' && typeof module.exports === 'object') {\n // Node-like environment\n module.exports = factory(require('jquery'));\n } else {\n // Browser globals\n factory(window.jQuery);\n }\n}(function(jQuery) {\n \"use strict\";\n\n function uaMatch( ua ) {\n // If an UA is not provided, default to the current browser UA.\n if ( ua === undefined ) {\n ua = window.navigator.userAgent;\n }\n ua = ua.toLowerCase();\n\n var match = /(edge)\\/([\\w.]+)/.exec( ua ) ||\n /(opr)[\\/]([\\w.]+)/.exec( ua ) ||\n /(chrome)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(iemobile)[\\/]([\\w.]+)/.exec( ua ) ||\n /(version)(applewebkit)[ \\/]([\\w.]+).*(safari)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(webkit)[ \\/]([\\w.]+).*(version)[ \\/]([\\w.]+).*(safari)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(webkit)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(msie) ([\\w.]+)/.exec( ua ) ||\n ua.indexOf(\"trident\") >= 0 && /(rv)(?::| )([\\w.]+)/.exec( ua ) ||\n ua.indexOf(\"compatible\") < 0 && /(mozilla)(?:.*? rv:([\\w.]+)|)/.exec( ua ) ||\n [];\n\n var platform_match = /(ipad)/.exec( ua ) ||\n /(ipod)/.exec( ua ) ||\n /(windows phone)/.exec( ua ) ||\n /(iphone)/.exec( ua ) ||\n /(kindle)/.exec( ua ) ||\n /(silk)/.exec( ua ) ||\n /(android)/.exec( ua ) ||\n /(win)/.exec( ua ) ||\n /(mac)/.exec( ua ) ||\n /(linux)/.exec( ua ) ||\n /(cros)/.exec( ua ) ||\n /(playbook)/.exec( ua ) ||\n /(bb)/.exec( ua ) ||\n /(blackberry)/.exec( ua ) ||\n [];\n\n var browser = {},\n matched = {\n browser: match[ 5 ] || match[ 3 ] || match[ 1 ] || \"\",\n version: match[ 2 ] || match[ 4 ] || \"0\",\n versionNumber: match[ 4 ] || match[ 2 ] || \"0\",\n platform: platform_match[ 0 ] || \"\"\n };\n\n if ( matched.browser ) {\n browser[ matched.browser ] = true;\n browser.version = matched.version;\n browser.versionNumber = parseInt(matched.versionNumber, 10);\n }\n\n if ( matched.platform ) {\n browser[ matched.platform ] = true;\n }\n\n // These are all considered mobile platforms, meaning they run a mobile browser\n if ( browser.android || browser.bb || browser.blackberry || browser.ipad || browser.iphone ||\n browser.ipod || browser.kindle || browser.playbook || browser.silk || browser[ \"windows phone\" ]) {\n browser.mobile = true;\n }\n\n // These are all considered desktop platforms, meaning they run a desktop browser\n if ( browser.cros || browser.mac || browser.linux || browser.win ) {\n browser.desktop = true;\n }\n\n // Chrome, Opera 15+ and Safari are webkit based browsers\n if ( browser.chrome || browser.opr || browser.safari ) {\n browser.webkit = true;\n }\n\n // IE11 has a new token so we will assign it msie to avoid breaking changes\n if ( browser.rv || browser.iemobile) {\n var ie = \"msie\";\n\n matched.browser = ie;\n browser[ie] = true;\n }\n\n // Edge is officially known as Microsoft Edge, so rewrite the key to match\n if ( browser.edge ) {\n delete browser.edge;\n var msedge = \"msedge\";\n\n matched.browser = msedge;\n browser[msedge] = true;\n }\n\n // Blackberry browsers are marked as Safari on BlackBerry\n if ( browser.safari && browser.blackberry ) {\n var blackberry = \"blackberry\";\n\n matched.browser = blackberry;\n browser[blackberry] = true;\n }\n\n // Playbook browsers are marked as Safari on Playbook\n if ( browser.safari && browser.playbook ) {\n var playbook = \"playbook\";\n\n matched.browser = playbook;\n browser[playbook] = true;\n }\n\n // BB10 is a newer OS version of BlackBerry\n if ( browser.bb ) {\n var bb = \"blackberry\";\n\n matched.browser = bb;\n browser[bb] = true;\n }\n\n // Opera 15+ are identified as opr\n if ( browser.opr ) {\n var opera = \"opera\";\n\n matched.browser = opera;\n browser[opera] = true;\n }\n\n // Stock Android browsers are marked as Safari on Android.\n if ( browser.safari && browser.android ) {\n var android = \"android\";\n\n matched.browser = android;\n browser[android] = true;\n }\n\n // Kindle browsers are marked as Safari on Kindle\n if ( browser.safari && browser.kindle ) {\n var kindle = \"kindle\";\n\n matched.browser = kindle;\n browser[kindle] = true;\n }\n\n // Kindle Silk browsers are marked as Safari on Kindle\n if ( browser.safari && browser.silk ) {\n var silk = \"silk\";\n\n matched.browser = silk;\n browser[silk] = true;\n }\n\n // Assign the name and platform variable\n browser.name = matched.browser;\n browser.platform = matched.platform;\n return browser;\n }\n\n // Run the matching process, also assign the function to the returned object\n // for manual, jQuery-free use if desired\n window.jQBrowser = uaMatch( window.navigator.userAgent );\n window.jQBrowser.uaMatch = uaMatch;\n\n // Only assign to jQuery.browser if jQuery is loaded\n if ( jQuery ) {\n jQuery.browser = window.jQBrowser;\n }\n\n return window.jQBrowser;\n}));\n","/** @license\r\n *\r\n * SoundManager 2: JavaScript Sound for the Web\r\n * ----------------------------------------------\r\n * http://schillmania.com/projects/soundmanager2/\r\n *\r\n * Copyright (c) 2007, Scott Schiller. All rights reserved.\r\n * Code provided under the BSD License:\r\n * http://schillmania.com/projects/soundmanager2/license.txt\r\n *\r\n * V2.97a.20170601\r\n */\r\n\r\n/**\r\n * About this file\r\n * -------------------------------------------------------------------------------------\r\n * This is the fully-commented source version of the SoundManager 2 API,\r\n * recommended for use during development and testing.\r\n *\r\n * See soundmanager2-nodebug-jsmin.js for an optimized build (~11KB with gzip.)\r\n * http://schillmania.com/projects/soundmanager2/doc/getstarted/#basic-inclusion\r\n * Alternately, serve this file with gzip for 75% compression savings (~30KB over HTTP.)\r\n *\r\n * You may notice <d> and </d> comments in this source; these are delimiters for\r\n * debug blocks which are removed in the -nodebug builds, further optimizing code size.\r\n *\r\n * Also, as you may note: Whoa, reliable cross-platform/device audio support is hard! ;)\r\n */\r\n\r\n(function SM2(window, _undefined) {\r\n\r\n/* global Audio, document, window, navigator, define, module, SM2_DEFER, opera, setTimeout, setInterval, clearTimeout, sm2Debugger */\r\n\r\n'use strict';\r\n\r\nif (!window || !window.document) {\r\n\r\n // Don't cross the [environment] streams. SM2 expects to be running in a browser, not under node.js etc.\r\n // Additionally, if a browser somehow manages to fail this test, as Egon said: \"It would be bad.\"\r\n\r\n throw new Error('SoundManager requires a browser with window and document objects.');\r\n\r\n}\r\n\r\nvar soundManager = null;\r\n\r\n/**\r\n * The SoundManager constructor.\r\n *\r\n * @constructor\r\n * @param {string} smURL Optional: Path to SWF files\r\n * @param {string} smID Optional: The ID to use for the SWF container element\r\n * @this {SoundManager}\r\n * @return {SoundManager} The new SoundManager instance\r\n */\r\n\r\nfunction SoundManager(smURL, smID) {\r\n\r\n /**\r\n * soundManager configuration options list\r\n * defines top-level configuration properties to be applied to the soundManager instance (eg. soundManager.flashVersion)\r\n * to set these properties, use the setup() method - eg., soundManager.setup({url: '/swf/', flashVersion: 9})\r\n */\r\n\r\n this.setupOptions = {\r\n\r\n url: (smURL || null), // path (directory) where SoundManager 2 SWFs exist, eg., /path/to/swfs/\r\n flashVersion: 8, // flash build to use (8 or 9.) Some API features require 9.\r\n debugMode: true, // enable debugging output (console.log() with HTML fallback)\r\n debugFlash: false, // enable debugging output inside SWF, troubleshoot Flash/browser issues\r\n useConsole: true, // use console.log() if available (otherwise, writes to #soundmanager-debug element)\r\n consoleOnly: true, // if console is being used, do not create/write to #soundmanager-debug\r\n waitForWindowLoad: false, // force SM2 to wait for window.onload() before trying to call soundManager.onload()\r\n bgColor: '#ffffff', // SWF background color. N/A when wmode = 'transparent'\r\n useHighPerformance: false, // position:fixed flash movie can help increase js/flash speed, minimize lag\r\n flashPollingInterval: null, // msec affecting whileplaying/loading callback frequency. If null, default of 50 msec is used.\r\n html5PollingInterval: null, // msec affecting whileplaying() for HTML5 audio, excluding mobile devices. If null, native HTML5 update events are used.\r\n flashLoadTimeout: 1000, // msec to wait for flash movie to load before failing (0 = infinity)\r\n wmode: null, // flash rendering mode - null, 'transparent', or 'opaque' (last two allow z-index to work)\r\n allowScriptAccess: 'always', // for scripting the SWF (object/embed property), 'always' or 'sameDomain'\r\n useFlashBlock: false, // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable.\r\n useHTML5Audio: true, // use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (MP3/MP4 support varies.) Ideally, transparent vs. Flash API where possible.\r\n forceUseGlobalHTML5Audio: false, // if true, a single Audio() object is used for all sounds - and only one can play at a time.\r\n ignoreMobileRestrictions: false, // if true, SM2 will not apply global HTML5 audio rules to mobile UAs. iOS > 7 and WebViews may allow multiple Audio() instances.\r\n html5Test: /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.\r\n preferFlash: false, // overrides useHTML5audio, will use Flash for MP3/MP4/AAC if present. Potential option if HTML5 playback with these formats is quirky.\r\n noSWFCache: false, // if true, appends ?ts={date} to break aggressive SWF caching.\r\n idPrefix: 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc.\r\n\r\n };\r\n\r\n this.defaultOptions = {\r\n\r\n /**\r\n * the default configuration for sound objects made with createSound() and related methods\r\n * eg., volume, auto-load behaviour and so forth\r\n */\r\n\r\n autoLoad: false, // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)\r\n autoPlay: false, // enable playing of file as soon as possible (much faster if \"stream\" is true)\r\n from: null, // position to start playback within a sound (msec), default = beginning\r\n loops: 1, // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0)\r\n onid3: null, // callback function for \"ID3 data is added/available\"\r\n onerror: null, // callback function for \"load failed\" (or, playback/network/decode error under HTML5.)\r\n onload: null, // callback function for \"load finished\"\r\n whileloading: null, // callback function for \"download progress update\" (X of Y bytes received)\r\n onplay: null, // callback for \"play\" start\r\n onpause: null, // callback for \"pause\"\r\n onresume: null, // callback for \"resume\" (pause toggle)\r\n whileplaying: null, // callback during play (position update)\r\n onposition: null, // object containing times and function callbacks for positions of interest\r\n onstop: null, // callback for \"user stop\"\r\n onfinish: null, // callback function for \"sound finished playing\"\r\n multiShot: true, // let sounds \"restart\" or layer on top of each other when played multiple times, rather than one-shot/one at a time\r\n multiShotEvents: false, // fire multiple sound events (currently onfinish() only) when multiShot is enabled\r\n position: null, // offset (milliseconds) to seek to within loaded sound data.\r\n pan: 0, // \"pan\" settings, left-to-right, -100 to 100\r\n playbackRate: 1, // rate at which to play the sound (HTML5-only)\r\n stream: true, // allows playing before entire file has loaded (recommended)\r\n to: null, // position to end playback within a sound (msec), default = end\r\n type: null, // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3\r\n usePolicyFile: false, // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access)\r\n volume: 100 // self-explanatory. 0-100, the latter being the max.\r\n\r\n };\r\n\r\n this.flash9Options = {\r\n\r\n /**\r\n * flash 9-only options,\r\n * merged into defaultOptions if flash 9 is being used\r\n */\r\n\r\n onfailure: null, // callback function for when playing fails (Flash 9, MovieStar + RTMP-only)\r\n isMovieStar: null, // \"MovieStar\" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL\r\n usePeakData: false, // enable left/right channel peak (level) data\r\n useWaveformData: false, // enable sound spectrum (raw waveform data) - NOTE: May increase CPU load.\r\n useEQData: false, // enable sound EQ (frequency spectrum data) - NOTE: May increase CPU load.\r\n onbufferchange: null, // callback for \"isBuffering\" property change\r\n ondataerror: null // callback for waveform/eq data access error (flash playing audio in other tabs/domains)\r\n\r\n };\r\n\r\n this.movieStarOptions = {\r\n\r\n /**\r\n * flash 9.0r115+ MPEG4 audio options,\r\n * merged into defaultOptions if flash 9+movieStar mode is enabled\r\n */\r\n\r\n bufferTime: 3, // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.)\r\n serverURL: null, // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants\r\n onconnect: null, // rtmp: callback for connection to flash media server\r\n duration: null // rtmp: song duration (msec)\r\n\r\n };\r\n\r\n this.audioFormats = {\r\n\r\n /**\r\n * determines HTML5 support + flash requirements.\r\n * if no support (via flash and/or HTML5) for a \"required\" format, SM2 will fail to start.\r\n * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true)\r\n */\r\n\r\n mp3: {\r\n type: ['audio/mpeg; codecs=\"mp3\"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'],\r\n required: true\r\n },\r\n\r\n mp4: {\r\n related: ['aac', 'm4a', 'm4b'], // additional formats under the MP4 container\r\n type: ['audio/mp4; codecs=\"mp4a.40.2\"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'],\r\n required: false\r\n },\r\n\r\n ogg: {\r\n type: ['audio/ogg; codecs=vorbis'],\r\n required: false\r\n },\r\n\r\n opus: {\r\n type: ['audio/ogg; codecs=opus', 'audio/opus'],\r\n required: false\r\n },\r\n\r\n wav: {\r\n type: ['audio/wav; codecs=\"1\"', 'audio/wav', 'audio/wave', 'audio/x-wav'],\r\n required: false\r\n },\r\n\r\n flac: {\r\n type: ['audio/flac'],\r\n required: false\r\n }\r\n\r\n };\r\n\r\n // HTML attributes (id + class names) for the SWF container\r\n\r\n this.movieID = 'sm2-container';\r\n this.id = (smID || 'sm2movie');\r\n\r\n this.debugID = 'soundmanager-debug';\r\n this.debugURLParam = /([#?&])debug=1/i;\r\n\r\n // dynamic attributes\r\n\r\n this.versionNumber = 'V2.97a.20170601';\r\n this.version = null;\r\n this.movieURL = null;\r\n this.altURL = null;\r\n this.swfLoaded = false;\r\n this.enabled = false;\r\n this.oMC = null;\r\n this.sounds = {};\r\n this.soundIDs = [];\r\n this.muted = false;\r\n this.didFlashBlock = false;\r\n this.filePattern = null;\r\n\r\n this.filePatterns = {\r\n flash8: /\\.mp3(\\?.*)?$/i,\r\n flash9: /\\.mp3(\\?.*)?$/i\r\n };\r\n\r\n // support indicators, set at init\r\n\r\n this.features = {\r\n buffering: false,\r\n peakData: false,\r\n waveformData: false,\r\n eqData: false,\r\n movieStar: false\r\n };\r\n\r\n // flash sandbox info, used primarily in troubleshooting\r\n\r\n this.sandbox = {\r\n // <d>\r\n type: null,\r\n types: {\r\n remote: 'remote (domain-based) rules',\r\n localWithFile: 'local with file access (no internet access)',\r\n localWithNetwork: 'local with network (internet access only, no local access)',\r\n localTrusted: 'local, trusted (local+internet access)'\r\n },\r\n description: null,\r\n noRemote: null,\r\n noLocal: null\r\n // </d>\r\n };\r\n\r\n /**\r\n * format support (html5/flash)\r\n * stores canPlayType() results based on audioFormats.\r\n * eg. { mp3: boolean, mp4: boolean }\r\n * treat as read-only.\r\n */\r\n\r\n this.html5 = {\r\n usingFlash: null // set if/when flash fallback is needed\r\n };\r\n\r\n // file type support hash\r\n this.flash = {};\r\n\r\n // determined at init time\r\n this.html5Only = false;\r\n\r\n // used for special cases (eg. iPad/iPhone/palm OS?)\r\n this.ignoreFlash = false;\r\n\r\n /**\r\n * a few private internals (OK, a lot. :D)\r\n */\r\n\r\n var SMSound,\r\n sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, rebootIntoHTML5, setVersionInfo, handleFocus, strings, initMovie, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [],\r\n canIgnoreFlash, needsFlash = null, featureCheck, html5OK, html5CanPlay, html5ErrorCodes, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0, didSetup, msecScale = 1000,\r\n is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie|trident/i),\r\n isWebkit = ua.match(/webkit/i),\r\n isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)),\r\n isOpera = (ua.match(/opera/i)),\r\n mobileHTML5 = (ua.match(/(mobile|pre\\/|xoom)/i) || is_iDevice || isAndroid),\r\n isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS\\sX\\s10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, \"Silk\") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159\r\n hasConsole = (window.console !== _undefined && console.log !== _undefined),\r\n isFocused = (doc.hasFocus !== _undefined ? doc.hasFocus() : null),\r\n tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())),\r\n okToDisable = !tryInitOnFocus,\r\n flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i,\r\n emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs)\r\n emptyWAV = 'data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==', // tiny WAV for HTML5 unloading\r\n overHTTP = (doc.location ? doc.location.protocol.match(/http/i) : null),\r\n http = (!overHTTP ? '//' : ''),\r\n // mp3, mp4, aac etc.\r\n netStreamMimeTypes = /^\\s*audio\\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4|m4v|m4a|m4b|mp4v|3gp|3g2)\\s*(?:$|;)/i,\r\n // Flash v9.0r115+ \"moviestar\" formats\r\n netStreamTypes = ['mpeg4', 'aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'm4b', 'mp4v', '3gp', '3g2'],\r\n netStreamPattern = new RegExp('\\\\.(' + netStreamTypes.join('|') + ')(\\\\?.*)?$', 'i');\r\n\r\n this.mimePattern = /^\\s*audio\\/(?:x-)?(?:mp(?:eg|3))\\s*(?:$|;)/i; // default mp3 set\r\n\r\n // use altURL if not \"online\"\r\n this.useAltURL = !overHTTP;\r\n\r\n swfCSS = {\r\n swfBox: 'sm2-object-box',\r\n swfDefault: 'movieContainer',\r\n swfError: 'swf_error', // SWF loaded, but SM2 couldn't start (other error)\r\n swfTimedout: 'swf_timedout',\r\n swfLoaded: 'swf_loaded',\r\n swfUnblocked: 'swf_unblocked', // or loaded OK\r\n sm2Debug: 'sm2_debug',\r\n highPerf: 'high_performance',\r\n flashDebug: 'flash_debug'\r\n };\r\n\r\n /**\r\n * HTML5 error codes, per W3C\r\n * Error code 1, MEDIA_ERR_ABORTED: Client aborted download at user's request.\r\n * Error code 2, MEDIA_ERR_NETWORK: A network error of some description caused the user agent to stop fetching the media resource, after the resource was established to be usable.\r\n * Error code 3, MEDIA_ERR_DECODE: An error of some description occurred while decoding the media resource, after the resource was established to be usable.\r\n * Error code 4, MEDIA_ERR_SRC_NOT_SUPPORTED: Media (audio file) not supported (\"not usable.\")\r\n * Reference: https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes\r\n */\r\n html5ErrorCodes = [\r\n null,\r\n 'MEDIA_ERR_ABORTED',\r\n 'MEDIA_ERR_NETWORK',\r\n 'MEDIA_ERR_DECODE',\r\n 'MEDIA_ERR_SRC_NOT_SUPPORTED'\r\n ];\r\n\r\n /**\r\n * basic HTML5 Audio() support test\r\n * try...catch because of IE 9 \"not implemented\" nonsense\r\n * https://github.com/Modernizr/Modernizr/issues/224\r\n */\r\n\r\n this.hasHTML5 = (function() {\r\n try {\r\n // new Audio(null) for stupid Opera 9.64 case, which throws not_enough_arguments exception otherwise.\r\n return (Audio !== _undefined && (isOpera && opera !== _undefined && opera.version() < 10 ? new Audio(null) : new Audio()).canPlayType !== _undefined);\r\n } catch(e) {\r\n return false;\r\n }\r\n }());\r\n\r\n /**\r\n * Public SoundManager API\r\n * -----------------------\r\n */\r\n\r\n /**\r\n * Configures top-level soundManager properties.\r\n *\r\n * @param {object} options Option parameters, eg. { flashVersion: 9, url: '/path/to/swfs/' }\r\n * onready and ontimeout are also accepted parameters. call soundManager.setup() to see the full list.\r\n */\r\n\r\n this.setup = function(options) {\r\n\r\n var noURL = (!sm2.url);\r\n\r\n // warn if flash options have already been applied\r\n\r\n if (options !== _undefined && didInit && needsFlash && sm2.ok() && (options.flashVersion !== _undefined || options.url !== _undefined || options.html5Test !== _undefined)) {\r\n complain(str('setupLate'));\r\n }\r\n\r\n // TODO: defer: true?\r\n\r\n assign(options);\r\n\r\n if (!useGlobalHTML5Audio) {\r\n\r\n if (mobileHTML5) {\r\n\r\n // force the singleton HTML5 pattern on mobile, by default.\r\n if (!sm2.setupOptions.ignoreMobileRestrictions || sm2.setupOptions.forceUseGlobalHTML5Audio) {\r\n messages.push(strings.globalHTML5);\r\n useGlobalHTML5Audio = true;\r\n }\r\n\r\n } else if (sm2.setupOptions.forceUseGlobalHTML5Audio) {\r\n\r\n // only apply singleton HTML5 on desktop if forced.\r\n messages.push(strings.globalHTML5);\r\n useGlobalHTML5Audio = true;\r\n\r\n }\r\n\r\n }\r\n\r\n if (!didSetup && mobileHTML5) {\r\n\r\n if (sm2.setupOptions.ignoreMobileRestrictions) {\r\n\r\n messages.push(strings.ignoreMobile);\r\n\r\n } else {\r\n\r\n // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point.\r\n\r\n // <d>\r\n if (!sm2.setupOptions.useHTML5Audio || sm2.setupOptions.preferFlash) {\r\n // notify that defaults are being changed.\r\n sm2._wD(strings.mobileUA);\r\n }\r\n // </d>\r\n\r\n sm2.setupOptions.useHTML5Audio = true;\r\n sm2.setupOptions.preferFlash = false;\r\n\r\n if (is_iDevice) {\r\n\r\n // no flash here.\r\n sm2.ignoreFlash = true;\r\n\r\n } else if ((isAndroid && !ua.match(/android\\s2\\.3/i)) || !isAndroid) {\r\n\r\n /**\r\n * Android devices tend to work better with a single audio instance, specifically for chained playback of sounds in sequence.\r\n * Common use case: exiting sound onfinish() -> createSound() -> play()\r\n * Presuming similar restrictions for other mobile, non-Android, non-iOS devices.\r\n */\r\n\r\n // <d>\r\n sm2._wD(strings.globalHTML5);\r\n // </d>\r\n\r\n useGlobalHTML5Audio = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n // special case 1: \"Late setup\". SM2 loaded normally, but user didn't assign flash URL eg., setup({url:...}) before SM2 init. Treat as delayed init.\r\n\r\n if (options) {\r\n\r\n if (noURL && didDCLoaded && options.url !== _undefined) {\r\n sm2.beginDelayedInit();\r\n }\r\n\r\n // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP.\r\n\r\n if (!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') {\r\n setTimeout(domContentLoaded, 1);\r\n }\r\n\r\n }\r\n\r\n didSetup = true;\r\n\r\n return sm2;\r\n\r\n };\r\n\r\n this.ok = function() {\r\n\r\n return (needsFlash ? (didInit && !disabled) : (sm2.useHTML5Audio && sm2.hasHTML5));\r\n\r\n };\r\n\r\n this.supported = this.ok; // legacy\r\n\r\n this.getMovie = function(movie_id) {\r\n\r\n // safety net: some old browsers differ on SWF references, possibly related to ExternalInterface / flash version\r\n return id(movie_id) || doc[movie_id] || window[movie_id];\r\n\r\n };\r\n\r\n /**\r\n * Creates a SMSound sound object instance. Can also be overloaded, e.g., createSound('mySound', '/some.mp3');\r\n *\r\n * @param {object} oOptions Sound options (at minimum, url parameter is required.)\r\n * @return {object} SMSound The new SMSound object.\r\n */\r\n\r\n this.createSound = function(oOptions, _url) {\r\n\r\n var cs, cs_string, options, oSound = null;\r\n\r\n // <d>\r\n cs = sm + '.createSound(): ';\r\n cs_string = cs + str(!didInit ? 'notReady' : 'notOK');\r\n // </d>\r\n\r\n if (!didInit || !sm2.ok()) {\r\n complain(cs_string);\r\n return false;\r\n }\r\n\r\n if (_url !== _undefined) {\r\n // function overloading in JS! :) ... assume simple createSound(id, url) use case.\r\n oOptions = {\r\n id: oOptions,\r\n url: _url\r\n };\r\n }\r\n\r\n // inherit from defaultOptions\r\n options = mixin(oOptions);\r\n\r\n options.url = parseURL(options.url);\r\n\r\n // generate an id, if needed.\r\n if (options.id === _undefined) {\r\n options.id = sm2.setupOptions.idPrefix + (idCounter++);\r\n }\r\n\r\n // <d>\r\n if (options.id.toString().charAt(0).match(/^[0-9]$/)) {\r\n sm2._wD(cs + str('badID', options.id), 2);\r\n }\r\n\r\n sm2._wD(cs + options.id + (options.url ? ' (' + options.url + ')' : ''), 1);\r\n // </d>\r\n\r\n if (idCheck(options.id, true)) {\r\n sm2._wD(cs + options.id + ' exists', 1);\r\n return sm2.sounds[options.id];\r\n }\r\n\r\n function make() {\r\n\r\n options = loopFix(options);\r\n sm2.sounds[options.id] = new SMSound(options);\r\n sm2.soundIDs.push(options.id);\r\n return sm2.sounds[options.id];\r\n\r\n }\r\n\r\n if (html5OK(options)) {\r\n\r\n oSound = make();\r\n // <d>\r\n if (!sm2.html5Only) {\r\n sm2._wD(options.id + ': Using HTML5');\r\n }\r\n // </d>\r\n oSound._setup_html5(options);\r\n\r\n } else {\r\n\r\n if (sm2.html5Only) {\r\n sm2._wD(options.id + ': No HTML5 support for this sound, and no Flash. Exiting.');\r\n return make();\r\n }\r\n\r\n // TODO: Move HTML5/flash checks into generic URL parsing/handling function.\r\n\r\n if (sm2.html5.usingFlash && options.url && options.url.match(/data:/i)) {\r\n // data: URIs not supported by Flash, either.\r\n sm2._wD(options.id + ': data: URIs not supported via Flash. Exiting.');\r\n return make();\r\n }\r\n\r\n if (fV > 8) {\r\n if (options.isMovieStar === null) {\r\n // attempt to detect MPEG-4 formats\r\n options.isMovieStar = !!(options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || (options.url && options.url.match(netStreamPattern)));\r\n }\r\n // <d>\r\n if (options.isMovieStar) {\r\n sm2._wD(cs + 'using MovieStar handling');\r\n if (options.loops > 1) {\r\n _wDS('noNSLoop');\r\n }\r\n }\r\n // </d>\r\n }\r\n\r\n options = policyFix(options, cs);\r\n oSound = make();\r\n\r\n if (fV === 8) {\r\n flash._createSound(options.id, options.loops || 1, options.usePolicyFile);\r\n } else {\r\n flash._createSound(options.id, options.url, options.usePeakData, options.useWaveformData, options.useEQData, options.isMovieStar, (options.isMovieStar ? options.bufferTime : false), options.loops || 1, options.serverURL, options.duration || null, options.autoPlay, true, options.autoLoad, options.usePolicyFile);\r\n if (!options.serverURL) {\r\n // We are connected immediately\r\n oSound.connected = true;\r\n if (options.onconnect) {\r\n options.onconnect.apply(oSound);\r\n }\r\n }\r\n }\r\n\r\n if (!options.serverURL && (options.autoLoad || options.autoPlay)) {\r\n // call load for non-rtmp streams\r\n oSound.load(options);\r\n }\r\n\r\n }\r\n\r\n // rtmp will play in onconnect\r\n if (!options.serverURL && options.autoPlay) {\r\n oSound.play();\r\n }\r\n\r\n return oSound;\r\n\r\n };\r\n\r\n /**\r\n * Destroys a SMSound sound object instance.\r\n *\r\n * @param {string} sID The ID of the sound to destroy\r\n */\r\n\r\n this.destroySound = function(sID, _bFromSound) {\r\n\r\n // explicitly destroy a sound before normal page unload, etc.\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n var oS = sm2.sounds[sID], i;\r\n\r\n oS.stop();\r\n\r\n // Disable all callbacks after stop(), when the sound is being destroyed\r\n oS._iO = {};\r\n\r\n oS.unload();\r\n\r\n for (i = 0; i < sm2.soundIDs.length; i++) {\r\n if (sm2.soundIDs[i] === sID) {\r\n sm2.soundIDs.splice(i, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (!_bFromSound) {\r\n // ignore if being called from SMSound instance\r\n oS.destruct(true);\r\n }\r\n\r\n oS = null;\r\n delete sm2.sounds[sID];\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Calls the load() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {object} oOptions Optional: Sound options\r\n */\r\n\r\n this.load = function(sID, oOptions) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].load(oOptions);\r\n\r\n };\r\n\r\n /**\r\n * Calls the unload() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n */\r\n\r\n this.unload = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].unload();\r\n\r\n };\r\n\r\n /**\r\n * Calls the onPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod The relevant callback to fire\r\n * @param {object} oScope Optional: The scope to apply the callback to\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.onPosition = function(sID, nPosition, oMethod, oScope) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].onposition(nPosition, oMethod, oScope);\r\n\r\n };\r\n\r\n // legacy/backwards-compability: lower-case method name\r\n this.onposition = this.onPosition;\r\n\r\n /**\r\n * Calls the clearOnPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod Optional: The relevant callback to fire\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.clearOnPosition = function(sID, nPosition, oMethod) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].clearOnPosition(nPosition, oMethod);\r\n\r\n };\r\n\r\n /**\r\n * Calls the play() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {object} oOptions Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.play = function(sID, oOptions) {\r\n\r\n var result = null,\r\n // legacy function-overloading use case: play('mySound', '/path/to/some.mp3');\r\n overloaded = (oOptions && !(oOptions instanceof Object));\r\n\r\n if (!didInit || !sm2.ok()) {\r\n complain(sm + '.play(): ' + str(!didInit ? 'notReady' : 'notOK'));\r\n return false;\r\n }\r\n\r\n if (!idCheck(sID, overloaded)) {\r\n\r\n // no sound found for the given ID. Bail.\r\n if (!overloaded) return false;\r\n\r\n if (overloaded) {\r\n oOptions = {\r\n url: oOptions\r\n };\r\n }\r\n\r\n if (oOptions && oOptions.url) {\r\n // overloading use case, create+play: .play('someID', {url:'/path/to.mp3'});\r\n sm2._wD(sm + '.play(): Attempting to create \"' + sID + '\"', 1);\r\n oOptions.id = sID;\r\n result = sm2.createSound(oOptions).play();\r\n }\r\n\r\n } else if (overloaded) {\r\n\r\n // existing sound object case\r\n oOptions = {\r\n url: oOptions\r\n };\r\n\r\n }\r\n\r\n if (result === null) {\r\n // default case\r\n result = sm2.sounds[sID].play(oOptions);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n // just for convenience\r\n this.start = this.play;\r\n\r\n /**\r\n * Calls the setPlaybackRate() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPlaybackRate = function(sID, rate, allowOverride) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPlaybackRate(rate, allowOverride);\r\n\r\n };\r\n\r\n /**\r\n * Calls the setPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nMsecOffset Position (milliseconds)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPosition = function(sID, nMsecOffset) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPosition(nMsecOffset);\r\n\r\n };\r\n\r\n /**\r\n * Calls the stop() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.stop = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.stop(' + sID + ')', 1);\r\n\r\n return sm2.sounds[sID].stop();\r\n\r\n };\r\n\r\n /**\r\n * Stops all currently-playing sounds.\r\n */\r\n\r\n this.stopAll = function() {\r\n\r\n var oSound;\r\n sm2._wD(sm + '.stopAll()', 1);\r\n\r\n for (oSound in sm2.sounds) {\r\n if (sm2.sounds.hasOwnProperty(oSound)) {\r\n // apply only to sound objects\r\n sm2.sounds[oSound].stop();\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the pause() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.pause = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].pause();\r\n\r\n };\r\n\r\n /**\r\n * Pauses all currently-playing sounds.\r\n */\r\n\r\n this.pauseAll = function() {\r\n\r\n var i;\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].pause();\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the resume() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.resume = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].resume();\r\n\r\n };\r\n\r\n /**\r\n * Resumes all currently-paused sounds.\r\n */\r\n\r\n this.resumeAll = function() {\r\n\r\n var i;\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].resume();\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the togglePause() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.togglePause = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].togglePause();\r\n\r\n };\r\n\r\n /**\r\n * Calls the setPan() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPan The pan value (-100 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPan = function(sID, nPan) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPan(nPan);\r\n\r\n };\r\n\r\n /**\r\n * Calls the setVolume() method of a SMSound object by ID\r\n * Overloaded case: pass only volume argument eg., setVolume(50) to apply to all sounds.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nVol The volume value (0 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setVolume = function(sID, nVol) {\r\n\r\n // setVolume(50) function overloading case - apply to all sounds\r\n\r\n var i, j;\r\n\r\n if (sID !== _undefined && !isNaN(sID) && nVol === _undefined) {\r\n for (i = 0, j = sm2.soundIDs.length; i < j; i++) {\r\n sm2.sounds[sm2.soundIDs[i]].setVolume(sID);\r\n }\r\n return false;\r\n }\r\n\r\n // setVolume('mySound', 50) case\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setVolume(nVol);\r\n\r\n };\r\n\r\n /**\r\n * Calls the mute() method of either a single SMSound object by ID, or all sound objects.\r\n *\r\n * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.)\r\n */\r\n\r\n this.mute = function(sID) {\r\n\r\n var i = 0;\r\n\r\n if (sID instanceof String) {\r\n sID = null;\r\n }\r\n\r\n if (!sID) {\r\n\r\n sm2._wD(sm + '.mute(): Muting all sounds');\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].mute();\r\n }\r\n sm2.muted = true;\r\n\r\n } else {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.mute(): Muting \"' + sID + '\"');\r\n return sm2.sounds[sID].mute();\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Mutes all sounds.\r\n */\r\n\r\n this.muteAll = function() {\r\n\r\n sm2.mute();\r\n\r\n };\r\n\r\n /**\r\n * Calls the unmute() method of either a single SMSound object by ID, or all sound objects.\r\n *\r\n * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.)\r\n */\r\n\r\n this.unmute = function(sID) {\r\n\r\n var i;\r\n\r\n if (sID instanceof String) {\r\n sID = null;\r\n }\r\n\r\n if (!sID) {\r\n\r\n sm2._wD(sm + '.unmute(): Unmuting all sounds');\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].unmute();\r\n }\r\n sm2.muted = false;\r\n\r\n } else {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.unmute(): Unmuting \"' + sID + '\"');\r\n\r\n return sm2.sounds[sID].unmute();\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Unmutes all sounds.\r\n */\r\n\r\n this.unmuteAll = function() {\r\n\r\n sm2.unmute();\r\n\r\n };\r\n\r\n /**\r\n * Calls the toggleMute() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.toggleMute = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].toggleMute();\r\n\r\n };\r\n\r\n /**\r\n * Retrieves the memory used by the flash plugin.\r\n *\r\n * @return {number} The amount of memory in use\r\n */\r\n\r\n this.getMemoryUse = function() {\r\n\r\n // flash-only\r\n var ram = 0;\r\n\r\n if (flash && fV !== 8) {\r\n ram = parseInt(flash._getMemoryUse(), 10);\r\n }\r\n\r\n return ram;\r\n\r\n };\r\n\r\n /**\r\n * Undocumented: NOPs soundManager and all SMSound objects.\r\n */\r\n\r\n this.disable = function(bNoDisable) {\r\n\r\n // destroy all functions\r\n var i;\r\n\r\n if (bNoDisable === _undefined) {\r\n bNoDisable = false;\r\n }\r\n\r\n // already disabled?\r\n if (disabled) return false;\r\n\r\n disabled = true;\r\n\r\n _wDS('shutdown', 1);\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n disableObject(sm2.sounds[sm2.soundIDs[i]]);\r\n }\r\n\r\n disableObject(sm2);\r\n\r\n // fire \"complete\", despite fail\r\n initComplete(bNoDisable);\r\n\r\n event.remove(window, 'load', initUserOnload);\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of a MIME type, eg. 'audio/mp3'.\r\n */\r\n\r\n this.canPlayMIME = function(sMIME) {\r\n\r\n var result;\r\n\r\n if (sm2.hasHTML5) {\r\n result = html5CanPlay({\r\n type: sMIME\r\n });\r\n }\r\n\r\n if (!result && needsFlash) {\r\n // if flash 9, test netStream (movieStar) types as well.\r\n result = (sMIME && sm2.ok() ? !!((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null); // TODO: make less \"weird\" (per JSLint)\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of a URL based on audio support.\r\n *\r\n * @param {string} sURL The URL to test\r\n * @return {boolean} URL playability\r\n */\r\n\r\n this.canPlayURL = function(sURL) {\r\n\r\n var result;\r\n\r\n if (sm2.hasHTML5) {\r\n result = html5CanPlay({\r\n url: sURL\r\n });\r\n }\r\n\r\n if (!result && needsFlash) {\r\n result = (sURL && sm2.ok() ? !!(sURL.match(sm2.filePattern)) : null);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of an HTML DOM <a> object (or similar object literal) based on audio support.\r\n *\r\n * @param {object} oLink an HTML DOM <a> object or object literal including href and/or type attributes\r\n * @return {boolean} URL playability\r\n */\r\n\r\n this.canPlayLink = function(oLink) {\r\n\r\n if (oLink.type !== _undefined && oLink.type && sm2.canPlayMIME(oLink.type)) return true;\r\n\r\n return sm2.canPlayURL(oLink.href);\r\n\r\n };\r\n\r\n /**\r\n * Retrieves a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.getSoundById = function(sID, _suppressDebug) {\r\n\r\n if (!sID) return null;\r\n\r\n var result = sm2.sounds[sID];\r\n\r\n // <d>\r\n if (!result && !_suppressDebug) {\r\n sm2._wD(sm + '.getSoundById(): Sound \"' + sID + '\" not found.', 2);\r\n }\r\n // </d>\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Queues a callback for execution when SoundManager has successfully initialized.\r\n *\r\n * @param {function} oMethod The callback method to fire\r\n * @param {object} oScope Optional: The scope to apply to the callback\r\n */\r\n\r\n this.onready = function(oMethod, oScope) {\r\n\r\n var sType = 'onready',\r\n result = false;\r\n\r\n if (typeof oMethod === 'function') {\r\n\r\n // <d>\r\n if (didInit) {\r\n sm2._wD(str('queue', sType));\r\n }\r\n // </d>\r\n\r\n if (!oScope) {\r\n oScope = window;\r\n }\r\n\r\n addOnEvent(sType, oMethod, oScope);\r\n processOnEvents();\r\n\r\n result = true;\r\n\r\n } else {\r\n\r\n throw str('needFunction', sType);\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Queues a callback for execution when SoundManager has failed to initialize.\r\n *\r\n * @param {function} oMethod The callback method to fire\r\n * @param {object} oScope Optional: The scope to apply to the callback\r\n */\r\n\r\n this.ontimeout = function(oMethod, oScope) {\r\n\r\n var sType = 'ontimeout',\r\n result = false;\r\n\r\n if (typeof oMethod === 'function') {\r\n\r\n // <d>\r\n if (didInit) {\r\n sm2._wD(str('queue', sType));\r\n }\r\n // </d>\r\n\r\n if (!oScope) {\r\n oScope = window;\r\n }\r\n\r\n addOnEvent(sType, oMethod, oScope);\r\n processOnEvents({ type: sType });\r\n\r\n result = true;\r\n\r\n } else {\r\n\r\n throw str('needFunction', sType);\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Writes console.log()-style debug output to a console or in-browser element.\r\n * Applies when debugMode = true\r\n *\r\n * @param {string} sText The console message\r\n * @param {object} nType Optional log level (number), or object. Number case: Log type/style where 0 = 'info', 1 = 'warn', 2 = 'error'. Object case: Object to be dumped.\r\n */\r\n\r\n this._writeDebug = function(sText, sTypeOrObject) {\r\n\r\n // pseudo-private console.log()-style output\r\n // <d>\r\n\r\n var sDID = 'soundmanager-debug', o, oItem;\r\n\r\n if (!sm2.setupOptions.debugMode) return false;\r\n\r\n if (hasConsole && sm2.useConsole) {\r\n if (sTypeOrObject && typeof sTypeOrObject === 'object') {\r\n // object passed; dump to console.\r\n console.log(sText, sTypeOrObject);\r\n } else if (debugLevels[sTypeOrObject] !== _undefined) {\r\n console[debugLevels[sTypeOrObject]](sText);\r\n } else {\r\n console.log(sText);\r\n }\r\n if (sm2.consoleOnly) return true;\r\n }\r\n\r\n o = id(sDID);\r\n\r\n if (!o) return false;\r\n\r\n oItem = doc.createElement('div');\r\n\r\n if (++wdCount % 2 === 0) {\r\n oItem.className = 'sm2-alt';\r\n }\r\n\r\n if (sTypeOrObject === _undefined) {\r\n sTypeOrObject = 0;\r\n } else {\r\n sTypeOrObject = parseInt(sTypeOrObject, 10);\r\n }\r\n\r\n oItem.appendChild(doc.createTextNode(sText));\r\n\r\n if (sTypeOrObject) {\r\n if (sTypeOrObject >= 2) {\r\n oItem.style.fontWeight = 'bold';\r\n }\r\n if (sTypeOrObject === 3) {\r\n oItem.style.color = '#ff3333';\r\n }\r\n }\r\n\r\n // top-to-bottom\r\n // o.appendChild(oItem);\r\n\r\n // bottom-to-top\r\n o.insertBefore(oItem, o.firstChild);\r\n\r\n o = null;\r\n // </d>\r\n\r\n return true;\r\n\r\n };\r\n\r\n // <d>\r\n // last-resort debugging option\r\n if (wl.indexOf('sm2-debug=alert') !== -1) {\r\n this._writeDebug = function(sText) {\r\n window.alert(sText);\r\n };\r\n }\r\n // </d>\r\n\r\n // alias\r\n this._wD = this._writeDebug;\r\n\r\n /**\r\n * Provides debug / state information on all SMSound objects.\r\n */\r\n\r\n this._debug = function() {\r\n\r\n // <d>\r\n var i, j;\r\n _wDS('currentObj', 1);\r\n\r\n for (i = 0, j = sm2.soundIDs.length; i < j; i++) {\r\n sm2.sounds[sm2.soundIDs[i]]._debug();\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n /**\r\n * Restarts and re-initializes the SoundManager instance.\r\n *\r\n * @param {boolean} resetEvents Optional: When true, removes all registered onready and ontimeout event callbacks.\r\n * @param {boolean} excludeInit Options: When true, does not call beginDelayedInit() (which would restart SM2).\r\n * @return {object} soundManager The soundManager instance.\r\n */\r\n\r\n this.reboot = function(resetEvents, excludeInit) {\r\n\r\n // reset some (or all) state, and re-init unless otherwise specified.\r\n\r\n // <d>\r\n if (sm2.soundIDs.length) {\r\n sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound object' + (sm2.soundIDs.length !== 1 ? 's' : '') + '...');\r\n }\r\n // </d>\r\n\r\n var i, j, k;\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].destruct();\r\n }\r\n\r\n // trash ze flash (remove from the DOM)\r\n\r\n if (flash) {\r\n\r\n try {\r\n\r\n if (isIE) {\r\n oRemovedHTML = flash.innerHTML;\r\n }\r\n\r\n oRemoved = flash.parentNode.removeChild(flash);\r\n\r\n } catch(e) {\r\n\r\n // Remove failed? May be due to flash blockers silently removing the SWF object/embed node from the DOM. Warn and continue.\r\n\r\n _wDS('badRemove', 2);\r\n\r\n }\r\n\r\n }\r\n\r\n // actually, force recreate of movie.\r\n\r\n oRemovedHTML = oRemoved = needsFlash = flash = null;\r\n\r\n sm2.enabled = didDCLoaded = didInit = waitingForEI = initPending = didAppend = appendSuccess = disabled = useGlobalHTML5Audio = sm2.swfLoaded = false;\r\n\r\n sm2.soundIDs = [];\r\n sm2.sounds = {};\r\n\r\n idCounter = 0;\r\n didSetup = false;\r\n\r\n if (!resetEvents) {\r\n // reset callbacks for onready, ontimeout etc. so that they will fire again on re-init\r\n for (i in on_queue) {\r\n if (on_queue.hasOwnProperty(i)) {\r\n for (j = 0, k = on_queue[i].length; j < k; j++) {\r\n on_queue[i][j].fired = false;\r\n }\r\n }\r\n }\r\n } else {\r\n // remove all callbacks entirely\r\n on_queue = [];\r\n }\r\n\r\n // <d>\r\n if (!excludeInit) {\r\n sm2._wD(sm + ': Rebooting...');\r\n }\r\n // </d>\r\n\r\n // reset HTML5 and flash canPlay test results\r\n\r\n sm2.html5 = {\r\n usingFlash: null\r\n };\r\n\r\n sm2.flash = {};\r\n\r\n // reset device-specific HTML/flash mode switches\r\n\r\n sm2.html5Only = false;\r\n sm2.ignoreFlash = false;\r\n\r\n window.setTimeout(function() {\r\n\r\n // by default, re-init\r\n\r\n if (!excludeInit) {\r\n sm2.beginDelayedInit();\r\n }\r\n\r\n }, 20);\r\n\r\n return sm2;\r\n\r\n };\r\n\r\n this.reset = function() {\r\n\r\n /**\r\n * Shuts down and restores the SoundManager instance to its original loaded state, without an explicit reboot. All onready/ontimeout handlers are removed.\r\n * After this call, SM2 may be re-initialized via soundManager.beginDelayedInit().\r\n * @return {object} soundManager The soundManager instance.\r\n */\r\n\r\n _wDS('reset');\r\n\r\n return sm2.reboot(true, true);\r\n\r\n };\r\n\r\n /**\r\n * Undocumented: Determines the SM2 flash movie's load progress.\r\n *\r\n * @return {number or null} Percent loaded, or if invalid/unsupported, null.\r\n */\r\n\r\n this.getMoviePercent = function() {\r\n\r\n /**\r\n * Interesting syntax notes...\r\n * Flash/ExternalInterface (ActiveX/NPAPI) bridge methods are not typeof \"function\" nor instanceof Function, but are still valid.\r\n * Furthermore, using (flash && flash.PercentLoaded) causes IE to throw \"object doesn't support this property or method\".\r\n * Thus, 'in' syntax must be used.\r\n */\r\n\r\n return (flash && 'PercentLoaded' in flash ? flash.PercentLoaded() : null);\r\n\r\n };\r\n\r\n /**\r\n * Additional helper for manually invoking SM2's init process after DOM Ready / window.onload().\r\n */\r\n\r\n this.beginDelayedInit = function() {\r\n\r\n windowLoaded = true;\r\n domContentLoaded();\r\n\r\n setTimeout(function() {\r\n\r\n if (initPending) return false;\r\n\r\n createMovie();\r\n initMovie();\r\n initPending = true;\r\n\r\n return true;\r\n\r\n }, 20);\r\n\r\n delayWaitForEI();\r\n\r\n };\r\n\r\n /**\r\n * Destroys the SoundManager instance and all SMSound instances.\r\n */\r\n\r\n this.destruct = function() {\r\n\r\n sm2._wD(sm + '.destruct()');\r\n sm2.disable(true);\r\n\r\n };\r\n\r\n /**\r\n * SMSound() (sound object) constructor\r\n * ------------------------------------\r\n *\r\n * @param {object} oOptions Sound options (id and url are required attributes)\r\n * @return {SMSound} The new SMSound object\r\n */\r\n\r\n SMSound = function(oOptions) {\r\n\r\n var s = this, resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, onPositionItems = [], onPositionFired = 0, detachOnPosition, applyFromTo, lastURL = null, lastHTML5State, urlOmitted;\r\n\r\n lastHTML5State = {\r\n // tracks duration + position (time)\r\n duration: null,\r\n time: null\r\n };\r\n\r\n this.id = oOptions.id;\r\n\r\n // legacy\r\n this.sID = this.id;\r\n\r\n this.url = oOptions.url;\r\n this.options = mixin(oOptions);\r\n\r\n // per-play-instance-specific options\r\n this.instanceOptions = this.options;\r\n\r\n // short alias\r\n this._iO = this.instanceOptions;\r\n\r\n // assign property defaults\r\n this.pan = this.options.pan;\r\n this.volume = this.options.volume;\r\n\r\n // whether or not this object is using HTML5\r\n this.isHTML5 = false;\r\n\r\n // internal HTML5 Audio() object reference\r\n this._a = null;\r\n\r\n // for flash 8 special-case createSound() without url, followed by load/play with url case\r\n urlOmitted = (!this.url);\r\n\r\n /**\r\n * SMSound() public methods\r\n * ------------------------\r\n */\r\n\r\n this.id3 = {};\r\n\r\n /**\r\n * Writes SMSound object parameters to debug console\r\n */\r\n\r\n this._debug = function() {\r\n\r\n // <d>\r\n sm2._wD(s.id + ': Merged options:', s.options);\r\n // </d>\r\n\r\n };\r\n\r\n /**\r\n * Begins loading a sound per its *url*.\r\n *\r\n * @param {object} options Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.load = function(options) {\r\n\r\n var oSound = null, instanceOptions;\r\n\r\n if (options !== _undefined) {\r\n s._iO = mixin(options, s.options);\r\n } else {\r\n options = s.options;\r\n s._iO = options;\r\n if (lastURL && lastURL !== s.url) {\r\n _wDS('manURL');\r\n s._iO.url = s.url;\r\n s.url = null;\r\n }\r\n }\r\n\r\n if (!s._iO.url) {\r\n s._iO.url = s.url;\r\n }\r\n\r\n s._iO.url = parseURL(s._iO.url);\r\n\r\n // ensure we're in sync\r\n s.instanceOptions = s._iO;\r\n\r\n // local shortcut\r\n instanceOptions = s._iO;\r\n\r\n sm2._wD(s.id + ': load (' + instanceOptions.url + ')');\r\n\r\n if (!instanceOptions.url && !s.url) {\r\n sm2._wD(s.id + ': load(): url is unassigned. Exiting.', 2);\r\n return s;\r\n }\r\n\r\n // <d>\r\n if (!s.isHTML5 && fV === 8 && !s.url && !instanceOptions.autoPlay) {\r\n // flash 8 load() -> play() won't work before onload has fired.\r\n sm2._wD(s.id + ': Flash 8 load() limitation: Wait for onload() before calling play().', 1);\r\n }\r\n // </d>\r\n\r\n if (instanceOptions.url === s.url && s.readyState !== 0 && s.readyState !== 2) {\r\n _wDS('onURL', 1);\r\n // if loaded and an onload() exists, fire immediately.\r\n if (s.readyState === 3 && instanceOptions.onload) {\r\n // assume success based on truthy duration.\r\n wrapCallback(s, function() {\r\n instanceOptions.onload.apply(s, [(!!s.duration)]);\r\n });\r\n }\r\n return s;\r\n }\r\n\r\n // reset a few state properties\r\n\r\n s.loaded = false;\r\n s.readyState = 1;\r\n s.playState = 0;\r\n s.id3 = {};\r\n\r\n // TODO: If switching from HTML5 -> flash (or vice versa), stop currently-playing audio.\r\n\r\n if (html5OK(instanceOptions)) {\r\n\r\n oSound = s._setup_html5(instanceOptions);\r\n\r\n if (!oSound._called_load) {\r\n\r\n s._html5_canplay = false;\r\n\r\n // TODO: review called_load / html5_canplay logic\r\n\r\n // if url provided directly to load(), assign it here.\r\n\r\n if (s.url !== instanceOptions.url) {\r\n\r\n sm2._wD(_wDS('manURL') + ': ' + instanceOptions.url);\r\n\r\n s._a.src = instanceOptions.url;\r\n\r\n // TODO: review / re-apply all relevant options (volume, loop, onposition etc.)\r\n\r\n // reset position for new URL\r\n s.setPosition(0);\r\n\r\n }\r\n\r\n // given explicit load call, try to preload.\r\n\r\n // early HTML5 implementation (non-standard)\r\n s._a.autobuffer = 'auto';\r\n\r\n // standard property, values: none / metadata / auto\r\n // reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx\r\n s._a.preload = 'auto';\r\n\r\n s._a._called_load = true;\r\n\r\n } else {\r\n\r\n sm2._wD(s.id + ': Ignoring request to load again');\r\n\r\n }\r\n\r\n } else {\r\n\r\n if (sm2.html5Only) {\r\n sm2._wD(s.id + ': No flash support. Exiting.');\r\n return s;\r\n }\r\n\r\n if (s._iO.url && s._iO.url.match(/data:/i)) {\r\n // data: URIs not supported by Flash, either.\r\n sm2._wD(s.id + ': data: URIs not supported via Flash. Exiting.');\r\n return s;\r\n }\r\n\r\n try {\r\n s.isHTML5 = false;\r\n s._iO = policyFix(loopFix(instanceOptions));\r\n // if we have \"position\", disable auto-play as we'll be seeking to that position at onload().\r\n if (s._iO.autoPlay && (s._iO.position || s._iO.from)) {\r\n sm2._wD(s.id + ': Disabling autoPlay because of non-zero offset case');\r\n s._iO.autoPlay = false;\r\n }\r\n // re-assign local shortcut\r\n instanceOptions = s._iO;\r\n if (fV === 8) {\r\n flash._load(s.id, instanceOptions.url, instanceOptions.stream, instanceOptions.autoPlay, instanceOptions.usePolicyFile);\r\n } else {\r\n flash._load(s.id, instanceOptions.url, !!(instanceOptions.stream), !!(instanceOptions.autoPlay), instanceOptions.loops || 1, !!(instanceOptions.autoLoad), instanceOptions.usePolicyFile);\r\n }\r\n } catch(e) {\r\n _wDS('smError', 2);\r\n debugTS('onload', false);\r\n catchError({\r\n type: 'SMSOUND_LOAD_JS_EXCEPTION',\r\n fatal: true\r\n });\r\n }\r\n\r\n }\r\n\r\n // after all of this, ensure sound url is up to date.\r\n s.url = instanceOptions.url;\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unloads a sound, canceling any open HTTP requests.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.unload = function() {\r\n\r\n // Flash 8/AS2 can't \"close\" a stream - fake it by loading an empty URL\r\n // Flash 9/AS3: Close stream, preventing further load\r\n // HTML5: Most UAs will use empty URL\r\n\r\n if (s.readyState !== 0) {\r\n\r\n sm2._wD(s.id + ': unload()');\r\n\r\n if (!s.isHTML5) {\r\n\r\n if (fV === 8) {\r\n flash._unload(s.id, emptyURL);\r\n } else {\r\n flash._unload(s.id);\r\n }\r\n\r\n } else {\r\n\r\n stop_html5_timer();\r\n\r\n if (s._a) {\r\n\r\n s._a.pause();\r\n\r\n // update empty URL, too\r\n lastURL = html5Unload(s._a);\r\n\r\n }\r\n\r\n }\r\n\r\n // reset load/status flags\r\n resetProperties();\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unloads and destroys a sound.\r\n */\r\n\r\n this.destruct = function(_bFromSM) {\r\n\r\n sm2._wD(s.id + ': Destruct');\r\n\r\n if (!s.isHTML5) {\r\n\r\n // kill sound within Flash\r\n // Disable the onfailure handler\r\n s._iO.onfailure = null;\r\n flash._destroySound(s.id);\r\n\r\n } else {\r\n\r\n stop_html5_timer();\r\n\r\n if (s._a) {\r\n s._a.pause();\r\n html5Unload(s._a);\r\n if (!useGlobalHTML5Audio) {\r\n remove_html5_events();\r\n }\r\n // break obvious circular reference\r\n s._a._s = null;\r\n s._a = null;\r\n }\r\n\r\n }\r\n\r\n if (!_bFromSM) {\r\n // ensure deletion from controller\r\n sm2.destroySound(s.id, true);\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Begins playing a sound.\r\n *\r\n * @param {object} options Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.play = function(options, _updatePlayState) {\r\n\r\n var fN, allowMulti, a, onready,\r\n audioClone, onended, oncanplay,\r\n startOK = true;\r\n\r\n // <d>\r\n fN = s.id + ': play(): ';\r\n // </d>\r\n\r\n // default to true\r\n _updatePlayState = (_updatePlayState === _undefined ? true : _updatePlayState);\r\n\r\n if (!options) {\r\n options = {};\r\n }\r\n\r\n // first, use local URL (if specified)\r\n if (s.url) {\r\n s._iO.url = s.url;\r\n }\r\n\r\n // mix in any options defined at createSound()\r\n s._iO = mixin(s._iO, s.options);\r\n\r\n // mix in any options specific to this method\r\n s._iO = mixin(options, s._iO);\r\n\r\n s._iO.url = parseURL(s._iO.url);\r\n\r\n s.instanceOptions = s._iO;\r\n\r\n // RTMP-only\r\n if (!s.isHTML5 && s._iO.serverURL && !s.connected) {\r\n if (!s.getAutoPlay()) {\r\n sm2._wD(fN + ' Netstream not connected yet - setting autoPlay');\r\n s.setAutoPlay(true);\r\n }\r\n // play will be called in onconnect()\r\n return s;\r\n }\r\n\r\n if (html5OK(s._iO)) {\r\n s._setup_html5(s._iO);\r\n start_html5_timer();\r\n }\r\n\r\n if (s.playState === 1 && !s.paused) {\r\n\r\n allowMulti = s._iO.multiShot;\r\n\r\n if (!allowMulti) {\r\n\r\n sm2._wD(fN + 'Already playing (one-shot)', 1);\r\n\r\n if (s.isHTML5) {\r\n // go back to original position.\r\n s.setPosition(s._iO.position);\r\n }\r\n\r\n return s;\r\n\r\n }\r\n\r\n sm2._wD(fN + 'Already playing (multi-shot)', 1);\r\n\r\n }\r\n\r\n // edge case: play() with explicit URL parameter\r\n if (options.url && options.url !== s.url) {\r\n\r\n // special case for createSound() followed by load() / play() with url; avoid double-load case.\r\n if (!s.readyState && !s.isHTML5 && fV === 8 && urlOmitted) {\r\n\r\n urlOmitted = false;\r\n\r\n } else {\r\n\r\n // load using merged options\r\n s.load(s._iO);\r\n\r\n }\r\n\r\n }\r\n\r\n if (!s.loaded) {\r\n\r\n if (s.readyState === 0) {\r\n\r\n sm2._wD(fN + 'Attempting to load');\r\n\r\n // try to get this sound playing ASAP\r\n if (!s.isHTML5 && !sm2.html5Only) {\r\n\r\n // flash: assign directly because setAutoPlay() increments the instanceCount\r\n s._iO.autoPlay = true;\r\n s.load(s._iO);\r\n\r\n } else if (s.isHTML5) {\r\n\r\n // iOS needs this when recycling sounds, loading a new URL on an existing object.\r\n s.load(s._iO);\r\n\r\n } else {\r\n\r\n sm2._wD(fN + 'Unsupported type. Exiting.');\r\n\r\n return s;\r\n\r\n }\r\n\r\n // HTML5 hack - re-set instanceOptions?\r\n s.instanceOptions = s._iO;\r\n\r\n } else if (s.readyState === 2) {\r\n\r\n sm2._wD(fN + 'Could not load - exiting', 2);\r\n\r\n return s;\r\n\r\n } else {\r\n\r\n sm2._wD(fN + 'Loading - attempting to play...');\r\n\r\n }\r\n\r\n } else {\r\n\r\n // \"play()\"\r\n sm2._wD(fN.substr(0, fN.lastIndexOf(':')));\r\n\r\n }\r\n\r\n if (!s.isHTML5 && fV === 9 && s.position > 0 && s.position === s.duration) {\r\n // flash 9 needs a position reset if play() is called while at the end of a sound.\r\n sm2._wD(fN + 'Sound at end, resetting to position: 0');\r\n options.position = 0;\r\n }\r\n\r\n /**\r\n * Streams will pause when their buffer is full if they are being loaded.\r\n * In this case paused is true, but the song hasn't started playing yet.\r\n * If we just call resume() the onplay() callback will never be called.\r\n * So only call resume() if the position is > 0.\r\n * Another reason is because options like volume won't have been applied yet.\r\n * For normal sounds, just resume.\r\n */\r\n\r\n if (s.paused && s.position >= 0 && (!s._iO.serverURL || s.position > 0)) {\r\n\r\n // https://gist.github.com/37b17df75cc4d7a90bf6\r\n sm2._wD(fN + 'Resuming from paused state', 1);\r\n s.resume();\r\n\r\n } else {\r\n\r\n s._iO = mixin(options, s._iO);\r\n\r\n /**\r\n * Preload in the event of play() with position under Flash,\r\n * or from/to parameters and non-RTMP case\r\n */\r\n if (((!s.isHTML5 && s._iO.position !== null && s._iO.position > 0) || (s._iO.from !== null && s._iO.from > 0) || s._iO.to !== null) && s.instanceCount === 0 && s.playState === 0 && !s._iO.serverURL) {\r\n\r\n onready = function() {\r\n // sound \"canplay\" or onload()\r\n // re-apply position/from/to to instance options, and start playback\r\n s._iO = mixin(options, s._iO);\r\n s.play(s._iO);\r\n };\r\n\r\n // HTML5 needs to at least have \"canplay\" fired before seeking.\r\n if (s.isHTML5 && !s._html5_canplay) {\r\n\r\n // this hasn't been loaded yet. load it first, and then do this again.\r\n sm2._wD(fN + 'Beginning load for non-zero offset case');\r\n\r\n s.load({\r\n // note: custom HTML5-only event added for from/to implementation.\r\n _oncanplay: onready\r\n });\r\n\r\n } else if (!s.isHTML5 && !s.loaded && (!s.readyState || s.readyState !== 2)) {\r\n\r\n // to be safe, preload the whole thing in Flash.\r\n\r\n sm2._wD(fN + 'Preloading for non-zero offset case');\r\n\r\n s.load({\r\n onload: onready\r\n });\r\n\r\n }\r\n\r\n // otherwise, we're ready to go. re-apply local options, and continue\r\n\r\n s._iO = applyFromTo();\r\n\r\n }\r\n\r\n // sm2._wD(fN + 'Starting to play');\r\n\r\n // increment instance counter, where enabled + supported\r\n if (!s.instanceCount || s._iO.multiShotEvents || (s.isHTML5 && s._iO.multiShot && !useGlobalHTML5Audio) || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) {\r\n s.instanceCount++;\r\n }\r\n\r\n // if first play and onposition parameters exist, apply them now\r\n if (s._iO.onposition && s.playState === 0) {\r\n attachOnPosition(s);\r\n }\r\n\r\n s.playState = 1;\r\n s.paused = false;\r\n\r\n s.position = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position : 0);\r\n\r\n if (!s.isHTML5) {\r\n s._iO = policyFix(loopFix(s._iO));\r\n }\r\n\r\n if (s._iO.onplay && _updatePlayState) {\r\n s._iO.onplay.apply(s);\r\n onplay_called = true;\r\n }\r\n\r\n s.setVolume(s._iO.volume, true);\r\n s.setPan(s._iO.pan, true);\r\n\r\n if (s._iO.playbackRate !== 1) {\r\n s.setPlaybackRate(s._iO.playbackRate);\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / msecScale), s._iO.multiShot || false);\r\n\r\n if (fV === 9 && !startOK) {\r\n // edge case: no sound hardware, or 32-channel flash ceiling hit.\r\n // applies only to Flash 9, non-NetStream/MovieStar sounds.\r\n // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play%28%29\r\n sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit', 2);\r\n if (s._iO.onplayerror) {\r\n s._iO.onplayerror.apply(s);\r\n }\r\n\r\n }\r\n\r\n } else if (s.instanceCount < 2) {\r\n\r\n // HTML5 single-instance case\r\n\r\n start_html5_timer();\r\n\r\n a = s._setup_html5();\r\n\r\n s.setPosition(s._iO.position);\r\n\r\n a.play();\r\n\r\n } else {\r\n\r\n // HTML5 multi-shot case\r\n\r\n sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...');\r\n\r\n audioClone = new Audio(s._iO.url);\r\n\r\n onended = function() {\r\n event.remove(audioClone, 'ended', onended);\r\n s._onfinish(s);\r\n // cleanup\r\n html5Unload(audioClone);\r\n audioClone = null;\r\n };\r\n\r\n oncanplay = function() {\r\n event.remove(audioClone, 'canplay', oncanplay);\r\n try {\r\n audioClone.currentTime = s._iO.position / msecScale;\r\n } catch(err) {\r\n complain(s.id + ': multiShot play() failed to apply position of ' + (s._iO.position / msecScale));\r\n }\r\n audioClone.play();\r\n };\r\n\r\n event.add(audioClone, 'ended', onended);\r\n\r\n // apply volume to clones, too\r\n if (s._iO.volume !== _undefined) {\r\n audioClone.volume = Math.max(0, Math.min(1, s._iO.volume / 100));\r\n }\r\n\r\n // playing multiple muted sounds? if you do this, you're weird ;) - but let's cover it.\r\n if (s.muted) {\r\n audioClone.muted = true;\r\n }\r\n\r\n if (s._iO.position) {\r\n // HTML5 audio can't seek before onplay() event has fired.\r\n // wait for canplay, then seek to position and start playback.\r\n event.add(audioClone, 'canplay', oncanplay);\r\n } else {\r\n // begin playback at currentTime: 0\r\n audioClone.play();\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n // just for convenience\r\n this.start = this.play;\r\n\r\n /**\r\n * Stops playing a sound (and optionally, all sounds)\r\n *\r\n * @param {boolean} bAll Optional: Whether to stop all sounds\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.stop = function(bAll) {\r\n\r\n var instanceOptions = s._iO,\r\n originalPosition;\r\n\r\n if (s.playState === 1) {\r\n\r\n sm2._wD(s.id + ': stop()');\r\n\r\n s._onbufferchange(0);\r\n s._resetOnPosition(0);\r\n s.paused = false;\r\n\r\n if (!s.isHTML5) {\r\n s.playState = 0;\r\n }\r\n\r\n // remove onPosition listeners, if any\r\n detachOnPosition();\r\n\r\n // and \"to\" position, if set\r\n if (instanceOptions.to) {\r\n s.clearOnPosition(instanceOptions.to);\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n flash._stop(s.id, bAll);\r\n\r\n // hack for netStream: just unload\r\n if (instanceOptions.serverURL) {\r\n s.unload();\r\n }\r\n\r\n } else if (s._a) {\r\n\r\n originalPosition = s.position;\r\n\r\n // act like Flash, though\r\n s.setPosition(0);\r\n\r\n // hack: reflect old position for onstop() (also like Flash)\r\n s.position = originalPosition;\r\n\r\n // html5 has no stop()\r\n // NOTE: pausing means iOS requires interaction to resume.\r\n s._a.pause();\r\n\r\n s.playState = 0;\r\n\r\n // and update UI\r\n s._onTimer();\r\n\r\n stop_html5_timer();\r\n\r\n }\r\n\r\n s.instanceCount = 0;\r\n s._iO = {};\r\n\r\n if (instanceOptions.onstop) {\r\n instanceOptions.onstop.apply(s);\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Undocumented/internal: Sets autoPlay for RTMP.\r\n *\r\n * @param {boolean} autoPlay state\r\n */\r\n\r\n this.setAutoPlay = function(autoPlay) {\r\n\r\n sm2._wD(s.id + ': Autoplay turned ' + (autoPlay ? 'on' : 'off'));\r\n s._iO.autoPlay = autoPlay;\r\n\r\n if (!s.isHTML5) {\r\n flash._setAutoPlay(s.id, autoPlay);\r\n if (autoPlay) {\r\n // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP)\r\n if (!s.instanceCount && s.readyState === 1) {\r\n s.instanceCount++;\r\n sm2._wD(s.id + ': Incremented instance count to ' + s.instanceCount);\r\n }\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Undocumented/internal: Returns the autoPlay boolean.\r\n *\r\n * @return {boolean} The current autoPlay value\r\n */\r\n\r\n this.getAutoPlay = function() {\r\n\r\n return s._iO.autoPlay;\r\n\r\n };\r\n\r\n /**\r\n * Sets the playback rate of a sound (HTML5-only.)\r\n *\r\n * @param {number} playbackRate (+/-)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPlaybackRate = function(playbackRate) {\r\n\r\n // Per Mozilla, limit acceptable values to prevent playback from stopping (unless allowOverride is truthy.)\r\n // https://developer.mozilla.org/en-US/Apps/Build/Audio_and_video_delivery/WebAudio_playbackRate_explained\r\n var normalizedRate = Math.max(0.5, Math.min(4, playbackRate));\r\n\r\n // <d>\r\n if (normalizedRate !== playbackRate) {\r\n sm2._wD(s.id + ': setPlaybackRate(' + playbackRate + '): limiting rate to ' + normalizedRate, 2);\r\n }\r\n // </d>\r\n\r\n if (s.isHTML5) {\r\n try {\r\n s._iO.playbackRate = normalizedRate;\r\n s._a.playbackRate = normalizedRate;\r\n } catch(e) {\r\n sm2._wD(s.id + ': setPlaybackRate(' + normalizedRate + ') failed: ' + e.message, 2);\r\n }\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the position of a sound.\r\n *\r\n * @param {number} nMsecOffset Position (milliseconds)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPosition = function(nMsecOffset) {\r\n\r\n if (nMsecOffset === _undefined) {\r\n nMsecOffset = 0;\r\n }\r\n\r\n var position, position1K,\r\n // Use the duration from the instance options, if we don't have a track duration yet.\r\n // position >= 0 and <= current available (loaded) duration\r\n offset = (s.isHTML5 ? Math.max(nMsecOffset, 0) : Math.min(s.duration || s._iO.duration, Math.max(nMsecOffset, 0)));\r\n\r\n s.position = offset;\r\n position1K = s.position / msecScale;\r\n s._resetOnPosition(s.position);\r\n s._iO.position = offset;\r\n\r\n if (!s.isHTML5) {\r\n\r\n position = (fV === 9 ? s.position : position1K);\r\n\r\n if (s.readyState && s.readyState !== 2) {\r\n // if paused or not playing, will not resume (by playing)\r\n flash._setPosition(s.id, position, (s.paused || !s.playState), s._iO.multiShot);\r\n }\r\n\r\n } else if (s._a) {\r\n\r\n // Set the position in the canplay handler if the sound is not ready yet\r\n if (s._html5_canplay) {\r\n\r\n if (s._a.currentTime.toFixed(3) !== position1K.toFixed(3)) {\r\n\r\n /**\r\n * DOM/JS errors/exceptions to watch out for:\r\n * if seek is beyond (loaded?) position, \"DOM exception 11\"\r\n * \"INDEX_SIZE_ERR\": DOM exception 1\r\n */\r\n sm2._wD(s.id + ': setPosition(' + position1K + ')');\r\n\r\n try {\r\n s._a.currentTime = position1K;\r\n if (s.playState === 0 || s.paused) {\r\n // allow seek without auto-play/resume\r\n s._a.pause();\r\n }\r\n } catch(e) {\r\n sm2._wD(s.id + ': setPosition(' + position1K + ') failed: ' + e.message, 2);\r\n }\r\n\r\n }\r\n\r\n } else if (position1K) {\r\n\r\n // warn on non-zero seek attempts\r\n sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready', 2);\r\n return s;\r\n\r\n }\r\n\r\n if (s.paused) {\r\n\r\n // if paused, refresh UI right away by forcing update\r\n s._onTimer(true);\r\n\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Pauses sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.pause = function(_bCallFlash) {\r\n\r\n if (s.paused || (s.playState === 0 && s.readyState !== 1)) return s;\r\n\r\n sm2._wD(s.id + ': pause()');\r\n s.paused = true;\r\n\r\n if (!s.isHTML5) {\r\n if (_bCallFlash || _bCallFlash === _undefined) {\r\n flash._pause(s.id, s._iO.multiShot);\r\n }\r\n } else {\r\n s._setup_html5().pause();\r\n stop_html5_timer();\r\n }\r\n\r\n if (s._iO.onpause) {\r\n s._iO.onpause.apply(s);\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Resumes sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n /**\r\n * When auto-loaded streams pause on buffer full they have a playState of 0.\r\n * We need to make sure that the playState is set to 1 when these streams \"resume\".\r\n * When a paused stream is resumed, we need to trigger the onplay() callback if it\r\n * hasn't been called already. In this case since the sound is being played for the\r\n * first time, I think it's more appropriate to call onplay() rather than onresume().\r\n */\r\n\r\n this.resume = function() {\r\n\r\n var instanceOptions = s._iO;\r\n\r\n if (!s.paused) return s;\r\n\r\n sm2._wD(s.id + ': resume()');\r\n s.paused = false;\r\n s.playState = 1;\r\n\r\n if (!s.isHTML5) {\r\n\r\n if (instanceOptions.isMovieStar && !instanceOptions.serverURL) {\r\n // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition.\r\n s.setPosition(s.position);\r\n }\r\n\r\n // flash method is toggle-based (pause/resume)\r\n flash._pause(s.id, instanceOptions.multiShot);\r\n\r\n } else {\r\n\r\n s._setup_html5().play();\r\n start_html5_timer();\r\n\r\n }\r\n\r\n if (!onplay_called && instanceOptions.onplay) {\r\n\r\n instanceOptions.onplay.apply(s);\r\n onplay_called = true;\r\n\r\n } else if (instanceOptions.onresume) {\r\n\r\n instanceOptions.onresume.apply(s);\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Toggles sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.togglePause = function() {\r\n\r\n sm2._wD(s.id + ': togglePause()');\r\n\r\n if (s.playState === 0) {\r\n s.play({\r\n position: (fV === 9 && !s.isHTML5 ? s.position : s.position / msecScale)\r\n });\r\n return s;\r\n }\r\n\r\n if (s.paused) {\r\n s.resume();\r\n } else {\r\n s.pause();\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the panning (L-R) effect.\r\n *\r\n * @param {number} nPan The pan value (-100 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPan = function(nPan, bInstanceOnly) {\r\n\r\n if (nPan === _undefined) {\r\n nPan = 0;\r\n }\r\n\r\n if (bInstanceOnly === _undefined) {\r\n bInstanceOnly = false;\r\n }\r\n\r\n if (!s.isHTML5) {\r\n flash._setPan(s.id, nPan);\r\n } // else { no HTML5 pan? }\r\n\r\n s._iO.pan = nPan;\r\n\r\n if (!bInstanceOnly) {\r\n s.pan = nPan;\r\n s.options.pan = nPan;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the volume.\r\n *\r\n * @param {number} nVol The volume value (0 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setVolume = function(nVol, _bInstanceOnly) {\r\n\r\n /**\r\n * Note: Setting volume has no effect on iOS \"special snowflake\" devices.\r\n * Hardware volume control overrides software, and volume\r\n * will always return 1 per Apple docs. (iOS 4 + 5.)\r\n * http://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingSoundtoCanvasAnimations/AddingSoundtoCanvasAnimations.html\r\n */\r\n\r\n if (nVol === _undefined) {\r\n nVol = 100;\r\n }\r\n\r\n if (_bInstanceOnly === _undefined) {\r\n _bInstanceOnly = false;\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n flash._setVolume(s.id, (sm2.muted && !s.muted) || s.muted ? 0 : nVol);\r\n\r\n } else if (s._a) {\r\n\r\n if (sm2.muted && !s.muted) {\r\n s.muted = true;\r\n s._a.muted = true;\r\n }\r\n\r\n // valid range for native HTML5 Audio(): 0-1\r\n s._a.volume = Math.max(0, Math.min(1, nVol / 100));\r\n\r\n }\r\n\r\n s._iO.volume = nVol;\r\n\r\n if (!_bInstanceOnly) {\r\n s.volume = nVol;\r\n s.options.volume = nVol;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Mutes the sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.mute = function() {\r\n\r\n s.muted = true;\r\n\r\n if (!s.isHTML5) {\r\n flash._setVolume(s.id, 0);\r\n } else if (s._a) {\r\n s._a.muted = true;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unmutes the sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.unmute = function() {\r\n\r\n s.muted = false;\r\n var hasIO = (s._iO.volume !== _undefined);\r\n\r\n if (!s.isHTML5) {\r\n flash._setVolume(s.id, hasIO ? s._iO.volume : s.options.volume);\r\n } else if (s._a) {\r\n s._a.muted = false;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Toggles the muted state of a sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.toggleMute = function() {\r\n\r\n return (s.muted ? s.unmute() : s.mute());\r\n\r\n };\r\n\r\n /**\r\n * Registers a callback to be fired when a sound reaches a given position during playback.\r\n *\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod The relevant callback to fire\r\n * @param {object} oScope Optional: The scope to apply the callback to\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.onPosition = function(nPosition, oMethod, oScope) {\r\n\r\n // TODO: basic dupe checking?\r\n\r\n onPositionItems.push({\r\n position: parseInt(nPosition, 10),\r\n method: oMethod,\r\n scope: (oScope !== _undefined ? oScope : s),\r\n fired: false\r\n });\r\n\r\n return s;\r\n\r\n };\r\n\r\n // legacy/backwards-compability: lower-case method name\r\n this.onposition = this.onPosition;\r\n\r\n /**\r\n * Removes registered callback(s) from a sound, by position and/or callback.\r\n *\r\n * @param {number} nPosition The position to clear callback(s) for\r\n * @param {function} oMethod Optional: Identify one callback to be removed when multiple listeners exist for one position\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.clearOnPosition = function(nPosition, oMethod) {\r\n\r\n var i;\r\n\r\n nPosition = parseInt(nPosition, 10);\r\n\r\n if (isNaN(nPosition)) {\r\n // safety check\r\n return;\r\n }\r\n\r\n for (i = 0; i < onPositionItems.length; i++) {\r\n\r\n if (nPosition === onPositionItems[i].position) {\r\n // remove this item if no method was specified, or, if the method matches\r\n\r\n if (!oMethod || (oMethod === onPositionItems[i].method)) {\r\n\r\n if (onPositionItems[i].fired) {\r\n // decrement \"fired\" counter, too\r\n onPositionFired--;\r\n }\r\n\r\n onPositionItems.splice(i, 1);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._processOnPosition = function() {\r\n\r\n var i, item, j = onPositionItems.length;\r\n\r\n if (!j || !s.playState || onPositionFired >= j) return false;\r\n\r\n for (i = j - 1; i >= 0; i--) {\r\n\r\n item = onPositionItems[i];\r\n\r\n if (!item.fired && s.position >= item.position) {\r\n\r\n item.fired = true;\r\n onPositionFired++;\r\n item.method.apply(item.scope, [item.position]);\r\n\r\n // reset j -- onPositionItems.length can be changed in the item callback above... occasionally breaking the loop.\r\n j = onPositionItems.length;\r\n\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._resetOnPosition = function(nPosition) {\r\n\r\n // reset \"fired\" for items interested in this position\r\n var i, item, j = onPositionItems.length;\r\n\r\n if (!j) return false;\r\n\r\n for (i = j - 1; i >= 0; i--) {\r\n\r\n item = onPositionItems[i];\r\n\r\n if (item.fired && nPosition <= item.position) {\r\n item.fired = false;\r\n onPositionFired--;\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * SMSound() private internals\r\n * --------------------------------\r\n */\r\n\r\n applyFromTo = function() {\r\n\r\n var instanceOptions = s._iO,\r\n f = instanceOptions.from,\r\n t = instanceOptions.to,\r\n start, end;\r\n\r\n end = function() {\r\n\r\n // end has been reached.\r\n sm2._wD(s.id + ': \"To\" time of ' + t + ' reached.');\r\n\r\n // detach listener\r\n s.clearOnPosition(t, end);\r\n\r\n // stop should clear this, too\r\n s.stop();\r\n\r\n };\r\n\r\n start = function() {\r\n\r\n sm2._wD(s.id + ': Playing \"from\" ' + f);\r\n\r\n // add listener for end\r\n if (t !== null && !isNaN(t)) {\r\n s.onPosition(t, end);\r\n }\r\n\r\n };\r\n\r\n if (f !== null && !isNaN(f)) {\r\n\r\n // apply to instance options, guaranteeing correct start position.\r\n instanceOptions.position = f;\r\n\r\n // multiShot timing can't be tracked, so prevent that.\r\n instanceOptions.multiShot = false;\r\n\r\n start();\r\n\r\n }\r\n\r\n // return updated instanceOptions including starting position\r\n return instanceOptions;\r\n\r\n };\r\n\r\n attachOnPosition = function() {\r\n\r\n var item,\r\n op = s._iO.onposition;\r\n\r\n // attach onposition things, if any, now.\r\n\r\n if (op) {\r\n\r\n for (item in op) {\r\n if (op.hasOwnProperty(item)) {\r\n s.onPosition(parseInt(item, 10), op[item]);\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n detachOnPosition = function() {\r\n\r\n var item,\r\n op = s._iO.onposition;\r\n\r\n // detach any onposition()-style listeners.\r\n\r\n if (op) {\r\n\r\n for (item in op) {\r\n if (op.hasOwnProperty(item)) {\r\n s.clearOnPosition(parseInt(item, 10));\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n start_html5_timer = function() {\r\n\r\n if (s.isHTML5) {\r\n startTimer(s);\r\n }\r\n\r\n };\r\n\r\n stop_html5_timer = function() {\r\n\r\n if (s.isHTML5) {\r\n stopTimer(s);\r\n }\r\n\r\n };\r\n\r\n resetProperties = function(retainPosition) {\r\n\r\n if (!retainPosition) {\r\n onPositionItems = [];\r\n onPositionFired = 0;\r\n }\r\n\r\n onplay_called = false;\r\n\r\n s._hasTimer = null;\r\n s._a = null;\r\n s._html5_canplay = false;\r\n s.bytesLoaded = null;\r\n s.bytesTotal = null;\r\n s.duration = (s._iO && s._iO.duration ? s._iO.duration : null);\r\n s.durationEstimate = null;\r\n s.buffered = [];\r\n\r\n // legacy: 1D array\r\n s.eqData = [];\r\n\r\n s.eqData.left = [];\r\n s.eqData.right = [];\r\n\r\n s.failures = 0;\r\n s.isBuffering = false;\r\n s.instanceOptions = {};\r\n s.instanceCount = 0;\r\n s.loaded = false;\r\n s.metadata = {};\r\n\r\n // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success\r\n s.readyState = 0;\r\n\r\n s.muted = false;\r\n s.paused = false;\r\n\r\n s.peakData = {\r\n left: 0,\r\n right: 0\r\n };\r\n\r\n s.waveformData = {\r\n left: [],\r\n right: []\r\n };\r\n\r\n s.playState = 0;\r\n s.position = null;\r\n\r\n s.id3 = {};\r\n\r\n };\r\n\r\n resetProperties();\r\n\r\n /**\r\n * Pseudo-private SMSound internals\r\n * --------------------------------\r\n */\r\n\r\n this._onTimer = function(bForce) {\r\n\r\n /**\r\n * HTML5-only _whileplaying() etc.\r\n * called from both HTML5 native events, and polling/interval-based timers\r\n * mimics flash and fires only when time/duration change, so as to be polling-friendly\r\n */\r\n\r\n var duration, isNew = false, time, x = {};\r\n\r\n if (s._hasTimer || bForce) {\r\n\r\n // TODO: May not need to track readyState (1 = loading)\r\n\r\n if (s._a && (bForce || ((s.playState > 0 || s.readyState === 1) && !s.paused))) {\r\n\r\n duration = s._get_html5_duration();\r\n\r\n if (duration !== lastHTML5State.duration) {\r\n\r\n lastHTML5State.duration = duration;\r\n s.duration = duration;\r\n isNew = true;\r\n\r\n }\r\n\r\n // TODO: investigate why this goes wack if not set/re-set each time.\r\n s.durationEstimate = s.duration;\r\n\r\n time = (s._a.currentTime * msecScale || 0);\r\n\r\n if (time !== lastHTML5State.time) {\r\n\r\n lastHTML5State.time = time;\r\n isNew = true;\r\n\r\n }\r\n\r\n if (isNew || bForce) {\r\n\r\n s._whileplaying(time, x, x, x, x);\r\n\r\n }\r\n\r\n }/* else {\r\n\r\n // sm2._wD('_onTimer: Warn for \"'+s.id+'\": '+(!s._a?'Could not find element. ':'')+(s.playState === 0?'playState bad, 0?':'playState = '+s.playState+', OK'));\r\n\r\n return false;\r\n\r\n }*/\r\n\r\n }\r\n\r\n return isNew;\r\n\r\n };\r\n\r\n this._get_html5_duration = function() {\r\n\r\n var instanceOptions = s._iO,\r\n // if audio object exists, use its duration - else, instance option duration (if provided - it's a hack, really, and should be retired) OR null\r\n d = (s._a && s._a.duration ? s._a.duration * msecScale : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)),\r\n result = (d && !isNaN(d) && d !== Infinity ? d : null);\r\n\r\n return result;\r\n\r\n };\r\n\r\n this._apply_loop = function(a, nLoops) {\r\n\r\n /**\r\n * boolean instead of \"loop\", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop\r\n * note that loop is either off or infinite under HTML5, unlike Flash which allows arbitrary loop counts to be specified.\r\n */\r\n\r\n // <d>\r\n if (!a.loop && nLoops > 1) {\r\n sm2._wD('Note: Native HTML5 looping is infinite.', 1);\r\n }\r\n // </d>\r\n\r\n a.loop = (nLoops > 1 ? 'loop' : '');\r\n\r\n };\r\n\r\n this._setup_html5 = function(options) {\r\n\r\n var instanceOptions = mixin(s._iO, options),\r\n a = useGlobalHTML5Audio ? globalHTML5Audio : s._a,\r\n dURL = decodeURI(instanceOptions.url),\r\n sameURL;\r\n\r\n /**\r\n * \"First things first, I, Poppa...\" (reset the previous state of the old sound, if playing)\r\n * Fixes case with devices that can only play one sound at a time\r\n * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state\r\n */\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n if (dURL === decodeURI(lastGlobalHTML5URL)) {\r\n // global HTML5 audio: re-use of URL\r\n sameURL = true;\r\n }\r\n\r\n } else if (dURL === decodeURI(lastURL)) {\r\n\r\n // options URL is the same as the \"last\" URL, and we used (loaded) it\r\n sameURL = true;\r\n\r\n }\r\n\r\n if (a) {\r\n\r\n if (a._s) {\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n if (a._s && a._s.playState && !sameURL) {\r\n\r\n // global HTML5 audio case, and loading a new URL. stop the currently-playing one.\r\n a._s.stop();\r\n\r\n }\r\n\r\n } else if (!useGlobalHTML5Audio && dURL === decodeURI(lastURL)) {\r\n\r\n // non-global HTML5 reuse case: same url, ignore request\r\n s._apply_loop(a, instanceOptions.loops);\r\n\r\n return a;\r\n\r\n }\r\n\r\n }\r\n\r\n if (!sameURL) {\r\n\r\n // don't retain onPosition() stuff with new URLs.\r\n\r\n if (lastURL) {\r\n resetProperties(false);\r\n }\r\n\r\n // assign new HTML5 URL\r\n\r\n a.src = instanceOptions.url;\r\n\r\n s.url = instanceOptions.url;\r\n\r\n lastURL = instanceOptions.url;\r\n\r\n lastGlobalHTML5URL = instanceOptions.url;\r\n\r\n a._called_load = false;\r\n\r\n }\r\n\r\n } else {\r\n\r\n if (instanceOptions.autoLoad || instanceOptions.autoPlay) {\r\n\r\n s._a = new Audio(instanceOptions.url);\r\n s._a.load();\r\n\r\n } else {\r\n\r\n // null for stupid Opera 9.64 case\r\n s._a = (isOpera && opera.version() < 10 ? new Audio(null) : new Audio());\r\n\r\n }\r\n\r\n // assign local reference\r\n a = s._a;\r\n\r\n a._called_load = false;\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n globalHTML5Audio = a;\r\n\r\n }\r\n\r\n }\r\n\r\n s.isHTML5 = true;\r\n\r\n // store a ref on the track\r\n s._a = a;\r\n\r\n // store a ref on the audio\r\n a._s = s;\r\n\r\n add_html5_events();\r\n\r\n s._apply_loop(a, instanceOptions.loops);\r\n\r\n if (instanceOptions.autoLoad || instanceOptions.autoPlay) {\r\n\r\n s.load();\r\n\r\n } else {\r\n\r\n // early HTML5 implementation (non-standard)\r\n a.autobuffer = false;\r\n\r\n // standard ('none' is also an option.)\r\n a.preload = 'auto';\r\n\r\n }\r\n\r\n return a;\r\n\r\n };\r\n\r\n add_html5_events = function() {\r\n\r\n if (s._a._added_events) return false;\r\n\r\n var f;\r\n\r\n function add(oEvt, oFn, bCapture) {\r\n return s._a ? s._a.addEventListener(oEvt, oFn, bCapture || false) : null;\r\n }\r\n\r\n s._a._added_events = true;\r\n\r\n for (f in html5_events) {\r\n if (html5_events.hasOwnProperty(f)) {\r\n add(f, html5_events[f]);\r\n }\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n remove_html5_events = function() {\r\n\r\n // Remove event listeners\r\n\r\n var f;\r\n\r\n function remove(oEvt, oFn, bCapture) {\r\n return (s._a ? s._a.removeEventListener(oEvt, oFn, bCapture || false) : null);\r\n }\r\n\r\n sm2._wD(s.id + ': Removing event listeners');\r\n s._a._added_events = false;\r\n\r\n for (f in html5_events) {\r\n if (html5_events.hasOwnProperty(f)) {\r\n remove(f, html5_events[f]);\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Pseudo-private event internals\r\n * ------------------------------\r\n */\r\n\r\n this._onload = function(nSuccess) {\r\n\r\n var fN,\r\n // check for duration to prevent false positives from flash 8 when loading from cache.\r\n loadOK = !!nSuccess || (!s.isHTML5 && fV === 8 && s.duration);\r\n\r\n // <d>\r\n fN = s.id + ': ';\r\n sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load / invalid sound?' + (!s.duration ? ' Zero-length duration reported.' : ' -') + ' (' + s.url + ')'), (loadOK ? 1 : 2));\r\n\r\n if (!loadOK && !s.isHTML5) {\r\n if (sm2.sandbox.noRemote === true) {\r\n sm2._wD(fN + str('noNet'), 1);\r\n }\r\n if (sm2.sandbox.noLocal === true) {\r\n sm2._wD(fN + str('noLocal'), 1);\r\n }\r\n }\r\n // </d>\r\n\r\n s.loaded = loadOK;\r\n s.readyState = (loadOK ? 3 : 2);\r\n s._onbufferchange(0);\r\n\r\n if (!loadOK && !s.isHTML5) {\r\n // note: no error code from Flash.\r\n s._onerror();\r\n }\r\n\r\n if (s._iO.onload) {\r\n wrapCallback(s, function() {\r\n s._iO.onload.apply(s, [loadOK]);\r\n });\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._onerror = function(errorCode, description) {\r\n\r\n // https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes\r\n if (s._iO.onerror) {\r\n wrapCallback(s, function() {\r\n s._iO.onerror.apply(s, [errorCode, description]);\r\n });\r\n }\r\n\r\n };\r\n\r\n this._onbufferchange = function(nIsBuffering) {\r\n\r\n // ignore if not playing\r\n if (s.playState === 0) return false;\r\n\r\n if ((nIsBuffering && s.isBuffering) || (!nIsBuffering && !s.isBuffering)) return false;\r\n\r\n s.isBuffering = (nIsBuffering === 1);\r\n\r\n if (s._iO.onbufferchange) {\r\n sm2._wD(s.id + ': Buffer state change: ' + nIsBuffering);\r\n s._iO.onbufferchange.apply(s, [nIsBuffering]);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Playback may have stopped due to buffering, or related reason.\r\n * This state can be encountered on iOS < 6 when auto-play is blocked.\r\n */\r\n\r\n this._onsuspend = function() {\r\n\r\n if (s._iO.onsuspend) {\r\n sm2._wD(s.id + ': Playback suspended');\r\n s._iO.onsuspend.apply(s);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * flash 9/movieStar + RTMP-only method, should fire only once at most\r\n * at this point we just recreate failed sounds rather than trying to reconnect\r\n */\r\n\r\n this._onfailure = function(msg, level, code) {\r\n\r\n s.failures++;\r\n sm2._wD(s.id + ': Failure (' + s.failures + '): ' + msg);\r\n\r\n if (s._iO.onfailure && s.failures === 1) {\r\n s._iO.onfailure(msg, level, code);\r\n } else {\r\n sm2._wD(s.id + ': Ignoring failure');\r\n }\r\n\r\n };\r\n\r\n /**\r\n * flash 9/movieStar + RTMP-only method for unhandled warnings/exceptions from Flash\r\n * e.g., RTMP \"method missing\" warning (non-fatal) for getStreamLength on server\r\n */\r\n\r\n this._onwarning = function(msg, level, code) {\r\n\r\n if (s._iO.onwarning) {\r\n s._iO.onwarning(msg, level, code);\r\n }\r\n\r\n };\r\n\r\n this._onfinish = function() {\r\n\r\n // store local copy before it gets trashed...\r\n var io_onfinish = s._iO.onfinish;\r\n\r\n s._onbufferchange(0);\r\n s._resetOnPosition(0);\r\n\r\n // reset some state items\r\n if (s.instanceCount) {\r\n\r\n s.instanceCount--;\r\n\r\n if (!s.instanceCount) {\r\n\r\n // remove onPosition listeners, if any\r\n detachOnPosition();\r\n\r\n // reset instance options\r\n s.playState = 0;\r\n s.paused = false;\r\n s.instanceCount = 0;\r\n s.instanceOptions = {};\r\n s._iO = {};\r\n stop_html5_timer();\r\n\r\n // reset position, too\r\n if (s.isHTML5) {\r\n s.position = 0;\r\n }\r\n\r\n }\r\n\r\n if (!s.instanceCount || s._iO.multiShotEvents) {\r\n // fire onfinish for last, or every instance\r\n if (io_onfinish) {\r\n sm2._wD(s.id + ': onfinish()');\r\n wrapCallback(s, function() {\r\n io_onfinish.apply(s);\r\n });\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) {\r\n\r\n var instanceOptions = s._iO;\r\n\r\n s.bytesLoaded = nBytesLoaded;\r\n s.bytesTotal = nBytesTotal;\r\n s.duration = Math.floor(nDuration);\r\n s.bufferLength = nBufferLength;\r\n\r\n if (!s.isHTML5 && !instanceOptions.isMovieStar) {\r\n\r\n if (instanceOptions.duration) {\r\n // use duration from options, if specified and larger. nobody should be specifying duration in options, actually, and it should be retired.\r\n s.durationEstimate = (s.duration > instanceOptions.duration) ? s.duration : instanceOptions.duration;\r\n } else {\r\n s.durationEstimate = parseInt((s.bytesTotal / s.bytesLoaded) * s.duration, 10);\r\n }\r\n\r\n } else {\r\n\r\n s.durationEstimate = s.duration;\r\n\r\n }\r\n\r\n // for flash, reflect sequential-load-style buffering\r\n if (!s.isHTML5) {\r\n s.buffered = [{\r\n start: 0,\r\n end: s.duration\r\n }];\r\n }\r\n\r\n // allow whileloading to fire even if \"load\" fired under HTML5, due to HTTP range/partials\r\n if ((s.readyState !== 3 || s.isHTML5) && instanceOptions.whileloading) {\r\n instanceOptions.whileloading.apply(s);\r\n }\r\n\r\n };\r\n\r\n this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) {\r\n\r\n var instanceOptions = s._iO,\r\n eqLeft;\r\n\r\n // flash safety net\r\n if (isNaN(nPosition) || nPosition === null) return false;\r\n\r\n // Safari HTML5 play() may return small -ve values when starting from position: 0, eg. -50.120396875. Unexpected/invalid per W3, I think. Normalize to 0.\r\n s.position = Math.max(0, nPosition);\r\n\r\n s._processOnPosition();\r\n\r\n if (!s.isHTML5 && fV > 8) {\r\n\r\n if (instanceOptions.usePeakData && oPeakData !== _undefined && oPeakData) {\r\n s.peakData = {\r\n left: oPeakData.leftPeak,\r\n right: oPeakData.rightPeak\r\n };\r\n }\r\n\r\n if (instanceOptions.useWaveformData && oWaveformDataLeft !== _undefined && oWaveformDataLeft) {\r\n s.waveformData = {\r\n left: oWaveformDataLeft.split(','),\r\n right: oWaveformDataRight.split(',')\r\n };\r\n }\r\n\r\n if (instanceOptions.useEQData) {\r\n if (oEQData !== _undefined && oEQData && oEQData.leftEQ) {\r\n eqLeft = oEQData.leftEQ.split(',');\r\n s.eqData = eqLeft;\r\n s.eqData.left = eqLeft;\r\n if (oEQData.rightEQ !== _undefined && oEQData.rightEQ) {\r\n s.eqData.right = oEQData.rightEQ.split(',');\r\n }\r\n }\r\n }\r\n\r\n }\r\n\r\n if (s.playState === 1) {\r\n\r\n // special case/hack: ensure buffering is false if loading from cache (and not yet started)\r\n if (!s.isHTML5 && fV === 8 && !s.position && s.isBuffering) {\r\n s._onbufferchange(0);\r\n }\r\n\r\n if (instanceOptions.whileplaying) {\r\n // flash may call after actual finish\r\n instanceOptions.whileplaying.apply(s);\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._oncaptiondata = function(oData) {\r\n\r\n /**\r\n * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature\r\n *\r\n * @param {object} oData\r\n */\r\n\r\n sm2._wD(s.id + ': Caption data received.');\r\n\r\n s.captiondata = oData;\r\n\r\n if (s._iO.oncaptiondata) {\r\n s._iO.oncaptiondata.apply(s, [oData]);\r\n }\r\n\r\n };\r\n\r\n this._onmetadata = function(oMDProps, oMDData) {\r\n\r\n /**\r\n * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature\r\n * RTMP may include song title, MovieStar content may include encoding info\r\n *\r\n * @param {array} oMDProps (names)\r\n * @param {array} oMDData (values)\r\n */\r\n\r\n sm2._wD(s.id + ': Metadata received.');\r\n\r\n var oData = {}, i, j;\r\n\r\n for (i = 0, j = oMDProps.length; i < j; i++) {\r\n oData[oMDProps[i]] = oMDData[i];\r\n }\r\n\r\n s.metadata = oData;\r\n\r\n if (s._iO.onmetadata) {\r\n s._iO.onmetadata.call(s, s.metadata);\r\n }\r\n\r\n };\r\n\r\n this._onid3 = function(oID3Props, oID3Data) {\r\n\r\n /**\r\n * internal: flash 8 + flash 9 ID3 feature\r\n * may include artist, song title etc.\r\n *\r\n * @param {array} oID3Props (names)\r\n * @param {array} oID3Data (values)\r\n */\r\n\r\n sm2._wD(s.id + ': ID3 data received.');\r\n\r\n var oData = [], i, j;\r\n\r\n for (i = 0, j = oID3Props.length; i < j; i++) {\r\n oData[oID3Props[i]] = oID3Data[i];\r\n }\r\n\r\n s.id3 = mixin(s.id3, oData);\r\n\r\n if (s._iO.onid3) {\r\n s._iO.onid3.apply(s);\r\n }\r\n\r\n };\r\n\r\n // flash/RTMP-only\r\n\r\n this._onconnect = function(bSuccess) {\r\n\r\n bSuccess = (bSuccess === 1);\r\n sm2._wD(s.id + ': ' + (bSuccess ? 'Connected.' : 'Failed to connect? - ' + s.url), (bSuccess ? 1 : 2));\r\n s.connected = bSuccess;\r\n\r\n if (bSuccess) {\r\n\r\n s.failures = 0;\r\n\r\n if (idCheck(s.id)) {\r\n if (s.getAutoPlay()) {\r\n // only update the play state if auto playing\r\n s.play(_undefined, s.getAutoPlay());\r\n } else if (s._iO.autoLoad) {\r\n s.load();\r\n }\r\n }\r\n\r\n if (s._iO.onconnect) {\r\n s._iO.onconnect.apply(s, [bSuccess]);\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._ondataerror = function(sError) {\r\n\r\n // flash 9 wave/eq data handler\r\n // hack: called at start, and end from flash at/after onfinish()\r\n if (s.playState > 0) {\r\n sm2._wD(s.id + ': Data error: ' + sError);\r\n if (s._iO.ondataerror) {\r\n s._iO.ondataerror.apply(s);\r\n }\r\n }\r\n\r\n };\r\n\r\n // <d>\r\n this._debug();\r\n // </d>\r\n\r\n }; // SMSound()\r\n\r\n /**\r\n * Private SoundManager internals\r\n * ------------------------------\r\n */\r\n\r\n getDocument = function() {\r\n\r\n return (doc.body || doc.getElementsByTagName('div')[0]);\r\n\r\n };\r\n\r\n id = function(sID) {\r\n\r\n return doc.getElementById(sID);\r\n\r\n };\r\n\r\n mixin = function(oMain, oAdd) {\r\n\r\n // non-destructive merge\r\n var o1 = (oMain || {}), o2, o;\r\n\r\n // if unspecified, o2 is the default options object\r\n o2 = (oAdd === _undefined ? sm2.defaultOptions : oAdd);\r\n\r\n for (o in o2) {\r\n\r\n if (o2.hasOwnProperty(o) && o1[o] === _undefined) {\r\n\r\n if (typeof o2[o] !== 'object' || o2[o] === null) {\r\n\r\n // assign directly\r\n o1[o] = o2[o];\r\n\r\n } else {\r\n\r\n // recurse through o2\r\n o1[o] = mixin(o1[o], o2[o]);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return o1;\r\n\r\n };\r\n\r\n wrapCallback = function(oSound, callback) {\r\n\r\n /**\r\n * 03/03/2013: Fix for Flash Player 11.6.602.171 + Flash 8 (flashVersion = 8) SWF issue\r\n * setTimeout() fix for certain SMSound callbacks like onload() and onfinish(), where subsequent calls like play() and load() fail when Flash Player 11.6.602.171 is installed, and using soundManager with flashVersion = 8 (which is the default).\r\n * Not sure of exact cause. Suspect race condition and/or invalid (NaN-style) position argument trickling down to the next JS -> Flash _start() call, in the play() case.\r\n * Fix: setTimeout() to yield, plus safer null / NaN checking on position argument provided to Flash.\r\n * https://getsatisfaction.com/schillmania/topics/recent_chrome_update_seems_to_have_broken_my_sm2_audio_player\r\n */\r\n if (!oSound.isHTML5 && fV === 8) {\r\n window.setTimeout(callback, 0);\r\n } else {\r\n callback();\r\n }\r\n\r\n };\r\n\r\n // additional soundManager properties that soundManager.setup() will accept\r\n\r\n extraOptions = {\r\n onready: 1,\r\n ontimeout: 1,\r\n defaultOptions: 1,\r\n flash9Options: 1,\r\n movieStarOptions: 1\r\n };\r\n\r\n assign = function(o, oParent) {\r\n\r\n /**\r\n * recursive assignment of properties, soundManager.setup() helper\r\n * allows property assignment based on whitelist\r\n */\r\n\r\n var i,\r\n result = true,\r\n hasParent = (oParent !== _undefined),\r\n setupOptions = sm2.setupOptions,\r\n bonusOptions = extraOptions;\r\n\r\n // <d>\r\n\r\n // if soundManager.setup() called, show accepted parameters.\r\n\r\n if (o === _undefined) {\r\n\r\n result = [];\r\n\r\n for (i in setupOptions) {\r\n\r\n if (setupOptions.hasOwnProperty(i)) {\r\n result.push(i);\r\n }\r\n\r\n }\r\n\r\n for (i in bonusOptions) {\r\n\r\n if (bonusOptions.hasOwnProperty(i)) {\r\n\r\n if (typeof sm2[i] === 'object') {\r\n result.push(i + ': {...}');\r\n } else if (sm2[i] instanceof Function) {\r\n result.push(i + ': function() {...}');\r\n } else {\r\n result.push(i);\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n sm2._wD(str('setup', result.join(', ')));\r\n\r\n return false;\r\n\r\n }\r\n\r\n // </d>\r\n\r\n for (i in o) {\r\n\r\n if (o.hasOwnProperty(i)) {\r\n\r\n // if not an {object} we want to recurse through...\r\n\r\n if (typeof o[i] !== 'object' || o[i] === null || o[i] instanceof Array || o[i] instanceof RegExp) {\r\n\r\n // check \"allowed\" options\r\n\r\n if (hasParent && bonusOptions[oParent] !== _undefined) {\r\n\r\n // valid recursive / nested object option, eg., { defaultOptions: { volume: 50 } }\r\n sm2[oParent][i] = o[i];\r\n\r\n } else if (setupOptions[i] !== _undefined) {\r\n\r\n // special case: assign to setupOptions object, which soundManager property references\r\n sm2.setupOptions[i] = o[i];\r\n\r\n // assign directly to soundManager, too\r\n sm2[i] = o[i];\r\n\r\n } else if (bonusOptions[i] === _undefined) {\r\n\r\n // invalid or disallowed parameter. complain.\r\n complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2);\r\n\r\n result = false;\r\n\r\n } else if (sm2[i] instanceof Function) {\r\n\r\n /**\r\n * valid extraOptions (bonusOptions) parameter.\r\n * is it a method, like onready/ontimeout? call it.\r\n * multiple parameters should be in an array, eg. soundManager.setup({onready: [myHandler, myScope]});\r\n */\r\n sm2[i].apply(sm2, (o[i] instanceof Array ? o[i] : [o[i]]));\r\n\r\n } else {\r\n\r\n // good old-fashioned direct assignment\r\n sm2[i] = o[i];\r\n\r\n }\r\n\r\n } else if (bonusOptions[i] === _undefined) {\r\n\r\n // recursion case, eg., { defaultOptions: { ... } }\r\n\r\n // invalid or disallowed parameter. complain.\r\n complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2);\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n // recurse through object\r\n return assign(o[i], i);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n function preferFlashCheck(kind) {\r\n\r\n // whether flash should play a given type\r\n return (sm2.preferFlash && hasFlash && !sm2.ignoreFlash && (sm2.flash[kind] !== _undefined && sm2.flash[kind]));\r\n\r\n }\r\n\r\n /**\r\n * Internal DOM2-level event helpers\r\n * ---------------------------------\r\n */\r\n\r\n event = (function() {\r\n\r\n // normalize event methods\r\n var old = (window.attachEvent),\r\n evt = {\r\n add: (old ? 'attachEvent' : 'addEventListener'),\r\n remove: (old ? 'detachEvent' : 'removeEventListener')\r\n };\r\n\r\n // normalize \"on\" event prefix, optional capture argument\r\n function getArgs(oArgs) {\r\n\r\n var args = slice.call(oArgs),\r\n len = args.length;\r\n\r\n if (old) {\r\n // prefix\r\n args[1] = 'on' + args[1];\r\n if (len > 3) {\r\n // no capture\r\n args.pop();\r\n }\r\n } else if (len === 3) {\r\n args.push(false);\r\n }\r\n\r\n return args;\r\n\r\n }\r\n\r\n function apply(args, sType) {\r\n\r\n // normalize and call the event method, with the proper arguments\r\n var element = args.shift(),\r\n method = [evt[sType]];\r\n\r\n if (old) {\r\n // old IE can't do apply().\r\n element[method](args[0], args[1]);\r\n } else {\r\n element[method].apply(element, args);\r\n }\r\n\r\n }\r\n\r\n function add() {\r\n apply(getArgs(arguments), 'add');\r\n }\r\n\r\n function remove() {\r\n apply(getArgs(arguments), 'remove');\r\n }\r\n\r\n return {\r\n add: add,\r\n remove: remove\r\n };\r\n\r\n }());\r\n\r\n /**\r\n * Internal HTML5 event handling\r\n * -----------------------------\r\n */\r\n\r\n function html5_event(oFn) {\r\n\r\n // wrap html5 event handlers so we don't call them on destroyed and/or unloaded sounds\r\n\r\n return function(e) {\r\n\r\n var s = this._s,\r\n result;\r\n\r\n if (!s || !s._a) {\r\n // <d>\r\n if (s && s.id) {\r\n sm2._wD(s.id + ': Ignoring ' + e.type);\r\n } else {\r\n sm2._wD(h5 + 'Ignoring ' + e.type);\r\n }\r\n // </d>\r\n result = null;\r\n } else {\r\n result = oFn.call(this, e);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n }\r\n\r\n html5_events = {\r\n\r\n // HTML5 event-name-to-handler map\r\n\r\n abort: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': abort');\r\n\r\n }),\r\n\r\n // enough has loaded to play\r\n\r\n canplay: html5_event(function() {\r\n\r\n var s = this._s,\r\n position1K;\r\n\r\n if (s._html5_canplay) {\r\n // this event has already fired. ignore.\r\n return;\r\n }\r\n\r\n s._html5_canplay = true;\r\n sm2._wD(s.id + ': canplay');\r\n s._onbufferchange(0);\r\n\r\n // position according to instance options\r\n position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position / msecScale : null);\r\n\r\n // set the position if position was provided before the sound loaded\r\n if (this.currentTime !== position1K) {\r\n sm2._wD(s.id + ': canplay: Setting position to ' + position1K);\r\n try {\r\n this.currentTime = position1K;\r\n } catch(ee) {\r\n sm2._wD(s.id + ': canplay: Setting position of ' + position1K + ' failed: ' + ee.message, 2);\r\n }\r\n }\r\n\r\n // hack for HTML5 from/to case\r\n if (s._iO._oncanplay) {\r\n s._iO._oncanplay();\r\n }\r\n\r\n }),\r\n\r\n canplaythrough: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n if (!s.loaded) {\r\n s._onbufferchange(0);\r\n s._whileloading(s.bytesLoaded, s.bytesTotal, s._get_html5_duration());\r\n s._onload(true);\r\n }\r\n\r\n }),\r\n\r\n durationchange: html5_event(function() {\r\n\r\n // durationchange may fire at various times, probably the safest way to capture accurate/final duration.\r\n\r\n var s = this._s,\r\n duration;\r\n\r\n duration = s._get_html5_duration();\r\n\r\n if (!isNaN(duration) && duration !== s.duration) {\r\n\r\n sm2._wD(this._s.id + ': durationchange (' + duration + ')' + (s.duration ? ', previously ' + s.duration : ''));\r\n\r\n s.durationEstimate = s.duration = duration;\r\n\r\n }\r\n\r\n }),\r\n\r\n // TODO: Reserved for potential use\r\n /*\r\n emptied: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': emptied');\r\n\r\n }),\r\n */\r\n\r\n ended: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n sm2._wD(s.id + ': ended');\r\n\r\n s._onfinish();\r\n\r\n }),\r\n\r\n error: html5_event(function() {\r\n\r\n var description = (html5ErrorCodes[this.error.code] || null);\r\n sm2._wD(this._s.id + ': HTML5 error, code ' + this.error.code + (description ? ' (' + description + ')' : ''));\r\n this._s._onload(false);\r\n this._s._onerror(this.error.code, description);\r\n\r\n }),\r\n\r\n loadeddata: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n sm2._wD(s.id + ': loadeddata');\r\n\r\n // safari seems to nicely report progress events, eventually totalling 100%\r\n if (!s._loaded && !isSafari) {\r\n s.duration = s._get_html5_duration();\r\n }\r\n\r\n }),\r\n\r\n loadedmetadata: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': loadedmetadata');\r\n\r\n }),\r\n\r\n loadstart: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': loadstart');\r\n // assume buffering at first\r\n this._s._onbufferchange(1);\r\n\r\n }),\r\n\r\n play: html5_event(function() {\r\n\r\n // sm2._wD(this._s.id + ': play()');\r\n // once play starts, no buffering\r\n this._s._onbufferchange(0);\r\n\r\n }),\r\n\r\n playing: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': playing ' + String.fromCharCode(9835));\r\n // once play starts, no buffering\r\n this._s._onbufferchange(0);\r\n\r\n }),\r\n\r\n progress: html5_event(function(e) {\r\n\r\n // note: can fire repeatedly after \"loaded\" event, due to use of HTTP range/partials\r\n\r\n var s = this._s,\r\n i, j, progStr, buffered = 0,\r\n isProgress = (e.type === 'progress'),\r\n ranges = e.target.buffered,\r\n // firefox 3.6 implements e.loaded/total (bytes)\r\n loaded = (e.loaded || 0),\r\n total = (e.total || 1);\r\n\r\n // reset the \"buffered\" (loaded byte ranges) array\r\n s.buffered = [];\r\n\r\n if (ranges && ranges.length) {\r\n\r\n // if loaded is 0, try TimeRanges implementation as % of load\r\n // https://developer.mozilla.org/en/DOM/TimeRanges\r\n\r\n // re-build \"buffered\" array\r\n // HTML5 returns seconds. SM2 API uses msec for setPosition() etc., whether Flash or HTML5.\r\n for (i = 0, j = ranges.length; i < j; i++) {\r\n s.buffered.push({\r\n start: ranges.start(i) * msecScale,\r\n end: ranges.end(i) * msecScale\r\n });\r\n }\r\n\r\n // use the last value locally\r\n buffered = (ranges.end(0) - ranges.start(0)) * msecScale;\r\n\r\n // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges\r\n loaded = Math.min(1, buffered / (e.target.duration * msecScale));\r\n\r\n // <d>\r\n if (isProgress && ranges.length > 1) {\r\n progStr = [];\r\n j = ranges.length;\r\n for (i = 0; i < j; i++) {\r\n progStr.push((e.target.buffered.start(i) * msecScale) + '-' + (e.target.buffered.end(i) * msecScale));\r\n }\r\n sm2._wD(this._s.id + ': progress, timeRanges: ' + progStr.join(', '));\r\n }\r\n\r\n if (isProgress && !isNaN(loaded)) {\r\n sm2._wD(this._s.id + ': progress, ' + Math.floor(loaded * 100) + '% loaded');\r\n }\r\n // </d>\r\n\r\n }\r\n\r\n if (!isNaN(loaded)) {\r\n\r\n // TODO: prevent calls with duplicate values.\r\n s._whileloading(loaded, total, s._get_html5_duration());\r\n if (loaded && total && loaded === total) {\r\n // in case \"onload\" doesn't fire (eg. gecko 1.9.2)\r\n html5_events.canplaythrough.call(this, e);\r\n }\r\n\r\n }\r\n\r\n }),\r\n\r\n ratechange: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': ratechange');\r\n\r\n }),\r\n\r\n suspend: html5_event(function(e) {\r\n\r\n // download paused/stopped, may have finished (eg. onload)\r\n var s = this._s;\r\n\r\n sm2._wD(this._s.id + ': suspend');\r\n html5_events.progress.call(this, e);\r\n s._onsuspend();\r\n\r\n }),\r\n\r\n stalled: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': stalled');\r\n\r\n }),\r\n\r\n timeupdate: html5_event(function() {\r\n\r\n this._s._onTimer();\r\n\r\n }),\r\n\r\n waiting: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n // see also: seeking\r\n sm2._wD(this._s.id + ': waiting');\r\n\r\n // playback faster than download rate, etc.\r\n s._onbufferchange(1);\r\n\r\n })\r\n\r\n };\r\n\r\n html5OK = function(iO) {\r\n\r\n // playability test based on URL or MIME type\r\n\r\n var result;\r\n\r\n if (!iO || (!iO.type && !iO.url && !iO.serverURL)) {\r\n\r\n // nothing to check\r\n result = false;\r\n\r\n } else if (iO.serverURL || (iO.type && preferFlashCheck(iO.type))) {\r\n\r\n // RTMP, or preferring flash\r\n result = false;\r\n\r\n } else {\r\n\r\n // Use type, if specified. Pass data: URIs to HTML5. If HTML5-only mode, no other options, so just give 'er\r\n result = ((iO.type ? html5CanPlay({ type: iO.type }) : html5CanPlay({ url: iO.url }) || sm2.html5Only || iO.url.match(/data:/i)));\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n html5Unload = function(oAudio) {\r\n\r\n /**\r\n * Internal method: Unload media, and cancel any current/pending network requests.\r\n * Firefox can load an empty URL, which allegedly destroys the decoder and stops the download.\r\n * https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media\r\n * However, Firefox has been seen loading a relative URL from '' and thus requesting the hosting page on unload.\r\n * Other UA behaviour is unclear, so everyone else gets an about:blank-style URL.\r\n */\r\n\r\n var url;\r\n\r\n if (oAudio) {\r\n\r\n // Firefox and Chrome accept short WAVe data: URIs. Chome dislikes audio/wav, but accepts audio/wav for data: MIME.\r\n // Desktop Safari complains / fails on data: URI, so it gets about:blank.\r\n url = (isSafari ? emptyURL : (sm2.html5.canPlayType('audio/wav') ? emptyWAV : emptyURL));\r\n\r\n oAudio.src = url;\r\n\r\n // reset some state, too\r\n if (oAudio._called_unload !== _undefined) {\r\n oAudio._called_load = false;\r\n }\r\n\r\n }\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n // ensure URL state is trashed, also\r\n lastGlobalHTML5URL = null;\r\n\r\n }\r\n\r\n return url;\r\n\r\n };\r\n\r\n html5CanPlay = function(o) {\r\n\r\n /**\r\n * Try to find MIME, test and return truthiness\r\n * o = {\r\n * url: '/path/to/an.mp3',\r\n * type: 'audio/mp3'\r\n * }\r\n */\r\n\r\n if (!sm2.useHTML5Audio || !sm2.hasHTML5) return false;\r\n\r\n var url = (o.url || null),\r\n mime = (o.type || null),\r\n aF = sm2.audioFormats,\r\n result,\r\n offset,\r\n fileExt,\r\n item;\r\n\r\n // account for known cases like audio/mp3\r\n\r\n if (mime && sm2.html5[mime] !== _undefined) return (sm2.html5[mime] && !preferFlashCheck(mime));\r\n\r\n if (!html5Ext) {\r\n\r\n html5Ext = [];\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n html5Ext.push(item);\r\n\r\n if (aF[item].related) {\r\n html5Ext = html5Ext.concat(aF[item].related);\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n html5Ext = new RegExp('\\\\.(' + html5Ext.join('|') + ')(\\\\?.*)?$', 'i');\r\n\r\n }\r\n\r\n // TODO: Strip URL queries, etc.\r\n fileExt = (url ? url.toLowerCase().match(html5Ext) : null);\r\n\r\n if (!fileExt || !fileExt.length) {\r\n\r\n if (!mime) {\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n // audio/mp3 -> mp3, result should be known\r\n offset = mime.indexOf(';');\r\n\r\n // strip \"audio/X; codecs...\"\r\n fileExt = (offset !== -1 ? mime.substr(0, offset) : mime).substr(6);\r\n\r\n }\r\n\r\n } else {\r\n\r\n // match the raw extension name - \"mp3\", for example\r\n fileExt = fileExt[1];\r\n\r\n }\r\n\r\n if (fileExt && sm2.html5[fileExt] !== _undefined) {\r\n\r\n // result known\r\n result = (sm2.html5[fileExt] && !preferFlashCheck(fileExt));\r\n\r\n } else {\r\n\r\n mime = 'audio/' + fileExt;\r\n result = sm2.html5.canPlayType({ type: mime });\r\n\r\n sm2.html5[fileExt] = result;\r\n\r\n // sm2._wD('canPlayType, found result: ' + result);\r\n result = (result && sm2.html5[mime] && !preferFlashCheck(mime));\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n testHTML5 = function() {\r\n\r\n /**\r\n * Internal: Iterates over audioFormats, determining support eg. audio/mp3, audio/mpeg and so on\r\n * assigns results to html5[] and flash[].\r\n */\r\n\r\n if (!sm2.useHTML5Audio || !sm2.hasHTML5) {\r\n\r\n // without HTML5, we need Flash.\r\n sm2.html5.usingFlash = true;\r\n needsFlash = true;\r\n\r\n return false;\r\n\r\n }\r\n\r\n // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load \"null\" as a URL. :/\r\n var a = (Audio !== _undefined ? (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()) : null),\r\n item, lookup, support = {}, aF, i;\r\n\r\n function cp(m) {\r\n\r\n var canPlay, j,\r\n result = false,\r\n isOK = false;\r\n\r\n if (!a || typeof a.canPlayType !== 'function') return result;\r\n\r\n if (m instanceof Array) {\r\n\r\n // iterate through all mime types, return any successes\r\n\r\n for (i = 0, j = m.length; i < j; i++) {\r\n\r\n if (sm2.html5[m[i]] || a.canPlayType(m[i]).match(sm2.html5Test)) {\r\n\r\n isOK = true;\r\n sm2.html5[m[i]] = true;\r\n\r\n // note flash support, too\r\n sm2.flash[m[i]] = !!(m[i].match(flashMIME));\r\n\r\n }\r\n\r\n }\r\n\r\n result = isOK;\r\n\r\n } else {\r\n\r\n canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false);\r\n result = !!(canPlay && (canPlay.match(sm2.html5Test)));\r\n\r\n }\r\n\r\n return result;\r\n\r\n }\r\n\r\n // test all registered formats + codecs\r\n\r\n aF = sm2.audioFormats;\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n lookup = 'audio/' + item;\r\n\r\n support[item] = cp(aF[item].type);\r\n\r\n // write back generic type too, eg. audio/mp3\r\n support[lookup] = support[item];\r\n\r\n // assign flash\r\n if (item.match(flashMIME)) {\r\n\r\n sm2.flash[item] = true;\r\n sm2.flash[lookup] = true;\r\n\r\n } else {\r\n\r\n sm2.flash[item] = false;\r\n sm2.flash[lookup] = false;\r\n\r\n }\r\n\r\n // assign result to related formats, too\r\n\r\n if (aF[item] && aF[item].related) {\r\n\r\n for (i = aF[item].related.length - 1; i >= 0; i--) {\r\n\r\n // eg. audio/m4a\r\n support['audio/' + aF[item].related[i]] = support[item];\r\n sm2.html5[aF[item].related[i]] = support[item];\r\n sm2.flash[aF[item].related[i]] = support[item];\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n support.canPlayType = (a ? cp : null);\r\n sm2.html5 = mixin(sm2.html5, support);\r\n\r\n sm2.html5.usingFlash = featureCheck();\r\n needsFlash = sm2.html5.usingFlash;\r\n\r\n return true;\r\n\r\n };\r\n\r\n strings = {\r\n\r\n // <d>\r\n notReady: 'Unavailable - wait until onready() has fired.',\r\n notOK: 'Audio support is not available.',\r\n domError: sm + 'exception caught while appending SWF to DOM.',\r\n spcWmode: 'Removing wmode, preventing known SWF loading issue(s)',\r\n swf404: smc + 'Verify that %s is a valid path.',\r\n tryDebug: 'Try ' + sm + '.debugFlash = true for more security details (output goes to SWF.)',\r\n checkSWF: 'See SWF output for more debug info.',\r\n localFail: smc + 'Non-HTTP page (' + doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/',\r\n waitFocus: smc + 'Special case: Waiting for SWF to load with window focus...',\r\n waitForever: smc + 'Waiting indefinitely for Flash (will recover if unblocked)...',\r\n waitSWF: smc + 'Waiting for 100% SWF load...',\r\n needFunction: smc + 'Function object expected for %s',\r\n badID: 'Sound ID \"%s\" should be a string, starting with a non-numeric character',\r\n currentObj: smc + '_debug(): Current sound objects',\r\n waitOnload: smc + 'Waiting for window.onload()',\r\n docLoaded: smc + 'Document already loaded',\r\n onload: smc + 'initComplete(): calling soundManager.onload()',\r\n onloadOK: sm + '.onload() complete',\r\n didInit: smc + 'init(): Already called?',\r\n secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',\r\n badRemove: smc + 'Failed to remove Flash node.',\r\n shutdown: sm + '.disable(): Shutting down',\r\n queue: smc + 'Queueing %s handler',\r\n smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.',\r\n fbTimeout: 'No flash response, applying .' + swfCSS.swfTimedout + ' CSS...',\r\n fbLoaded: 'Flash loaded',\r\n fbHandler: smc + 'flashBlockHandler()',\r\n manURL: 'SMSound.load(): Using manually-assigned URL',\r\n onURL: sm + '.load(): current URL already assigned.',\r\n badFV: sm + '.flashVersion must be 8 or 9. \"%s\" is invalid. Reverting to %s.',\r\n as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)',\r\n noNSLoop: 'Note: Looping not implemented for MovieStar formats',\r\n needfl9: 'Note: Switching to flash 9, required for MP4 formats.',\r\n mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case',\r\n needFlash: smc + 'Fatal error: Flash is needed to play some required formats, but is not available.',\r\n gotFocus: smc + 'Got window focus.',\r\n policy: 'Enabling usePolicyFile for data access',\r\n setup: sm + '.setup(): allowed parameters: %s',\r\n setupError: sm + '.setup(): \"%s\" cannot be assigned with this method.',\r\n setupUndef: sm + '.setup(): Could not find option \"%s\"',\r\n setupLate: sm + '.setup(): url, flashVersion and html5Test property changes will not take effect until reboot().',\r\n noURL: smc + 'Flash URL required. Call soundManager.setup({url:...}) to get started.',\r\n sm2Loaded: 'SoundManager 2: Ready. ' + String.fromCharCode(10003),\r\n reset: sm + '.reset(): Removing event callbacks',\r\n mobileUA: 'Mobile UA detected, preferring HTML5 by default.',\r\n globalHTML5: 'Using singleton HTML5 Audio() pattern for this device.',\r\n ignoreMobile: 'Ignoring mobile restrictions for this device.'\r\n // </d>\r\n\r\n };\r\n\r\n str = function() {\r\n\r\n // internal string replace helper.\r\n // arguments: o [,items to replace]\r\n // <d>\r\n\r\n var args,\r\n i, j, o,\r\n sstr;\r\n\r\n // real array, please\r\n args = slice.call(arguments);\r\n\r\n // first argument\r\n o = args.shift();\r\n\r\n sstr = (strings && strings[o] ? strings[o] : '');\r\n\r\n if (sstr && args && args.length) {\r\n for (i = 0, j = args.length; i < j; i++) {\r\n sstr = sstr.replace('%s', args[i]);\r\n }\r\n }\r\n\r\n return sstr;\r\n // </d>\r\n\r\n };\r\n\r\n loopFix = function(sOpt) {\r\n\r\n // flash 8 requires stream = false for looping to work\r\n if (fV === 8 && sOpt.loops > 1 && sOpt.stream) {\r\n _wDS('as2loop');\r\n sOpt.stream = false;\r\n }\r\n\r\n return sOpt;\r\n\r\n };\r\n\r\n policyFix = function(sOpt, sPre) {\r\n\r\n if (sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) {\r\n sm2._wD((sPre || '') + str('policy'));\r\n sOpt.usePolicyFile = true;\r\n }\r\n\r\n return sOpt;\r\n\r\n };\r\n\r\n complain = function(sMsg) {\r\n\r\n // <d>\r\n if (hasConsole && console.warn !== _undefined) {\r\n console.warn(sMsg);\r\n } else {\r\n sm2._wD(sMsg);\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n doNothing = function() {\r\n\r\n return false;\r\n\r\n };\r\n\r\n disableObject = function(o) {\r\n\r\n var oProp;\r\n\r\n for (oProp in o) {\r\n if (o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') {\r\n o[oProp] = doNothing;\r\n }\r\n }\r\n\r\n oProp = null;\r\n\r\n };\r\n\r\n failSafely = function(bNoDisable) {\r\n\r\n // general failure exception handler\r\n\r\n if (bNoDisable === _undefined) {\r\n bNoDisable = false;\r\n }\r\n\r\n if (disabled || bNoDisable) {\r\n sm2.disable(bNoDisable);\r\n }\r\n\r\n };\r\n\r\n normalizeMovieURL = function(movieURL) {\r\n\r\n var urlParams = null, url;\r\n\r\n if (movieURL) {\r\n\r\n if (movieURL.match(/\\.swf(\\?.*)?$/i)) {\r\n\r\n urlParams = movieURL.substr(movieURL.toLowerCase().lastIndexOf('.swf?') + 4);\r\n\r\n // assume user knows what they're doing\r\n if (urlParams) return movieURL;\r\n\r\n } else if (movieURL.lastIndexOf('/') !== movieURL.length - 1) {\r\n\r\n // append trailing slash, if needed\r\n movieURL += '/';\r\n\r\n }\r\n\r\n }\r\n\r\n url = (movieURL && movieURL.lastIndexOf('/') !== -1 ? movieURL.substr(0, movieURL.lastIndexOf('/') + 1) : './') + sm2.movieURL;\r\n\r\n if (sm2.noSWFCache) {\r\n url += ('?ts=' + new Date().getTime());\r\n }\r\n\r\n return url;\r\n\r\n };\r\n\r\n setVersionInfo = function() {\r\n\r\n // short-hand for internal use\r\n\r\n fV = parseInt(sm2.flashVersion, 10);\r\n\r\n if (fV !== 8 && fV !== 9) {\r\n sm2._wD(str('badFV', fV, defaultFlashVersion));\r\n sm2.flashVersion = fV = defaultFlashVersion;\r\n }\r\n\r\n // debug flash movie, if applicable\r\n\r\n var isDebug = (sm2.debugMode || sm2.debugFlash ? '_debug.swf' : '.swf');\r\n\r\n if (sm2.useHTML5Audio && !sm2.html5Only && sm2.audioFormats.mp4.required && fV < 9) {\r\n sm2._wD(str('needfl9'));\r\n sm2.flashVersion = fV = 9;\r\n }\r\n\r\n sm2.version = sm2.versionNumber + (sm2.html5Only ? ' (HTML5-only mode)' : (fV === 9 ? ' (AS3/Flash 9)' : ' (AS2/Flash 8)'));\r\n\r\n // set up default options\r\n if (fV > 8) {\r\n\r\n // +flash 9 base options\r\n sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.flash9Options);\r\n sm2.features.buffering = true;\r\n\r\n // +moviestar support\r\n sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.movieStarOptions);\r\n sm2.filePatterns.flash9 = new RegExp('\\\\.(mp3|' + netStreamTypes.join('|') + ')(\\\\?.*)?$', 'i');\r\n sm2.features.movieStar = true;\r\n\r\n } else {\r\n\r\n sm2.features.movieStar = false;\r\n\r\n }\r\n\r\n // regExp for flash canPlay(), etc.\r\n sm2.filePattern = sm2.filePatterns[(fV !== 8 ? 'flash9' : 'flash8')];\r\n\r\n // if applicable, use _debug versions of SWFs\r\n sm2.movieURL = (fV === 8 ? 'soundmanager2.swf' : 'soundmanager2_flash9.swf').replace('.swf', isDebug);\r\n\r\n sm2.features.peakData = sm2.features.waveformData = sm2.features.eqData = (fV > 8);\r\n\r\n };\r\n\r\n setPolling = function(bPolling, bHighPerformance) {\r\n\r\n if (!flash) {\r\n return;\r\n }\r\n\r\n flash._setPolling(bPolling, bHighPerformance);\r\n\r\n };\r\n\r\n initDebug = function() {\r\n\r\n // starts debug mode, creating output <div> for UAs without console object\r\n\r\n // allow force of debug mode via URL\r\n // <d>\r\n if (sm2.debugURLParam.test(wl)) {\r\n sm2.setupOptions.debugMode = sm2.debugMode = true;\r\n }\r\n\r\n if (id(sm2.debugID)) {\r\n return;\r\n }\r\n\r\n var oD, oDebug, oTarget, oToggle, tmp;\r\n\r\n if (sm2.debugMode && !id(sm2.debugID) && (!hasConsole || !sm2.useConsole || !sm2.consoleOnly)) {\r\n\r\n oD = doc.createElement('div');\r\n oD.id = sm2.debugID + '-toggle';\r\n\r\n oToggle = {\r\n position: 'fixed',\r\n bottom: '0px',\r\n right: '0px',\r\n width: '1.2em',\r\n height: '1.2em',\r\n lineHeight: '1.2em',\r\n margin: '2px',\r\n textAlign: 'center',\r\n border: '1px solid #999',\r\n cursor: 'pointer',\r\n background: '#fff',\r\n color: '#333',\r\n zIndex: 10001\r\n };\r\n\r\n oD.appendChild(doc.createTextNode('-'));\r\n oD.onclick = toggleDebug;\r\n oD.title = 'Toggle SM2 debug console';\r\n\r\n if (ua.match(/msie 6/i)) {\r\n oD.style.position = 'absolute';\r\n oD.style.cursor = 'hand';\r\n }\r\n\r\n for (tmp in oToggle) {\r\n if (oToggle.hasOwnProperty(tmp)) {\r\n oD.style[tmp] = oToggle[tmp];\r\n }\r\n }\r\n\r\n oDebug = doc.createElement('div');\r\n oDebug.id = sm2.debugID;\r\n oDebug.style.display = (sm2.debugMode ? 'block' : 'none');\r\n\r\n if (sm2.debugMode && !id(oD.id)) {\r\n try {\r\n oTarget = getDocument();\r\n oTarget.appendChild(oD);\r\n } catch(e2) {\r\n throw new Error(str('domError') + ' \\n' + e2.toString());\r\n }\r\n oTarget.appendChild(oDebug);\r\n }\r\n\r\n }\r\n\r\n oTarget = null;\r\n // </d>\r\n\r\n };\r\n\r\n idCheck = this.getSoundById;\r\n\r\n // <d>\r\n _wDS = function(o, errorLevel) {\r\n\r\n return (!o ? '' : sm2._wD(str(o), errorLevel));\r\n\r\n };\r\n\r\n toggleDebug = function() {\r\n\r\n var o = id(sm2.debugID),\r\n oT = id(sm2.debugID + '-toggle');\r\n\r\n if (!o) {\r\n return;\r\n }\r\n\r\n if (debugOpen) {\r\n // minimize\r\n oT.innerHTML = '+';\r\n o.style.display = 'none';\r\n } else {\r\n oT.innerHTML = '-';\r\n o.style.display = 'block';\r\n }\r\n\r\n debugOpen = !debugOpen;\r\n\r\n };\r\n\r\n debugTS = function(sEventType, bSuccess, sMessage) {\r\n\r\n // troubleshooter debug hooks\r\n\r\n if (window.sm2Debugger !== _undefined) {\r\n try {\r\n sm2Debugger.handleEvent(sEventType, bSuccess, sMessage);\r\n } catch(e) {\r\n // oh well\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n\r\n };\r\n // </d>\r\n\r\n getSWFCSS = function() {\r\n\r\n var css = [];\r\n\r\n if (sm2.debugMode) {\r\n css.push(swfCSS.sm2Debug);\r\n }\r\n\r\n if (sm2.debugFlash) {\r\n css.push(swfCSS.flashDebug);\r\n }\r\n\r\n if (sm2.useHighPerformance) {\r\n css.push(swfCSS.highPerf);\r\n }\r\n\r\n return css.join(' ');\r\n\r\n };\r\n\r\n flashBlockHandler = function() {\r\n\r\n // *possible* flash block situation.\r\n\r\n var name = str('fbHandler'),\r\n p = sm2.getMoviePercent(),\r\n css = swfCSS,\r\n error = {\r\n type: 'FLASHBLOCK'\r\n };\r\n\r\n if (sm2.html5Only) {\r\n // no flash, or unused\r\n return;\r\n }\r\n\r\n if (!sm2.ok()) {\r\n\r\n if (needsFlash) {\r\n // make the movie more visible, so user can fix\r\n sm2.oMC.className = getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null ? css.swfTimedout : css.swfError);\r\n sm2._wD(name + ': ' + str('fbTimeout') + (p ? ' (' + str('fbLoaded') + ')' : ''));\r\n }\r\n\r\n sm2.didFlashBlock = true;\r\n\r\n // fire onready(), complain lightly\r\n processOnEvents({\r\n type: 'ontimeout',\r\n ignoreInit: true,\r\n error: error\r\n });\r\n\r\n catchError(error);\r\n\r\n } else {\r\n\r\n // SM2 loaded OK (or recovered)\r\n\r\n // <d>\r\n if (sm2.didFlashBlock) {\r\n sm2._wD(name + ': Unblocked');\r\n }\r\n // </d>\r\n\r\n if (sm2.oMC) {\r\n sm2.oMC.className = [getSWFCSS(), css.swfDefault, css.swfLoaded + (sm2.didFlashBlock ? ' ' + css.swfUnblocked : '')].join(' ');\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n addOnEvent = function(sType, oMethod, oScope) {\r\n\r\n if (on_queue[sType] === _undefined) {\r\n on_queue[sType] = [];\r\n }\r\n\r\n on_queue[sType].push({\r\n method: oMethod,\r\n scope: (oScope || null),\r\n fired: false\r\n });\r\n\r\n };\r\n\r\n processOnEvents = function(oOptions) {\r\n\r\n // if unspecified, assume OK/error\r\n\r\n if (!oOptions) {\r\n oOptions = {\r\n type: (sm2.ok() ? 'onready' : 'ontimeout')\r\n };\r\n }\r\n\r\n // not ready yet.\r\n if (!didInit && oOptions && !oOptions.ignoreInit) return false;\r\n\r\n // invalid case\r\n if (oOptions.type === 'ontimeout' && (sm2.ok() || (disabled && !oOptions.ignoreInit))) return false;\r\n\r\n var status = {\r\n success: (oOptions && oOptions.ignoreInit ? sm2.ok() : !disabled)\r\n },\r\n\r\n // queue specified by type, or none\r\n srcQueue = (oOptions && oOptions.type ? on_queue[oOptions.type] || [] : []),\r\n\r\n queue = [], i, j,\r\n args = [status],\r\n canRetry = (needsFlash && !sm2.ok());\r\n\r\n if (oOptions.error) {\r\n args[0].error = oOptions.error;\r\n }\r\n\r\n for (i = 0, j = srcQueue.length; i < j; i++) {\r\n if (srcQueue[i].fired !== true) {\r\n queue.push(srcQueue[i]);\r\n }\r\n }\r\n\r\n if (queue.length) {\r\n\r\n // sm2._wD(sm + ': Firing ' + queue.length + ' ' + oOptions.type + '() item' + (queue.length === 1 ? '' : 's'));\r\n for (i = 0, j = queue.length; i < j; i++) {\r\n\r\n if (queue[i].scope) {\r\n queue[i].method.apply(queue[i].scope, args);\r\n } else {\r\n queue[i].method.apply(this, args);\r\n }\r\n\r\n if (!canRetry) {\r\n // useFlashBlock and SWF timeout case doesn't count here.\r\n queue[i].fired = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n initUserOnload = function() {\r\n\r\n window.setTimeout(function() {\r\n\r\n if (sm2.useFlashBlock) {\r\n flashBlockHandler();\r\n }\r\n\r\n processOnEvents();\r\n\r\n // call user-defined \"onload\", scoped to window\r\n\r\n if (typeof sm2.onload === 'function') {\r\n _wDS('onload', 1);\r\n sm2.onload.apply(window);\r\n _wDS('onloadOK', 1);\r\n }\r\n\r\n if (sm2.waitForWindowLoad) {\r\n event.add(window, 'load', initUserOnload);\r\n }\r\n\r\n }, 1);\r\n\r\n };\r\n\r\n detectFlash = function() {\r\n\r\n /**\r\n * Hat tip: Flash Detect library (BSD, (C) 2007) by Carl \"DocYes\" S. Yestrau\r\n * http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt\r\n */\r\n\r\n // this work has already been done.\r\n if (hasFlash !== _undefined) return hasFlash;\r\n\r\n var hasPlugin = false, n = navigator, obj, type, types, AX = window.ActiveXObject;\r\n\r\n // MS Edge 14 throws an \"Unspecified Error\" because n.plugins is inaccessible due to permissions\r\n var nP;\r\n\r\n try {\r\n nP = n.plugins;\r\n } catch(e) {\r\n nP = undefined;\r\n }\r\n\r\n if (nP && nP.length) {\r\n\r\n type = 'application/x-shockwave-flash';\r\n types = n.mimeTypes;\r\n\r\n if (types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) {\r\n hasPlugin = true;\r\n }\r\n\r\n } else if (AX !== _undefined && !ua.match(/MSAppHost/i)) {\r\n\r\n // Windows 8 Store Apps (MSAppHost) are weird (compatibility?) and won't complain here, but will barf if Flash/ActiveX object is appended to the DOM.\r\n try {\r\n obj = new AX('ShockwaveFlash.ShockwaveFlash');\r\n } catch(e) {\r\n // oh well\r\n obj = null;\r\n }\r\n\r\n hasPlugin = (!!obj);\r\n\r\n // cleanup, because it is ActiveX after all\r\n obj = null;\r\n\r\n }\r\n\r\n hasFlash = hasPlugin;\r\n\r\n return hasPlugin;\r\n\r\n };\r\n\r\n featureCheck = function() {\r\n\r\n var flashNeeded,\r\n item,\r\n formats = sm2.audioFormats,\r\n // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (original iPad) + iOS4 works.\r\n isSpecial = (is_iDevice && !!(ua.match(/os (1|2|3_0|3_1)\\s/i)));\r\n\r\n if (isSpecial) {\r\n\r\n // has Audio(), but is broken; let it load links directly.\r\n sm2.hasHTML5 = false;\r\n\r\n // ignore flash case, however\r\n sm2.html5Only = true;\r\n\r\n // hide the SWF, if present\r\n if (sm2.oMC) {\r\n sm2.oMC.style.display = 'none';\r\n }\r\n\r\n } else if (sm2.useHTML5Audio) {\r\n\r\n if (!sm2.html5 || !sm2.html5.canPlayType) {\r\n sm2._wD('SoundManager: No HTML5 Audio() support detected.');\r\n sm2.hasHTML5 = false;\r\n }\r\n\r\n // <d>\r\n if (isBadSafari) {\r\n sm2._wD(smc + 'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - ' + (!hasFlash ? ' would use flash fallback for MP3/MP4, but none detected.' : 'will use flash fallback for MP3/MP4, if available'), 1);\r\n }\r\n // </d>\r\n\r\n }\r\n\r\n if (sm2.useHTML5Audio && sm2.hasHTML5) {\r\n\r\n // sort out whether flash is optional, required or can be ignored.\r\n\r\n // innocent until proven guilty.\r\n canIgnoreFlash = true;\r\n\r\n for (item in formats) {\r\n\r\n if (formats.hasOwnProperty(item)) {\r\n\r\n if (formats[item].required) {\r\n\r\n if (!sm2.html5.canPlayType(formats[item].type)) {\r\n\r\n // 100% HTML5 mode is not possible.\r\n canIgnoreFlash = false;\r\n flashNeeded = true;\r\n\r\n } else if (sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type])) {\r\n\r\n // flash may be required, or preferred for this format.\r\n flashNeeded = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n // sanity check...\r\n if (sm2.ignoreFlash) {\r\n flashNeeded = false;\r\n canIgnoreFlash = true;\r\n }\r\n\r\n sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !flashNeeded);\r\n\r\n return (!sm2.html5Only);\r\n\r\n };\r\n\r\n parseURL = function(url) {\r\n\r\n /**\r\n * Internal: Finds and returns the first playable URL (or failing that, the first URL.)\r\n * @param {string or array} url A single URL string, OR, an array of URL strings or {url:'/path/to/resource', type:'audio/mp3'} objects.\r\n */\r\n\r\n var i, j, urlResult = 0, result;\r\n\r\n if (url instanceof Array) {\r\n\r\n // find the first good one\r\n for (i = 0, j = url.length; i < j; i++) {\r\n\r\n if (url[i] instanceof Object) {\r\n\r\n // MIME check\r\n if (sm2.canPlayMIME(url[i].type)) {\r\n urlResult = i;\r\n break;\r\n }\r\n\r\n } else if (sm2.canPlayURL(url[i])) {\r\n\r\n // URL string check\r\n urlResult = i;\r\n break;\r\n\r\n }\r\n\r\n }\r\n\r\n // normalize to string\r\n if (url[urlResult].url) {\r\n url[urlResult] = url[urlResult].url;\r\n }\r\n\r\n result = url[urlResult];\r\n\r\n } else {\r\n\r\n // single URL case\r\n result = url;\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n\r\n startTimer = function(oSound) {\r\n\r\n /**\r\n * attach a timer to this sound, and start an interval if needed\r\n */\r\n\r\n if (!oSound._hasTimer) {\r\n\r\n oSound._hasTimer = true;\r\n\r\n if (!mobileHTML5 && sm2.html5PollingInterval) {\r\n\r\n if (h5IntervalTimer === null && h5TimerCount === 0) {\r\n\r\n h5IntervalTimer = setInterval(timerExecute, sm2.html5PollingInterval);\r\n\r\n }\r\n\r\n h5TimerCount++;\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n stopTimer = function(oSound) {\r\n\r\n /**\r\n * detach a timer\r\n */\r\n\r\n if (oSound._hasTimer) {\r\n\r\n oSound._hasTimer = false;\r\n\r\n if (!mobileHTML5 && sm2.html5PollingInterval) {\r\n\r\n // interval will stop itself at next execution.\r\n\r\n h5TimerCount--;\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n timerExecute = function() {\r\n\r\n /**\r\n * manual polling for HTML5 progress events, ie., whileplaying()\r\n * (can achieve greater precision than conservative default HTML5 interval)\r\n */\r\n\r\n var i;\r\n\r\n if (h5IntervalTimer !== null && !h5TimerCount) {\r\n\r\n // no active timers, stop polling interval.\r\n\r\n clearInterval(h5IntervalTimer);\r\n\r\n h5IntervalTimer = null;\r\n\r\n return;\r\n\r\n }\r\n\r\n // check all HTML5 sounds with timers\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n\r\n if (sm2.sounds[sm2.soundIDs[i]].isHTML5 && sm2.sounds[sm2.soundIDs[i]]._hasTimer) {\r\n sm2.sounds[sm2.soundIDs[i]]._onTimer();\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n catchError = function(options) {\r\n\r\n options = (options !== _undefined ? options : {});\r\n\r\n if (typeof sm2.onerror === 'function') {\r\n sm2.onerror.apply(window, [{\r\n type: (options.type !== _undefined ? options.type : null)\r\n }]);\r\n }\r\n\r\n if (options.fatal !== _undefined && options.fatal) {\r\n sm2.disable();\r\n }\r\n\r\n };\r\n\r\n badSafariFix = function() {\r\n\r\n // special case: \"bad\" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4\r\n if (!isBadSafari || !detectFlash()) {\r\n // doesn't apply\r\n return;\r\n }\r\n\r\n var aF = sm2.audioFormats, i, item;\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n if (item === 'mp3' || item === 'mp4') {\r\n\r\n sm2._wD(sm + ': Using flash fallback for ' + item + ' format');\r\n sm2.html5[item] = false;\r\n\r\n // assign result to related formats, too\r\n if (aF[item] && aF[item].related) {\r\n for (i = aF[item].related.length - 1; i >= 0; i--) {\r\n sm2.html5[aF[item].related[i]] = false;\r\n }\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Pseudo-private flash/ExternalInterface methods\r\n * ----------------------------------------------\r\n */\r\n\r\n this._setSandboxType = function(sandboxType) {\r\n\r\n // <d>\r\n // Security sandbox according to Flash plugin\r\n var sb = sm2.sandbox;\r\n\r\n sb.type = sandboxType;\r\n sb.description = sb.types[(sb.types[sandboxType] !== _undefined ? sandboxType : 'unknown')];\r\n\r\n if (sb.type === 'localWithFile') {\r\n\r\n sb.noRemote = true;\r\n sb.noLocal = false;\r\n _wDS('secNote', 2);\r\n\r\n } else if (sb.type === 'localWithNetwork') {\r\n\r\n sb.noRemote = false;\r\n sb.noLocal = true;\r\n\r\n } else if (sb.type === 'localTrusted') {\r\n\r\n sb.noRemote = false;\r\n sb.noLocal = false;\r\n\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n this._externalInterfaceOK = function(swfVersion) {\r\n\r\n // flash callback confirming flash loaded, EI working etc.\r\n // swfVersion: SWF build string\r\n\r\n if (sm2.swfLoaded) {\r\n return;\r\n }\r\n\r\n var e;\r\n\r\n debugTS('swf', true);\r\n debugTS('flashtojs', true);\r\n sm2.swfLoaded = true;\r\n tryInitOnFocus = false;\r\n\r\n if (isBadSafari) {\r\n badSafariFix();\r\n }\r\n\r\n // complain if JS + SWF build/version strings don't match, excluding +DEV builds\r\n // <d>\r\n if (!swfVersion || swfVersion.replace(/\\+dev/i, '') !== sm2.versionNumber.replace(/\\+dev/i, '')) {\r\n\r\n e = sm + ': Fatal: JavaScript file build \"' + sm2.versionNumber + '\" does not match Flash SWF build \"' + swfVersion + '\" at ' + sm2.url + '. Ensure both are up-to-date.';\r\n\r\n // escape flash -> JS stack so this error fires in window.\r\n setTimeout(function() {\r\n throw new Error(e);\r\n }, 0);\r\n\r\n // exit, init will fail with timeout\r\n return;\r\n\r\n }\r\n // </d>\r\n\r\n // IE needs a larger timeout\r\n setTimeout(init, isIE ? 100 : 1);\r\n\r\n };\r\n\r\n /**\r\n * Private initialization helpers\r\n * ------------------------------\r\n */\r\n\r\n createMovie = function(movieID, movieURL) {\r\n\r\n // ignore if already connected\r\n if (didAppend && appendSuccess) return false;\r\n\r\n function initMsg() {\r\n\r\n // <d>\r\n\r\n var options = [],\r\n title,\r\n msg = [],\r\n delimiter = ' + ';\r\n\r\n title = 'SoundManager ' + sm2.version + (!sm2.html5Only && sm2.useHTML5Audio ? (sm2.hasHTML5 ? ' + HTML5 audio' : ', no HTML5 audio support') : '');\r\n\r\n if (!sm2.html5Only) {\r\n\r\n if (sm2.preferFlash) {\r\n options.push('preferFlash');\r\n }\r\n\r\n if (sm2.useHighPerformance) {\r\n options.push('useHighPerformance');\r\n }\r\n\r\n if (sm2.flashPollingInterval) {\r\n options.push('flashPollingInterval (' + sm2.flashPollingInterval + 'ms)');\r\n }\r\n\r\n if (sm2.html5PollingInterval) {\r\n options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)');\r\n }\r\n\r\n if (sm2.wmode) {\r\n options.push('wmode (' + sm2.wmode + ')');\r\n }\r\n\r\n if (sm2.debugFlash) {\r\n options.push('debugFlash');\r\n }\r\n\r\n if (sm2.useFlashBlock) {\r\n options.push('flashBlock');\r\n }\r\n\r\n } else if (sm2.html5PollingInterval) {\r\n options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)');\r\n }\r\n\r\n if (options.length) {\r\n msg = msg.concat([options.join(delimiter)]);\r\n }\r\n\r\n sm2._wD(title + (msg.length ? delimiter + msg.join(', ') : ''), 1);\r\n\r\n showSupport();\r\n\r\n // </d>\r\n\r\n }\r\n\r\n if (sm2.html5Only) {\r\n\r\n // 100% HTML5 mode\r\n setVersionInfo();\r\n\r\n initMsg();\r\n sm2.oMC = id(sm2.movieID);\r\n init();\r\n\r\n // prevent multiple init attempts\r\n didAppend = true;\r\n\r\n appendSuccess = true;\r\n\r\n return false;\r\n\r\n }\r\n\r\n // flash path\r\n var remoteURL = (movieURL || sm2.url),\r\n localURL = (sm2.altURL || remoteURL),\r\n swfTitle = 'JS/Flash audio component (SoundManager 2)',\r\n oTarget = getDocument(),\r\n extraClass = getSWFCSS(),\r\n isRTL = null,\r\n html = doc.getElementsByTagName('html')[0],\r\n oEmbed, oMovie, tmp, movieHTML, oEl, s, x, sClass;\r\n\r\n isRTL = (html && html.dir && html.dir.match(/rtl/i));\r\n movieID = (movieID === _undefined ? sm2.id : movieID);\r\n\r\n function param(name, value) {\r\n return '<param name=\"' + name + '\" value=\"' + value + '\" />';\r\n }\r\n\r\n // safety check for legacy (change to Flash 9 URL)\r\n setVersionInfo();\r\n sm2.url = normalizeMovieURL(overHTTP ? remoteURL : localURL);\r\n movieURL = sm2.url;\r\n\r\n sm2.wmode = (!sm2.wmode && sm2.useHighPerformance ? 'transparent' : sm2.wmode);\r\n\r\n if (sm2.wmode !== null && (ua.match(/msie 8/i) || (!isIE && !sm2.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) {\r\n /**\r\n * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here\r\n * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout\r\n * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?)\r\n */\r\n messages.push(strings.spcWmode);\r\n sm2.wmode = null;\r\n }\r\n\r\n oEmbed = {\r\n name: movieID,\r\n id: movieID,\r\n src: movieURL,\r\n quality: 'high',\r\n allowScriptAccess: sm2.allowScriptAccess,\r\n bgcolor: sm2.bgColor,\r\n pluginspage: http + 'www.macromedia.com/go/getflashplayer',\r\n title: swfTitle,\r\n type: 'application/x-shockwave-flash',\r\n wmode: sm2.wmode,\r\n // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html\r\n hasPriority: 'true'\r\n };\r\n\r\n if (sm2.debugFlash) {\r\n oEmbed.FlashVars = 'debug=1';\r\n }\r\n\r\n if (!sm2.wmode) {\r\n // don't write empty attribute\r\n delete oEmbed.wmode;\r\n }\r\n\r\n if (isIE) {\r\n\r\n // IE is \"special\".\r\n oMovie = doc.createElement('div');\r\n movieHTML = [\r\n '<object id=\"' + movieID + '\" data=\"' + movieURL + '\" type=\"' + oEmbed.type + '\" title=\"' + oEmbed.title + '\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0\">',\r\n param('movie', movieURL),\r\n param('AllowScriptAccess', sm2.allowScriptAccess),\r\n param('quality', oEmbed.quality),\r\n (sm2.wmode ? param('wmode', sm2.wmode) : ''),\r\n param('bgcolor', sm2.bgColor),\r\n param('hasPriority', 'true'),\r\n (sm2.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''),\r\n '</object>'\r\n ].join('');\r\n\r\n } else {\r\n\r\n oMovie = doc.createElement('embed');\r\n for (tmp in oEmbed) {\r\n if (oEmbed.hasOwnProperty(tmp)) {\r\n oMovie.setAttribute(tmp, oEmbed[tmp]);\r\n }\r\n }\r\n\r\n }\r\n\r\n initDebug();\r\n extraClass = getSWFCSS();\r\n oTarget = getDocument();\r\n\r\n if (oTarget) {\r\n\r\n sm2.oMC = (id(sm2.movieID) || doc.createElement('div'));\r\n\r\n if (!sm2.oMC.id) {\r\n\r\n sm2.oMC.id = sm2.movieID;\r\n sm2.oMC.className = swfCSS.swfDefault + ' ' + extraClass;\r\n s = null;\r\n oEl = null;\r\n\r\n if (!sm2.useFlashBlock) {\r\n if (sm2.useHighPerformance) {\r\n // on-screen at all times\r\n s = {\r\n position: 'fixed',\r\n width: '8px',\r\n height: '8px',\r\n // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes.\r\n bottom: '0px',\r\n left: '0px',\r\n overflow: 'hidden'\r\n };\r\n } else {\r\n // hide off-screen, lower priority\r\n s = {\r\n position: 'absolute',\r\n width: '6px',\r\n height: '6px',\r\n top: '-9999px',\r\n left: '-9999px'\r\n };\r\n if (isRTL) {\r\n s.left = Math.abs(parseInt(s.left, 10)) + 'px';\r\n }\r\n }\r\n }\r\n\r\n if (isWebkit) {\r\n // soundcloud-reported render/crash fix, safari 5\r\n sm2.oMC.style.zIndex = 10000;\r\n }\r\n\r\n if (!sm2.debugFlash) {\r\n for (x in s) {\r\n if (s.hasOwnProperty(x)) {\r\n sm2.oMC.style[x] = s[x];\r\n }\r\n }\r\n }\r\n\r\n try {\r\n\r\n if (!isIE) {\r\n sm2.oMC.appendChild(oMovie);\r\n }\r\n\r\n oTarget.appendChild(sm2.oMC);\r\n\r\n if (isIE) {\r\n oEl = sm2.oMC.appendChild(doc.createElement('div'));\r\n oEl.className = swfCSS.swfBox;\r\n oEl.innerHTML = movieHTML;\r\n }\r\n\r\n appendSuccess = true;\r\n\r\n } catch(e) {\r\n\r\n throw new Error(str('domError') + ' \\n' + e.toString());\r\n\r\n }\r\n\r\n } else {\r\n\r\n // SM2 container is already in the document (eg. flashblock use case)\r\n sClass = sm2.oMC.className;\r\n sm2.oMC.className = (sClass ? sClass + ' ' : swfCSS.swfDefault) + (extraClass ? ' ' + extraClass : '');\r\n sm2.oMC.appendChild(oMovie);\r\n\r\n if (isIE) {\r\n oEl = sm2.oMC.appendChild(doc.createElement('div'));\r\n oEl.className = swfCSS.swfBox;\r\n oEl.innerHTML = movieHTML;\r\n }\r\n\r\n appendSuccess = true;\r\n\r\n }\r\n\r\n }\r\n\r\n didAppend = true;\r\n\r\n initMsg();\r\n\r\n // sm2._wD(sm + ': Trying to load ' + movieURL + (!overHTTP && sm2.altURL ? ' (alternate URL)' : ''), 1);\r\n\r\n return true;\r\n\r\n };\r\n\r\n initMovie = function() {\r\n\r\n if (sm2.html5Only) {\r\n createMovie();\r\n return false;\r\n }\r\n\r\n // attempt to get, or create, movie (may already exist)\r\n if (flash) return false;\r\n\r\n if (!sm2.url) {\r\n\r\n /**\r\n * Something isn't right - we've reached init, but the soundManager url property has not been set.\r\n * User has not called setup({url: ...}), or has not set soundManager.url (legacy use case) directly before init time.\r\n * Notify and exit. If user calls setup() with a url: property, init will be restarted as in the deferred loading case.\r\n */\r\n\r\n _wDS('noURL');\r\n return false;\r\n\r\n }\r\n\r\n // inline markup case\r\n flash = sm2.getMovie(sm2.id);\r\n\r\n if (!flash) {\r\n\r\n if (!oRemoved) {\r\n\r\n // try to create\r\n createMovie(sm2.id, sm2.url);\r\n\r\n } else {\r\n\r\n // try to re-append removed movie after reboot()\r\n if (!isIE) {\r\n sm2.oMC.appendChild(oRemoved);\r\n } else {\r\n sm2.oMC.innerHTML = oRemovedHTML;\r\n }\r\n\r\n oRemoved = null;\r\n didAppend = true;\r\n\r\n }\r\n\r\n flash = sm2.getMovie(sm2.id);\r\n\r\n }\r\n\r\n if (typeof sm2.oninitmovie === 'function') {\r\n setTimeout(sm2.oninitmovie, 1);\r\n }\r\n\r\n // <d>\r\n flushMessages();\r\n // </d>\r\n\r\n return true;\r\n\r\n };\r\n\r\n delayWaitForEI = function() {\r\n\r\n setTimeout(waitForEI, 1000);\r\n\r\n };\r\n\r\n rebootIntoHTML5 = function() {\r\n\r\n // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled.\r\n\r\n window.setTimeout(function() {\r\n\r\n complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...');\r\n\r\n sm2.setup({\r\n preferFlash: false\r\n }).reboot();\r\n\r\n // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true.\r\n sm2.didFlashBlock = true;\r\n\r\n sm2.beginDelayedInit();\r\n\r\n }, 1);\r\n\r\n };\r\n\r\n waitForEI = function() {\r\n\r\n var p,\r\n loadIncomplete = false;\r\n\r\n if (!sm2.url) {\r\n // No SWF url to load (noURL case) - exit for now. Will be retried when url is set.\r\n return;\r\n }\r\n\r\n if (waitingForEI) {\r\n return;\r\n }\r\n\r\n waitingForEI = true;\r\n event.remove(window, 'load', delayWaitForEI);\r\n\r\n if (hasFlash && tryInitOnFocus && !isFocused) {\r\n // Safari won't load flash in background tabs, only when focused.\r\n _wDS('waitFocus');\r\n return;\r\n }\r\n\r\n if (!didInit) {\r\n p = sm2.getMoviePercent();\r\n if (p > 0 && p < 100) {\r\n loadIncomplete = true;\r\n }\r\n }\r\n\r\n setTimeout(function() {\r\n\r\n p = sm2.getMoviePercent();\r\n\r\n if (loadIncomplete) {\r\n // special case: if movie *partially* loaded, retry until it's 100% before assuming failure.\r\n waitingForEI = false;\r\n sm2._wD(str('waitSWF'));\r\n window.setTimeout(delayWaitForEI, 1);\r\n return;\r\n }\r\n\r\n // <d>\r\n if (!didInit) {\r\n\r\n sm2._wD(sm + ': No Flash response within expected time. Likely causes: ' + (p === 0 ? 'SWF load failed, ' : '') + 'Flash blocked or JS-Flash security error.' + (sm2.debugFlash ? ' ' + str('checkSWF') : ''), 2);\r\n\r\n if (!overHTTP && p) {\r\n\r\n _wDS('localFail', 2);\r\n\r\n if (!sm2.debugFlash) {\r\n _wDS('tryDebug', 2);\r\n }\r\n\r\n }\r\n\r\n if (p === 0) {\r\n\r\n // if 0 (not null), probably a 404.\r\n sm2._wD(str('swf404', sm2.url), 1);\r\n\r\n }\r\n\r\n debugTS('flashtojs', false, ': Timed out' + (overHTTP ? ' (Check flash security or flash blockers)' : ' (No plugin/missing SWF?)'));\r\n\r\n }\r\n // </d>\r\n\r\n // give up / time-out, depending\r\n\r\n if (!didInit && okToDisable) {\r\n\r\n if (p === null) {\r\n\r\n // SWF failed to report load progress. Possibly blocked.\r\n\r\n if (sm2.useFlashBlock || sm2.flashLoadTimeout === 0) {\r\n\r\n if (sm2.useFlashBlock) {\r\n\r\n flashBlockHandler();\r\n\r\n }\r\n\r\n _wDS('waitForever');\r\n\r\n } else if (!sm2.useFlashBlock && canIgnoreFlash) {\r\n\r\n // no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load.\r\n rebootIntoHTML5();\r\n\r\n } else {\r\n\r\n _wDS('waitForever');\r\n\r\n // fire any regular registered ontimeout() listeners.\r\n processOnEvents({\r\n type: 'ontimeout',\r\n ignoreInit: true,\r\n error: {\r\n type: 'INIT_FLASHBLOCK'\r\n }\r\n });\r\n\r\n }\r\n\r\n } else if (sm2.flashLoadTimeout === 0) {\r\n\r\n // SWF loaded? Shouldn't be a blocking issue, then.\r\n\r\n _wDS('waitForever');\r\n\r\n } else if (!sm2.useFlashBlock && canIgnoreFlash) {\r\n\r\n rebootIntoHTML5();\r\n\r\n } else {\r\n\r\n failSafely(true);\r\n\r\n }\r\n\r\n }\r\n\r\n }, sm2.flashLoadTimeout);\r\n\r\n };\r\n\r\n handleFocus = function() {\r\n\r\n function cleanup() {\r\n event.remove(window, 'focus', handleFocus);\r\n }\r\n\r\n if (isFocused || !tryInitOnFocus) {\r\n // already focused, or not special Safari background tab case\r\n cleanup();\r\n return true;\r\n }\r\n\r\n okToDisable = true;\r\n isFocused = true;\r\n _wDS('gotFocus');\r\n\r\n // allow init to restart\r\n waitingForEI = false;\r\n\r\n // kick off ExternalInterface timeout, now that the SWF has started\r\n delayWaitForEI();\r\n\r\n cleanup();\r\n return true;\r\n\r\n };\r\n\r\n flushMessages = function() {\r\n\r\n // <d>\r\n\r\n // SM2 pre-init debug messages\r\n if (messages.length) {\r\n sm2._wD('SoundManager 2: ' + messages.join(' '), 1);\r\n messages = [];\r\n }\r\n\r\n // </d>\r\n\r\n };\r\n\r\n showSupport = function() {\r\n\r\n // <d>\r\n\r\n flushMessages();\r\n\r\n var item, tests = [];\r\n\r\n if (sm2.useHTML5Audio && sm2.hasHTML5) {\r\n for (item in sm2.audioFormats) {\r\n if (sm2.audioFormats.hasOwnProperty(item)) {\r\n tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && needsFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && needsFlash ? ' (preferring flash)' : (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ' : '') + 'and no flash support)' : ''))));\r\n }\r\n }\r\n sm2._wD('SoundManager 2 HTML5 support: ' + tests.join(', '), 1);\r\n }\r\n\r\n // </d>\r\n\r\n };\r\n\r\n initComplete = function(bNoDisable) {\r\n\r\n if (didInit) return false;\r\n\r\n if (sm2.html5Only) {\r\n // all good.\r\n _wDS('sm2Loaded', 1);\r\n didInit = true;\r\n initUserOnload();\r\n debugTS('onload', true);\r\n return true;\r\n }\r\n\r\n var wasTimeout = (sm2.useFlashBlock && sm2.flashLoadTimeout && !sm2.getMoviePercent()),\r\n result = true,\r\n error;\r\n\r\n if (!wasTimeout) {\r\n didInit = true;\r\n }\r\n\r\n error = {\r\n type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')\r\n };\r\n\r\n sm2._wD('SoundManager 2 ' + (disabled ? 'failed to load' : 'loaded') + ' (' + (disabled ? 'Flash security/load error' : 'OK') + ') ' + String.fromCharCode(disabled ? 10006 : 10003), disabled ? 2 : 1);\r\n\r\n if (disabled || bNoDisable) {\r\n\r\n if (sm2.useFlashBlock && sm2.oMC) {\r\n sm2.oMC.className = getSWFCSS() + ' ' + (sm2.getMoviePercent() === null ? swfCSS.swfTimedout : swfCSS.swfError);\r\n }\r\n\r\n processOnEvents({\r\n type: 'ontimeout',\r\n error: error,\r\n ignoreInit: true\r\n });\r\n\r\n debugTS('onload', false);\r\n catchError(error);\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n debugTS('onload', true);\r\n\r\n }\r\n\r\n if (!disabled) {\r\n\r\n if (sm2.waitForWindowLoad && !windowLoaded) {\r\n\r\n _wDS('waitOnload');\r\n event.add(window, 'load', initUserOnload);\r\n\r\n } else {\r\n\r\n // <d>\r\n if (sm2.waitForWindowLoad && windowLoaded) {\r\n _wDS('docLoaded');\r\n }\r\n // </d>\r\n\r\n initUserOnload();\r\n\r\n }\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * apply top-level setupOptions object as local properties, eg., this.setupOptions.flashVersion -> this.flashVersion (soundManager.flashVersion)\r\n * this maintains backward compatibility, and allows properties to be defined separately for use by soundManager.setup().\r\n */\r\n\r\n setProperties = function() {\r\n\r\n var i,\r\n o = sm2.setupOptions;\r\n\r\n for (i in o) {\r\n\r\n if (o.hasOwnProperty(i)) {\r\n\r\n // assign local property if not already defined\r\n\r\n if (sm2[i] === _undefined) {\r\n\r\n sm2[i] = o[i];\r\n\r\n } else if (sm2[i] !== o[i]) {\r\n\r\n // legacy support: write manually-assigned property (eg., soundManager.url) back to setupOptions to keep things in sync\r\n sm2.setupOptions[i] = sm2[i];\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n\r\n init = function() {\r\n\r\n // called after onload()\r\n\r\n if (didInit) {\r\n _wDS('didInit');\r\n return false;\r\n }\r\n\r\n function cleanup() {\r\n event.remove(window, 'load', sm2.beginDelayedInit);\r\n }\r\n\r\n if (sm2.html5Only) {\r\n\r\n if (!didInit) {\r\n // we don't need no steenking flash!\r\n cleanup();\r\n sm2.enabled = true;\r\n initComplete();\r\n }\r\n\r\n return true;\r\n\r\n }\r\n\r\n // flash path\r\n initMovie();\r\n\r\n try {\r\n\r\n // attempt to talk to Flash\r\n flash._externalInterfaceTest(false);\r\n\r\n /**\r\n * Apply user-specified polling interval, OR, if \"high performance\" set, faster vs. default polling\r\n * (determines frequency of whileloading/whileplaying callbacks, effectively driving UI framerates)\r\n */\r\n setPolling(true, (sm2.flashPollingInterval || (sm2.useHighPerformance ? 10 : 50)));\r\n\r\n if (!sm2.debugMode) {\r\n // stop the SWF from making debug output calls to JS\r\n flash._disableDebug();\r\n }\r\n\r\n sm2.enabled = true;\r\n debugTS('jstoflash', true);\r\n\r\n if (!sm2.html5Only) {\r\n // prevent browser from showing cached page state (or rather, restoring \"suspended\" page state) via back button, because flash may be dead\r\n // http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/\r\n event.add(window, 'unload', doNothing);\r\n }\r\n\r\n } catch(e) {\r\n\r\n sm2._wD('js/flash exception: ' + e.toString());\r\n\r\n debugTS('jstoflash', false);\r\n\r\n catchError({\r\n type: 'JS_TO_FLASH_EXCEPTION',\r\n fatal: true\r\n });\r\n\r\n // don't disable, for reboot()\r\n failSafely(true);\r\n\r\n initComplete();\r\n\r\n return false;\r\n\r\n }\r\n\r\n initComplete();\r\n\r\n // disconnect events\r\n cleanup();\r\n\r\n return true;\r\n\r\n };\r\n\r\n domContentLoaded = function() {\r\n\r\n if (didDCLoaded) return false;\r\n\r\n didDCLoaded = true;\r\n\r\n // assign top-level soundManager properties eg. soundManager.url\r\n setProperties();\r\n\r\n initDebug();\r\n\r\n if (!hasFlash && sm2.hasHTML5) {\r\n\r\n sm2._wD('SoundManager 2: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1);\r\n\r\n sm2.setup({\r\n useHTML5Audio: true,\r\n // make sure we aren't preferring flash, either\r\n // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak.\r\n preferFlash: false\r\n });\r\n\r\n }\r\n\r\n testHTML5();\r\n\r\n if (!hasFlash && needsFlash) {\r\n\r\n messages.push(strings.needFlash);\r\n\r\n // TODO: Fatal here vs. timeout approach, etc.\r\n // hack: fail sooner.\r\n sm2.setup({\r\n flashLoadTimeout: 1\r\n });\r\n\r\n }\r\n\r\n if (doc.removeEventListener) {\r\n doc.removeEventListener('DOMContentLoaded', domContentLoaded, false);\r\n }\r\n\r\n initMovie();\r\n\r\n return true;\r\n\r\n };\r\n\r\n domContentLoadedIE = function() {\r\n\r\n if (doc.readyState === 'complete') {\r\n domContentLoaded();\r\n doc.detachEvent('onreadystatechange', domContentLoadedIE);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n winOnLoad = function() {\r\n\r\n // catch edge case of initComplete() firing after window.load()\r\n windowLoaded = true;\r\n\r\n // catch case where DOMContentLoaded has been sent, but we're still in doc.readyState = 'interactive'\r\n domContentLoaded();\r\n\r\n event.remove(window, 'load', winOnLoad);\r\n\r\n };\r\n\r\n // sniff up-front\r\n detectFlash();\r\n\r\n // focus and window load, init (primarily flash-driven)\r\n event.add(window, 'focus', handleFocus);\r\n event.add(window, 'load', delayWaitForEI);\r\n event.add(window, 'load', winOnLoad);\r\n\r\n if (doc.addEventListener) {\r\n\r\n doc.addEventListener('DOMContentLoaded', domContentLoaded, false);\r\n\r\n } else if (doc.attachEvent) {\r\n\r\n doc.attachEvent('onreadystatechange', domContentLoadedIE);\r\n\r\n } else {\r\n\r\n // no add/attachevent support - safe to assume no JS -> Flash either\r\n debugTS('onload', false);\r\n catchError({\r\n type: 'NO_DOM2_EVENTS',\r\n fatal: true\r\n });\r\n\r\n }\r\n\r\n} // SoundManager()\r\n\r\n// SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading\r\n\r\nif (window.SM2_DEFER === _undefined || !SM2_DEFER) {\r\n soundManager = new SoundManager();\r\n}\r\n\r\n/**\r\n * SoundManager public interfaces\r\n * ------------------------------\r\n */\r\n\r\nif (typeof module === 'object' && module && typeof module.exports === 'object') {\r\n\r\n /**\r\n * commonJS module\r\n */\r\n\r\n module.exports.SoundManager = SoundManager;\r\n module.exports.soundManager = soundManager;\r\n\r\n} else if (typeof define === 'function' && define.amd) {\r\n\r\n /**\r\n * AMD - requireJS\r\n * basic usage:\r\n * require([\"/path/to/soundmanager2.js\"], function(SoundManager) {\r\n * SoundManager.getInstance().setup({\r\n * url: '/swf/',\r\n * onready: function() { ... }\r\n * })\r\n * });\r\n *\r\n * SM2_DEFER usage:\r\n * window.SM2_DEFER = true;\r\n * require([\"/path/to/soundmanager2.js\"], function(SoundManager) {\r\n * SoundManager.getInstance(function() {\r\n * var soundManager = new SoundManager.constructor();\r\n * soundManager.setup({\r\n * url: '/swf/',\r\n * ...\r\n * });\r\n * ...\r\n * soundManager.beginDelayedInit();\r\n * return soundManager;\r\n * })\r\n * });\r\n */\r\n\r\n define(function() {\r\n /**\r\n * Retrieve the global instance of SoundManager.\r\n * If a global instance does not exist it can be created using a callback.\r\n *\r\n * @param {Function} smBuilder Optional: Callback used to create a new SoundManager instance\r\n * @return {SoundManager} The global SoundManager instance\r\n */\r\n function getInstance(smBuilder) {\r\n if (!window.soundManager && smBuilder instanceof Function) {\r\n var instance = smBuilder(SoundManager);\r\n if (instance instanceof SoundManager) {\r\n window.soundManager = instance;\r\n }\r\n }\r\n return window.soundManager;\r\n }\r\n return {\r\n constructor: SoundManager,\r\n getInstance: getInstance\r\n };\r\n });\r\n\r\n}\r\n\r\n// standard browser case\r\n\r\n// constructor\r\nwindow.SoundManager = SoundManager;\r\n\r\n/**\r\n * note: SM2 requires a window global due to Flash, which makes calls to window.soundManager.\r\n * Flash may not always be needed, but this is not known until async init and SM2 may even \"reboot\" into Flash mode.\r\n */\r\n\r\n// public API, flash callbacks etc.\r\nwindow.soundManager = soundManager;\r\n\r\n}(window));\r\n"],"names":["PageChunk","leafIndex","chunkIndex","text","lineRects","this","server","bookPath","$","ajax","type","url","dataType","cache","data","path","page","chunks","_fromTextWrapperResponse","chunksResponse","map","c","i","correctedLineRects","_fixChunkRects","slice","correctedText","_removeDanglingHyphens","rects","length","firstRect","secondRect","left","bottom","width","secondHeight","secondWidth","secondRight","replace","PageChunkIterator","pageCount","start","opts","Object","assign","DEFAULT_OPTS","_cursor","chunk","_bufferedPages","_bufferingPages","_cursorLock","Promise","resolve","then","_nextUncontrolled","_decrementUncontrolled","AT_END","_recenterBuffer","_fetchPageChunks","cursorChangePromise","prevPageChunks","index","Math","max","pageBufferSize","end","min","_removePageFromBuffer","_fetchPageChunksDirect","fetch","AbstractTTSEngine","options","voice","getBestBookVoice","getVoices","bookLanguage","playing","paused","_chunkIterator","activeSound","playbackRate","events","on","updateBestVoice","trigger","Error","voices","userLanguages","navigator","languages","bookLangVoices","filter","v","lang","startsWith","matchingUserLangs","language","getMatchingVoice","find","default","matchingVoices","numLeafs","onLoadingStart","step","stop","fireEvent","pause","resume","finish","all","decrement","voiceURI","off","setVoice","newRate","setPlaybackRate","next","onDone","sound","createSound","rate","load","onLoadingComplete","beforeChunkPlay","playSound","afterChunkPlay","playPromise","loaded","play","FestivalTTSEngine","audioFormat","browser","mozilla","localService","name","soundManager","setup","debugMode","preferFlash","useHTML5Audio","flashVersion","promise","userAgent","match","iOSCaptureUserIntentHack","FestivalTTSSound","getSoundUrl","dataString","encodeURIComponent","SILENCE_1MS","res","onfinish","destruct","supported","soundUrl","_finishResolver","onload","onresume","sleep","mp3","ogg","promisifyEvent","target","eventType","addEventListener","resolver","ev","removeEventListener","isAndroid","test","COLUMN_TO_LANG_INDEX","searchForISO6391","columnsToSearch","langs","colI","column","split","x","toLowerCase","indexOf","super_","WebTTSEngine","speechSynthesis","audio","Audio","SILENCE_6S_MP3","loop","src","mediaSession","metadata","MediaMetadata","title","br","bookTitle","artist","m","label","value","artwork","thumbnail","setActionHandler","jumpBackward","jumpForward","WebTTSSound","window","started","stopped","utterance","_lastEvents","boundary","_charIndex","_finishPromise","SpeechSynthesisUtterance","location","toString","console","log","dispatchEvent","CustomEvent","wasPaused","recentEvent","charIndex","cancel","speak","isLocalVoice","isChrome","_chromePausingBugFix","endPromise","race","Event","pausePromise","pauseMightNotWork","isFirefox","timeoutPromise","resumeMightNotWork","resumeMightNotFire","resumePromise","reload","result","en","jQuery","extend","BookReader","defaultOptions","enableTtsPlugin","prototype","call","_ttsBoxesByIndex","TTSEngine","isSupported","engineName","festival","web","ttsEngine","showProgressPopup","bind","removeProgressPopup","ttsStop","ttsBeforeChunkPlay","ttsSendChunkFinishedAnalyticsEvent","init","eventNames","PostInit","click","ttsToggle","ttsStart","_createPageContainer","pageContainer","pageIndex","renderBoxesInPageContainerLayer","$container","buildMobileDrawerElement","$el","after","imagesBaseURL","initNavbar","refs","$BRReadAloudToolbar","prepend","renderVoiceOption","join","voiceSortOrder","a","b","localeCompare","renderVoicesMenu","voicesMenu","empty","bookLanguages","sort","otherLanguages","append","val","show","hide","ttsUpdateState","ttsPlayPause","ttsJumpForward","ttsJumpBackward","$rateSelector","parseFloat","tooltips","insertBefore","closest","autoStop","startTTSEngine","constModeThumb","mode","switchMode","constMode1up","addClass","ttsSendAnalyticsEvent","currentIndex","getNumLeafs","isPlaying","toggleClass","togglePlayPause","removeClass","ttsRemoveHilites","ttsMaybeFlipToIndex","ttsHighlightChunk","ttsScrollToChunk","in2PageMode","constMode2up","twoPage","currentIndexR","currentIndexL","animationFinishedCallback","jumpToIndex","l","r","t","pageIndexString","boxes","_models","book","getPage","getActivePageContainerElementsForIndex","forEach","container","entries","last","scrollIntoView","block","isFullscreenActive","inline","behavior","getActivePageContainerElements","remove","action","archiveAnalyticsSendEvent","extraValues","mediaLanguage","vendor","isSafari","global","fails","uncurryThis","trim","whitespaces","charAt","n$ParseFloat","Symbol","ITERATOR","iterator","FORCED","module","exports","string","trimmedString","$entries","stat","O","$parseFloat","forced","fixRegExpWellKnownSymbolLogic","anObject","toLength","requireObjectCoercible","getMethod","advanceStringIndex","regExpExec","MATCH","nativeMatch","maybeCallNative","regexp","matcher","undefined","RegExp","rx","S","done","fullUnicode","unicode","lastIndex","A","n","matchStr","uaMatch","ua","exec","platform_match","matched","version","versionNumber","platform","parseInt","android","bb","blackberry","ipad","iphone","ipod","kindle","playbook","silk","mobile","cros","mac","linux","win","desktop","chrome","opr","safari","webkit","rv","iemobile","ie","edge","msedge","opera","jQBrowser","factory","_undefined","document","SoundManager","smURL","smID","setupOptions","debugFlash","useConsole","consoleOnly","waitForWindowLoad","bgColor","useHighPerformance","flashPollingInterval","html5PollingInterval","flashLoadTimeout","wmode","allowScriptAccess","useFlashBlock","forceUseGlobalHTML5Audio","ignoreMobileRestrictions","html5Test","noSWFCache","idPrefix","autoLoad","autoPlay","from","loops","onid3","onerror","whileloading","onplay","onpause","whileplaying","onposition","onstop","multiShot","multiShotEvents","position","pan","stream","to","usePolicyFile","volume","flash9Options","onfailure","isMovieStar","usePeakData","useWaveformData","useEQData","onbufferchange","ondataerror","movieStarOptions","bufferTime","serverURL","onconnect","duration","audioFormats","required","mp4","related","opus","wav","flac","movieID","id","debugID","debugURLParam","movieURL","altURL","swfLoaded","enabled","oMC","sounds","soundIDs","muted","didFlashBlock","filePattern","filePatterns","flash8","flash9","features","buffering","peakData","waveformData","eqData","movieStar","sandbox","types","remote","localWithFile","localWithNetwork","localTrusted","description","noRemote","noLocal","html5","usingFlash","flash","html5Only","ignoreFlash","SMSound","doNothing","setProperties","fV","debugTS","_wDS","initComplete","mixin","extraOptions","addOnEvent","processOnEvents","initUserOnload","delayWaitForEI","waitForEI","rebootIntoHTML5","setVersionInfo","handleFocus","strings","initMovie","domContentLoaded","winOnLoad","didDCLoaded","getDocument","createMovie","catchError","setPolling","initDebug","disableObject","failSafely","normalizeMovieURL","str","flashBlockHandler","getSWFCSS","swfCSS","toggleDebug","loopFix","policyFix","complain","idCheck","startTimer","stopTimer","timerExecute","parseURL","canIgnoreFlash","featureCheck","html5OK","html5CanPlay","html5ErrorCodes","html5Ext","html5Unload","domContentLoadedIE","testHTML5","event","lastGlobalHTML5URL","hasFlash","detectFlash","badSafariFix","html5_events","showSupport","flushMessages","wrapCallback","didSetup","sm2","globalHTML5Audio","sm","smc","wl","href","doc","on_queue","debugOpen","didAppend","appendSuccess","didInit","disabled","windowLoaded","wdCount","debugLevels","oRemoved","oRemovedHTML","waitingForEI","initPending","h5TimerCount","h5IntervalTimer","messages","needsFlash","Array","useGlobalHTML5Audio","idCounter","msecScale","is_iDevice","isIE","isWebkit","isOpera","mobileHTML5","isBadSafari","hasConsole","isFocused","hasFocus","tryInitOnFocus","okToDisable","flashMIME","emptyURL","overHTTP","protocol","http","netStreamMimeTypes","netStreamTypes","netStreamPattern","preferFlashCheck","kind","html5_event","oFn","e","s","_s","_a","_wD","h5","mimePattern","useAltURL","swfBox","swfDefault","swfError","swfTimedout","swfUnblocked","sm2Debug","highPerf","flashDebug","hasHTML5","canPlayType","noURL","ok","push","globalHTML5","ignoreMobile","mobileUA","beginDelayedInit","readyState","setTimeout","getMovie","movie_id","oOptions","_url","cs","cs_string","oSound","make","_setup_html5","_createSound","connected","apply","destroySound","sID","_bFromSound","oS","_iO","unload","splice","onPosition","nPosition","oMethod","oScope","clearOnPosition","overloaded","allowOverride","setPosition","nMsecOffset","stopAll","hasOwnProperty","pauseAll","resumeAll","togglePause","setPan","nPan","setVolume","nVol","j","isNaN","mute","String","muteAll","unmute","unmuteAll","toggleMute","getMemoryUse","ram","_getMemoryUse","disable","bNoDisable","canPlayMIME","sMIME","canPlayURL","sURL","canPlayLink","oLink","getSoundById","_suppressDebug","onready","sType","ontimeout","_writeDebug","sText","sTypeOrObject","o","oItem","createElement","className","appendChild","createTextNode","style","fontWeight","color","firstChild","alert","_debug","reboot","resetEvents","excludeInit","k","innerHTML","parentNode","removeChild","fired","reset","getMoviePercent","PercentLoaded","resetProperties","add_html5_events","remove_html5_events","stop_html5_timer","start_html5_timer","attachOnPosition","detachOnPosition","applyFromTo","lastHTML5State","urlOmitted","onplay_called","onPositionItems","onPositionFired","lastURL","time","instanceOptions","isHTML5","id3","playState","_called_load","_html5_canplay","autobuffer","preload","_load","fatal","_unload","_bFromSM","_destroySound","_updatePlayState","fN","audioClone","onended","oncanplay","startOK","getAutoPlay","setAutoPlay","substr","lastIndexOf","instanceCount","_oncanplay","_onfinish","currentTime","err","add","_start","onplayerror","bAll","originalPosition","_onbufferchange","_resetOnPosition","_onTimer","_stop","_setAutoPlay","normalizedRate","message","position1K","offset","toFixed","_setPosition","_bCallFlash","_pause","bInstanceOnly","_setPan","_bInstanceOnly","_setVolume","hasIO","method","scope","_processOnPosition","item","f","op","retainPosition","_hasTimer","bytesLoaded","bytesTotal","durationEstimate","buffered","right","failures","isBuffering","bForce","isNew","_get_html5_duration","_whileplaying","d","Infinity","_apply_loop","nLoops","sameURL","dURL","decodeURI","_added_events","oEvt","_onload","nSuccess","loadOK","_onerror","errorCode","nIsBuffering","_onsuspend","onsuspend","_onfailure","msg","level","code","_onwarning","onwarning","io_onfinish","_whileloading","nBytesLoaded","nBytesTotal","nDuration","nBufferLength","floor","bufferLength","oPeakData","oWaveformDataLeft","oWaveformDataRight","oEQData","eqLeft","leftPeak","rightPeak","leftEQ","rightEQ","_oncaptiondata","oData","captiondata","oncaptiondata","_onmetadata","oMDProps","oMDData","onmetadata","_onid3","oID3Props","oID3Data","_onconnect","bSuccess","_ondataerror","sError","body","getElementsByTagName","getElementById","oMain","oAdd","o2","o1","callback","oParent","hasParent","bonusOptions","Function","old","evt","getArgs","oArgs","args","len","pop","element","shift","arguments","abort","canplay","ee","canplaythrough","durationchange","ended","error","loadeddata","_loaded","loadedmetadata","loadstart","fromCharCode","progress","progStr","isProgress","ranges","total","ratechange","suspend","stalled","timeupdate","waiting","iO","oAudio","_called_unload","fileExt","mime","aF","concat","lookup","support","cp","canPlay","isOK","notReady","notOK","domError","spcWmode","swf404","tryDebug","checkSWF","localFail","waitFocus","waitForever","waitSWF","needFunction","badID","currentObj","waitOnload","docLoaded","onloadOK","secNote","badRemove","shutdown","queue","smError","fbTimeout","fbLoaded","fbHandler","manURL","onURL","badFV","as2loop","noNSLoop","needfl9","mfTimeout","needFlash","gotFocus","policy","setupError","setupUndef","setupLate","sm2Loaded","sstr","sOpt","sPre","sMsg","warn","oProp","Date","getTime","isDebug","bPolling","bHighPerformance","_setPolling","oD","oDebug","oTarget","oToggle","tmp","height","lineHeight","margin","textAlign","border","cursor","background","zIndex","onclick","display","e2","errorLevel","oT","sEventType","sMessage","sm2Debugger","handleEvent","css","p","ignoreInit","status","success","srcQueue","canRetry","obj","nP","hasPlugin","AX","ActiveXObject","plugins","mimeTypes","enabledPlugin","flashNeeded","formats","urlResult","setInterval","clearInterval","_setSandboxType","sandboxType","sb","_externalInterfaceOK","swfVersion","initMsg","isRTL","oEmbed","oMovie","movieHTML","oEl","sClass","remoteURL","localURL","extraClass","html","param","dir","quality","bgcolor","pluginspage","hasPriority","FlashVars","setAttribute","overflow","top","abs","oninitmovie","loadIncomplete","cleanup","tests","_externalInterfaceTest","_disableDebug","detachEvent","attachEvent","SM2_DEFER","constructor","getInstance","smBuilder","instance"],"sourceRoot":""}
|
1
|
+
{"version":3,"file":"plugins/plugin.tts.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/tts/PageChunk.js","webpack://@internetarchive/bookreader/./src/plugins/tts/PageChunkIterator.js","webpack://@internetarchive/bookreader/./src/plugins/tts/AbstractTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/FestivalTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/utils.js","webpack://@internetarchive/bookreader/./src/plugins/tts/plugin.tts.js","webpack://@internetarchive/bookreader/./src/plugins/tts/WebTTSEngine.js","webpack://@internetarchive/bookreader/./src/plugins/tts/tooltip_dict.js","webpack://@internetarchive/bookreader/./src/util/browserSniffing.js","webpack://@internetarchive/bookreader/./node_modules/core-js/internals/number-parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.parse-float.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.match.js","webpack://@internetarchive/bookreader/./node_modules/iso-language-codes/js/data.js","webpack://@internetarchive/bookreader/./node_modules/jquery.browser/dist/jquery.browser.js","webpack://@internetarchive/bookreader/./node_modules/soundmanager2/script/soundmanager2.js"],"sourcesContent":["/**\n * Class to manage a 'chunk' (approximately a paragraph) of text on a page.\n */\nexport default class PageChunk {\n /**\n * @param {number} leafIndex\n * @param {number} chunkIndex\n * @param {string} text\n * @param {DJVURect[]} lineRects\n */\n constructor(leafIndex, chunkIndex, text, lineRects) {\n this.leafIndex = leafIndex;\n this.chunkIndex = chunkIndex;\n this.text = text;\n this.lineRects = lineRects;\n }\n\n /**\n * @param {string} server\n * @param {string} bookPath\n * @param {number} leafIndex\n * @return {Promise<PageChunk[]>}\n */\n static async fetch(server, bookPath, leafIndex) {\n const chunks = await $.ajax({\n type: 'GET',\n url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,\n dataType:'jsonp',\n cache: true,\n data: {\n path: `${bookPath}_djvu.xml`,\n page: leafIndex\n }\n });\n return PageChunk._fromTextWrapperResponse(leafIndex, chunks);\n }\n\n /**\n * Convert the response from BookReaderGetTextWrapper.php into a {@link PageChunk} instance\n * @param {number} leafIndex\n * @param {Array<[String, ...DJVURect[]]>} chunksResponse\n * @return {PageChunk[]}\n */\n static _fromTextWrapperResponse(leafIndex, chunksResponse) {\n return chunksResponse.map((c, i) => {\n const correctedLineRects = PageChunk._fixChunkRects(c.slice(1));\n const correctedText = PageChunk._removeDanglingHyphens(c[0]);\n return new PageChunk(leafIndex, i, correctedText, correctedLineRects);\n });\n }\n\n /**\n * @private\n * Sometimes the first rectangle will be ridiculously wide/tall. Find those and fix them\n * *NOTE*: Modifies the original array and returns it.\n * *NOTE*: This should probably be fixed on the petabox side, and then removed here\n * Has 2 problems:\n * - If the rect is the last rect on the page (and hence the only rect in the array),\n * the rect's size isn't fixed\n * - Because this relies on the second rect, there's a chance it won't be the right\n * width\n * @param {DJVURect[]} rects\n * @return {DJVURect[]}\n */\n static _fixChunkRects(rects) {\n if (rects.length < 2) return rects;\n\n const [firstRect, secondRect] = rects;\n const [left, bottom, right] = firstRect;\n const width = right - left;\n const secondHeight = secondRect[1] - secondRect[3];\n const secondWidth = secondRect[2] - secondRect[0];\n const secondRight = secondRect[2];\n\n if (width > secondWidth * 30) {\n // Set the end to be the same\n firstRect[2] = secondRight;\n // And the top to be the same height\n firstRect[3] = bottom - secondHeight;\n }\n\n return rects;\n }\n\n /**\n * Remove \"dangling\" hyphens from read aloud text to avoid TTS stuttering\n * @param {string} text\n * @return {string}\n */\n static _removeDanglingHyphens(text) {\n // Some books mis-OCR a dangling hyphen as a ¬ (mathematical not sign) . Since in math\n // the not sign should not appear followed by a space, we think we can safely assume\n // this should be replaced.\n return text.replace(/[-¬]\\s+/g, '');\n }\n}\n\n/**\n * @typedef {[number, number, number, number]} DJVURect\n * coords are in l,b,r,t order\n */\n","import PageChunk from './PageChunk.js';\n\n/**\n * Class that iterates over the page chunks of a book; caching/buffering\n * as much as possible to try to ensure a smooth experience.\n */\nexport default class PageChunkIterator {\n /**\n * @param {number} pageCount total number of pages\n * @param {number} start page to start on\n * @param {PageChunkIteratorOptions} opts\n */\n constructor(pageCount, start, opts) {\n this.pageCount = pageCount;\n this.opts = Object.assign({}, DEFAULT_OPTS, opts);\n /** Position in the chunk sequence */\n this._cursor = { page: start, chunk: 0 };\n /** @type {Object<number, PageChunk[]>} leaf index -> chunks*/\n this._bufferedPages = {};\n /** @type {Object<number, PromiseLike<PageChunk[]>} leaf index -> chunks*/\n this._bufferingPages = {};\n /**\n * @type {Promise} promise that manages cursor modifications so that they\n * happen in order triggered as opposed to order the server responds\n **/\n this._cursorLock = Promise.resolve();\n }\n\n /**\n * Get the next chunk\n * @return {PromiseLike<\"__PageChunkIterator.AT_END__\" | PageChunk>}\n */\n next() {\n return this._cursorLock = this._cursorLock\n .then(() => this._nextUncontrolled());\n }\n\n /**\n * Sends the cursor back 1\n * @return {Promise}\n **/\n decrement() {\n return this._cursorLock = this._cursorLock\n .then(() => this._decrementUncontrolled());\n }\n\n /**\n * Gets without ensuring synchronization. Since this iterator has a lot of async\n * code, calling e.g. \"next\" twice (before the first call to next has finished)\n * would cause the system to be in a weird state. To avoid that, we make sure calls\n * to next and decrement (functions that modify the cursor) are synchronized,\n * so that regardless how long it takes for one to respond, they'll always be executed\n * in the correct order.\n * @return {PromiseLike<\"__PageChunkIterator.AT_END__\" | PageChunk>}\n */\n async _nextUncontrolled() {\n if (this._cursor.page == this.pageCount) {\n return Promise.resolve(PageChunkIterator.AT_END);\n }\n this._recenterBuffer(this._cursor.page);\n const chunks = await this._fetchPageChunks(this._cursor.page);\n if (this._cursor.chunk == chunks.length) {\n this._cursor.page++;\n this._cursor.chunk = 0;\n return this._nextUncontrolled();\n }\n return chunks[this._cursor.chunk++];\n }\n\n /**\n * Decrements without ensuring synchronization. (See {@link PageChunkIterator._nextUncontrolled});\n * @return {Promise}\n */\n _decrementUncontrolled() {\n let cursorChangePromise = Promise.resolve();\n\n if (this._cursor.chunk > 0) {\n this._cursor.chunk--;\n } else if (this._cursor.page > 0) {\n this._cursor.page--;\n // Go back possibly multiple pages, because pages can be blank\n cursorChangePromise = this._fetchPageChunks(this._cursor.page)\n .then(prevPageChunks => {\n if (prevPageChunks.length == 0) return this._decrementUncontrolled();\n else this._cursor.chunk = prevPageChunks.length - 1;\n });\n }\n\n return cursorChangePromise\n .then(() => this._fetchPageChunks(this._cursor.page));\n }\n\n /**\n * Recenter the buffer around the provided page index\n * @param {number} index\n */\n _recenterBuffer(index) {\n const start = Math.max(0, index - this.opts.pageBufferSize);\n const end = Math.min(this.pageCount, index + this.opts.pageBufferSize + 1);\n for (let i = start; i < end; i++) {\n this._fetchPageChunks(i);\n }\n\n this._removePageFromBuffer(start - 1);\n this._removePageFromBuffer(end + 1);\n }\n\n /**\n * @param {number} index\n */\n _removePageFromBuffer(index) {\n delete this._bufferingPages[index];\n delete this._bufferedPages[index];\n }\n\n /**\n * Fetches the chunks on a page; checks the buffer, so it won't make unnecessary\n * requests if it's called multiple times for the same index.\n * @param {number} index\n * @return {Promise<PageChunk[]>}\n */\n _fetchPageChunks(index) {\n if (index in this._bufferingPages) return this._bufferingPages[index];\n if (index in this._bufferedPages) return Promise.resolve(this._bufferedPages[index]);\n\n this._bufferingPages[index] = this._fetchPageChunksDirect(index)\n .then(chunks => {\n delete this._bufferingPages[index];\n this._bufferedPages[index] = chunks;\n return chunks;\n });\n\n return this._bufferingPages[index];\n }\n\n /**\n * Fetches a page without checking buffer\n * @param {number} index\n */\n _fetchPageChunksDirect(index) {\n return PageChunk.fetch(this.opts.server, this.opts.bookPath, index);\n }\n}\n\nPageChunkIterator.AT_END = \"__PageChunkIterator.AT_END__\";\n\n/** @type {PageChunkIteratorOptions} */\nconst DEFAULT_OPTS = {\n server: null,\n bookPath: null,\n pageBufferSize: 2,\n};\n\n/**\n * @typedef {Object} PageChunkIteratorOptions\n * @property {string} server\n * @property {string} bookPath\n * @property {number} [pageBufferSize] number of pages to buffer before/after the current page\n */\n","import PageChunkIterator from './PageChunkIterator.js';\n/** @typedef {import('./utils.js').ISO6391} ISO6391 */\n/** @typedef {import('./PageChunk.js')} PageChunk */\n\n/**\n * @export\n * @typedef {Object} TTSEngineOptions\n * @property {String} server\n * @property {String} bookPath\n * @property {ISO6391} bookLanguage\n * @property {Function} onLoadingStart\n * @property {Function} onLoadingComplete\n * @property {Function} onDone called when the entire book is done\n * @property {function(PageChunk): PromiseLike} beforeChunkPlay will delay the playing of the chunk\n * @property {function(PageChunk): void} afterChunkPlay fires once a chunk has fully finished\n */\n\n/**\n * @typedef {Object} AbstractTTSSound\n * @property {PageChunk} chunk\n * @property {boolean} loaded\n * @property {number} rate\n * @property {SpeechSynthesisVoice} voice\n * @property {(callback: Function) => void} load\n * @property {() => PromiseLike} play\n * @property {() => Promise} stop\n * @property {() => void} pause\n * @property {() => void} resume\n * @property {() => void} finish force the sound to 'finish'\n * @property {number => void} setPlaybackRate\n * @property {SpeechSynthesisVoice => void} setVoice\n **/\n\n/** Handling bookreader's text-to-speech */\nexport default class AbstractTTSEngine {\n /**\n * @protected\n * @param {TTSEngineOptions} options\n */\n constructor(options) {\n this.playing = false;\n this.paused = false;\n this.opts = options;\n /** @type {PageChunkIterator} */\n this._chunkIterator = null;\n /** @type {AbstractTTSSound} */\n this.activeSound = null;\n this.playbackRate = 1;\n /** Events we can bind to */\n this.events = $({});\n /** @type {SpeechSynthesisVoice} */\n this.voice = null;\n // Listen for voice changes (fired by subclasses)\n this.events.on('voiceschanged', this.updateBestVoice);\n this.events.trigger('voiceschanged');\n }\n\n /**\n * @abstract\n * @return {boolean}\n */\n static isSupported() { throw new Error(\"Unimplemented abstract class\"); }\n\n /**\n * @abstract\n * @return {SpeechSynthesisVoice[]}\n */\n getVoices() { throw new Error(\"Unimplemented abstract class\"); }\n\n /** @abstract */\n init() { return null; }\n\n updateBestVoice = () => {\n this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);\n }\n\n /**\n * @param {number} leafIndex\n * @param {number} numLeafs total number of leafs in the current book\n */\n start(leafIndex, numLeafs) {\n this.playing = true;\n this.opts.onLoadingStart();\n\n this._chunkIterator = new PageChunkIterator(numLeafs, leafIndex, {\n server: this.opts.server,\n bookPath: this.opts.bookPath,\n pageBufferSize: 5,\n });\n\n this.step();\n this.events.trigger('start');\n }\n\n stop() {\n if (this.activeSound) this.activeSound.stop();\n this.playing = false;\n this._chunkIterator = null;\n this.activeSound = null;\n this.events.trigger('stop');\n }\n\n /** @public */\n pause() {\n const fireEvent = !this.paused && this.activeSound;\n this.paused = true;\n if (this.activeSound) this.activeSound.pause();\n if (fireEvent) this.events.trigger('pause');\n }\n\n /** @public */\n resume() {\n const fireEvent = this.paused && this.activeSound;\n this.paused = false;\n if (this.activeSound) this.activeSound.resume();\n if (fireEvent) this.events.trigger('resume');\n }\n\n togglePlayPause() {\n if (this.paused) this.resume();\n else this.pause();\n }\n\n /** @public */\n jumpForward() {\n if (this.activeSound) this.activeSound.finish();\n }\n\n /** @public */\n async jumpBackward() {\n await Promise.all([\n this.activeSound.stop(),\n this._chunkIterator.decrement()\n .then(() => this._chunkIterator.decrement())\n ]);\n this.step();\n }\n\n /** @param {string} voiceURI */\n setVoice(voiceURI) {\n // if the user actively selects a voice, don't re-choose best voice anymore\n // MS Edge fires voices changed randomly very often\n this.events.off('voiceschanged', this.updateBestVoice);\n this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);\n if (this.activeSound) this.activeSound.setVoice(this.voice);\n }\n\n /** @param {number} newRate */\n setPlaybackRate(newRate) {\n this.playbackRate = newRate;\n if (this.activeSound) this.activeSound.setPlaybackRate(newRate);\n }\n\n /** @private */\n async step() {\n const chunk = await this._chunkIterator.next();\n if (chunk == PageChunkIterator.AT_END) {\n this.stop();\n this.opts.onDone();\n return;\n }\n this.opts.onLoadingStart();\n const sound = this.createSound(chunk);\n sound.chunk = chunk;\n sound.rate = this.playbackRate;\n sound.voice = this.voice;\n sound.load(() => this.opts.onLoadingComplete());\n\n this.opts.onLoadingComplete();\n\n await this.opts.beforeChunkPlay(chunk);\n\n if (!this.playing) return;\n\n const playPromise = await this.playSound(sound)\n .then(()=> this.opts.afterChunkPlay(sound.chunk));\n\n if (this.paused) this.pause();\n await playPromise;\n\n if (this.playing) return this.step();\n }\n\n /**\n * @abstract\n * @param {PageChunk} chunk\n * @return {AbstractTTSSound}\n */\n createSound(chunk) { throw new Error(\"Unimplemented abstract class\"); }\n\n /**\n * @param {AbstractTTSSound} sound\n * @return {PromiseLike} promise called once playing finished\n */\n playSound(sound) {\n this.activeSound = sound;\n if (!this.activeSound.loaded) this.opts.onLoadingStart();\n return this.activeSound.play();\n }\n\n /** Convenience wrapper for {@see AbstractTTSEngine.getBestVoice} */\n getBestVoice() {\n return AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);\n }\n\n /**\n * @private\n * Find the best voice to use given the available voices, the book language, and the user's\n * languages.\n * @param {SpeechSynthesisVoice[]} voices\n * @param {ISO6391} bookLanguage\n * @param {string[]} userLanguages languages in BCP47 format (e.g. en-US). Ordered by preference.\n * @return {SpeechSynthesisVoice | undefined}\n */\n static getBestBookVoice(voices, bookLanguage, userLanguages = navigator.languages) {\n const bookLangVoices = voices.filter(v => v.lang.startsWith(bookLanguage));\n // navigator.languages browser support isn't great yet, so get just 1 language otherwise\n // Sample navigator.languages: [\"en-CA\", \"fr-CA\", \"fr\", \"en-US\", \"en\", \"de-DE\", \"de\"]\n userLanguages = userLanguages || (navigator.language ? [navigator.language] : []);\n\n // user languages that match the book language\n const matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));\n\n // Try to find voices that intersect these two sets\n return AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices) ||\n // no user languages match the books; let's return the best voice for the book language\n (bookLangVoices.find(v => v.default) || bookLangVoices[0])\n // No voices match the book language? let's find a voice in the user's language\n // and ignore book lang\n || AbstractTTSEngine.getMatchingVoice(userLanguages, voices)\n // C'mon! Ok, just read with whatever we got!\n || (voices.find(v => v.default) || voices[0]);\n }\n\n /**\n * @private\n * Get the best voice that matches one of the BCP47 languages (order by preference)\n * @param {string[]} languages in BCP 47 format (e.g. 'en-US', or 'en'); ordered by preference\n * @param {SpeechSynthesisVoice[]} voices voices to choose from\n * @return {SpeechSynthesisVoice | undefined}\n */\n static getMatchingVoice(languages, voices) {\n for (const lang of languages) {\n // Chrome Android was returning voice languages like `en_US` instead of `en-US`\n const matchingVoices = voices.filter(v => v.lang.replace('_', '-').startsWith(lang));\n if (matchingVoices.length) {\n return matchingVoices.find(v => v.default) || matchingVoices[0];\n }\n }\n }\n}\n","import AbstractTTSEngine from './AbstractTTSEngine.js';\nimport { sleep } from '../../BookReader/utils.js';\n/* global soundManager */\nimport 'soundmanager2';\nimport 'jquery.browser';\n\n/** @typedef {import(\"./AbstractTTSEngine.js\").TTSEngineOptions} TTSEngineOptions */\n/** @typedef {import(\"./AbstractTTSEngine.js\").AbstractTTSSound} AbstractTTSSound */\n\n/**\n * @extends AbstractTTSEngine\n * TTS using Festival endpoint\n **/\nexport default class FestivalTTSEngine extends AbstractTTSEngine {\n /** @override */\n static isSupported() {\n return typeof(soundManager) !== 'undefined' && soundManager.supported();\n }\n\n /** @param {TTSEngineOptions} options */\n constructor(options) {\n super(options);\n // $.browsers is sometimes undefined on some Android browsers :/\n // Likely related to when $.browser was moved to npm\n /** @type {'mp3' | 'ogg'} format of audio to get */\n this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3'; //eslint-disable-line no-jquery/no-browser\n }\n\n /** @override */\n getVoices() {\n return [\n { default: true, lang: \"en-US\", localService: false, name: \"Festival - English (US)\", voiceURI: null }\n ];\n }\n\n /** @override */\n init() {\n // setup sound manager\n soundManager.setup({\n debugMode: false,\n // Note, there's a bug in Chrome regarding range requests.\n // Flash is used as a workaround.\n // See https://bugs.chromium.org/p/chromium/issues/detail?id=505707\n preferFlash: true,\n url: '/bookreader/BookReader/soundmanager/swf',\n useHTML5Audio: true,\n //flash 8 version of swf is buggy when calling play() on a sound that is still loading\n flashVersion: 9\n });\n }\n\n /**\n * @override\n * @param {number} leafIndex\n * @param {number} numLeafs total number of leafs in the current book\n */\n start(leafIndex, numLeafs) {\n let promise = null;\n\n // Hack for iOS\n if (navigator.userAgent.match(/mobile/i)) {\n promise = this.iOSCaptureUserIntentHack();\n }\n\n promise = promise || Promise.resolve();\n promise.then(() => super.start(leafIndex, numLeafs));\n }\n\n /** @override */\n createSound(chunk) {\n return new FestivalTTSSound(this.getSoundUrl(chunk.text));\n }\n\n /**\n * @private\n * Get URL for audio that says this text\n * @param {String} dataString the thing to say\n * @return {String} url\n */\n getSoundUrl(dataString) {\n return 'https://' + this.opts.server + '/BookReader/BookReaderGetTTS.php?string='\n + encodeURIComponent(dataString)\n + '&format=.' + this.audioFormat;\n }\n\n /**\n * @private\n * Security restrictions require playback to be triggered\n * by a user click/touch. This intention gets lost in the async calls\n * on iOS, but, for some reason, if we start the audio here, it works.\n * See https://stackoverflow.com/questions/12206631/html5-audio-cant-play-through-javascript-unless-triggered-manually-once\n * @return {PromiseLike}\n */\n async iOSCaptureUserIntentHack() {\n const sound = soundManager.createSound({ url: SILENCE_1MS[this.audioFormat] });\n await new Promise(res => sound.play({onfinish: res}));\n sound.destruct();\n }\n}\n\n/** @extends AbstractTTSSound */\nclass FestivalTTSSound {\n /** @param {string} soundUrl **/\n constructor(soundUrl) {\n this.soundUrl = soundUrl;\n /** @type {SMSound} */\n this.sound = null;\n this.rate = 1;\n /** @type {function} calling this resolves the \"play\" promise */\n this._finishResolver = null;\n }\n\n get loaded() {\n return this.sound && this.sound.loaded;\n }\n\n load(onload) {\n this.sound = soundManager.createSound({\n url: this.soundUrl,\n // API recommended, but only fires once play started on safari\n onload: () => {\n if (this.rate != 1) this.sound.setPlaybackRate(this.rate);\n onload();\n },\n onresume: async () => {\n await sleep(25);\n if (this.rate != 1) this.sound.setPlaybackRate(this.rate);\n }\n });\n return this.sound.load();\n }\n\n async play() {\n await new Promise(res => {\n this._finishResolver = res;\n this.sound.play({ onfinish: res });\n });\n this.sound.destruct();\n }\n\n /** @override */\n stop() {\n this.sound.stop();\n return Promise.resolve();\n }\n\n /** @override */\n pause() { this.sound.pause(); }\n /** @override */\n resume() { this.sound.resume(); }\n /** @override */\n setPlaybackRate(rate) {\n this.rate = rate;\n this.sound.setPlaybackRate(rate);\n }\n\n /** @override */\n finish() {\n this.sound.stop();\n this._finishResolver();\n }\n}\n\n/** Needed to capture the audio context for iOS hack. Generated using Audacity. */\nconst SILENCE_1MS = {\n mp3: 'data:audio/mp3;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAACAAACcQCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA//////////////////////////////////////////////////////////////////8AAAAeTEFNRTMuOTlyBJwAAAAAAAAAADUgJAaUQQABrgAAAnHIf8sZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//sQxAADwlwBKGAAACAAAD/AAAAEAAAAH///////////////+UBAMExBTUUzLjk5LjOqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDEIAPAAAGkAAAAIAAANIAAAASqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==',\n ogg: 'data:audio/ogg;base64,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',\n};\n","import langs from 'iso-language-codes/js/data.js';\n\n/**\n * Convert a EventTarget style event into a promise\n * @param {EventTarget} target\n * @param {string} eventType\n * @return {Promise<Event>}\n */\nexport function promisifyEvent(target, eventType) {\n return new Promise(res => {\n const resolver = ev => {\n target.removeEventListener(eventType, resolver);\n res(ev);\n };\n target.addEventListener(eventType, resolver);\n });\n}\n\n/**\n * Use regex to approximate word count in a string\n * @param {string} text\n * @return {number}\n */\nexport function approximateWordCount(text) {\n const m = text.match(/\\S+/g);\n return m ? m.length : 0;\n}\n\n/**\n * Checks whether the current browser is on android\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isAndroid(userAgent = navigator.userAgent) {\n return /android/i.test(userAgent);\n}\n\n/**\n * @typedef {string} ISO6391\n * Language code in ISO 639-1 format. e.g. en, fr, zh\n **/\n\n/** Each lang is an array, with each index mapping to a different property */\nconst COLUMN_TO_LANG_INDEX = {\n 'Name': 0,\n 'Endonym': 1,\n 'ISO 639-1': 2,\n 'ISO 639-2/T': 3,\n 'ISO 639-2/B': 4\n};\n\n/**\n * @param {string} language in some format\n * @return {ISO6391?}\n */\nexport function toISO6391(language) {\n if (!language) return null;\n language = language.toLowerCase();\n\n return searchForISO6391(language, ['ISO 639-1']) ||\n searchForISO6391(language, ['ISO 639-2/B']) ||\n searchForISO6391(language, ['ISO 639-2/T', 'Endonym', 'Name']);\n}\n\n/**\n * Searches for the given long in the given columns.\n * @param {string} language\n * @param {Array<keyof COLUMN_TO_LANG_INDEX>} columnsToSearch\n * @return {ISO6391?}\n */\nfunction searchForISO6391(language, columnsToSearch) {\n for (let i = 0; i < langs.length; i++) {\n for (let colI = 0; colI < columnsToSearch.length; colI++) {\n const column = columnsToSearch[colI];\n const columnValue = langs[i][COLUMN_TO_LANG_INDEX[column]];\n if (columnValue.split(', ').map(x => x.toLowerCase()).indexOf(language) != -1) {\n return langs[i][COLUMN_TO_LANG_INDEX['ISO 639-1']];\n }\n }\n }\n return null;\n}\n","/* global BookReader */\n/**\n * Plugin for Text to Speech in BookReader\n */\nimport FestivalTTSEngine from './FestivalTTSEngine.js';\nimport WebTTSEngine from './WebTTSEngine.js';\nimport { toISO6391, approximateWordCount } from './utils.js';\nimport { en as tooltips } from './tooltip_dict.js';\nimport { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';\n/** @typedef {import('./PageChunk.js').default} PageChunk */\n/** @typedef {import(\"./AbstractTTSEngine.js\").default} AbstractTTSEngine */\n\n// Default options for TTS\njQuery.extend(BookReader.defaultOptions, {\n server: 'ia600609.us.archive.org',\n bookPath: '',\n enableTtsPlugin: true,\n});\n\n// Extend the constructor to add TTS properties\nBookReader.prototype.setup = (function (super_) {\n return function (options) {\n super_.call(this, options);\n\n if (this.options.enableTtsPlugin) {\n /** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */\n this._ttsBoxesByIndex = {};\n\n let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :\n FestivalTTSEngine.isSupported() ? FestivalTTSEngine :\n null;\n\n if (/_forceTTSEngine=(festival|web)/.test(location.toString())) {\n const engineName = location.toString().match(/_forceTTSEngine=(festival|web)/)[1];\n TTSEngine = { festival: FestivalTTSEngine, web: WebTTSEngine }[engineName];\n }\n\n if (TTSEngine) {\n /** @type {AbstractTTSEngine} */\n this.ttsEngine = new TTSEngine({\n server: options.server,\n bookPath: options.bookPath,\n bookLanguage: toISO6391(options.bookLanguage),\n onLoadingStart: this.showProgressPopup.bind(this, 'Loading audio...'),\n onLoadingComplete: this.removeProgressPopup.bind(this),\n onDone: this.ttsStop.bind(this),\n beforeChunkPlay: this.ttsBeforeChunkPlay.bind(this),\n afterChunkPlay: this.ttsSendChunkFinishedAnalyticsEvent.bind(this),\n });\n }\n }\n };\n})(BookReader.prototype.setup);\n\nBookReader.prototype.init = (function(super_) {\n return function() {\n if (this.options.enableTtsPlugin) {\n // Bind to events\n\n this.bind(BookReader.eventNames.PostInit, () => {\n this.$('.BRicon.read').click(() => {\n this.ttsToggle();\n return false;\n });\n if (this.ttsEngine) {\n this.ttsEngine.init();\n if (/[?&]_autoReadAloud=show/.test(location.toString())) {\n this.ttsStart(false); // false flag is to initiate read aloud controls\n }\n }\n });\n\n // This is fired when the hash changes by one of the other plugins!\n // i.e. it will fire every time the page changes -_-\n // this.bind(BookReader.eventNames.stop, function(e, br) {\n // this.ttsStop();\n // }.bind(this));\n }\n super_.call(this);\n };\n})(BookReader.prototype.init);\n\n/** @override */\nBookReader.prototype._createPageContainer = (function (super_) {\n return function (index) {\n const pageContainer = super_.call(this, index);\n if (this.options.enableTtsPlugin && pageContainer.page && index in this._ttsBoxesByIndex) {\n const pageIndex = pageContainer.page.index;\n renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);\n }\n return pageContainer;\n };\n})(BookReader.prototype._createPageContainer);\n\n// Extend buildMobileDrawerElement\nBookReader.prototype.buildMobileDrawerElement = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (this.options.enableTtsPlugin && this.ttsEngine) {\n $el.find('.BRmobileMenu__moreInfoRow').after($(`\n <li>\n <span>\n <span class=\"DrawerIconWrapper\"><img class=\"DrawerIcon\" src=\"${this.imagesBaseURL}icon_speaker_open.svg\" alt=\"info-speaker\"/></span>\n Read Aloud\n </span>\n <div>\n <span class=\"larger\">Press to toggle read aloud</span>\n <br/>\n <button class=\"BRicon read\"></button>\n </div>\n </li>`));\n }\n return $el;\n };\n})(BookReader.prototype.buildMobileDrawerElement);\n\n// Extend initNavbar\nBookReader.prototype.initNavbar = (function (super_) {\n return function () {\n const $el = super_.call(this);\n if (this.options.enableTtsPlugin && this.ttsEngine) {\n this.refs.$BRReadAloudToolbar = $(`\n <ul class=\"read-aloud\">\n <li>\n <select class=\"playback-speed\" name=\"playback-speed\" title=\"${tooltips.playbackSpeed}\">\n <option value=\"0.25\">0.25x</option>\n <option value=\"0.5\">0.5x</option>\n <option value=\"0.75\">0.75x</option>\n <option value=\"1.0\" selected>1.0x</option>\n <option value=\"1.25\">1.25x</option>\n <option value=\"1.5\">1.5x</option>\n <option value=\"1.75\">1.75x</option>\n <option value=\"2\">2x</option>\n </select>\n </li>\n <li>\n <button type=\"button\" name=\"review\" title=\"${tooltips.review}\">\n <div class=\"icon icon-review\"></div>\n </button>\n </li>\n <li>\n <button type=\"button\" name=\"play\" title=\"${tooltips.play}\">\n <div class=\"icon icon-play\"></div>\n <div class=\"icon icon-pause\"></div>\n </button>\n </li>\n <li>\n <button type=\"button\" name=\"advance\" title=\"${tooltips.advance}\">\n <div class=\"icon icon-advance\"></div>\n </button>\n </li>\n <li>\n <select class=\"playback-voices\" name=\"playback-voice\" style=\"display: none\" title=\"Change read aloud voices\">\n </select>\n </li>\n </ul>\n `);\n\n $el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);\n\n const renderVoiceOption = (voices) => {\n return voices.map(voice =>\n `<option value=\"${voice.voiceURI}\">${voice.lang} - ${voice.name}</option>`).join('');\n };\n\n const voiceSortOrder = (a,b) => `${a.lang} - ${a.name}`.localeCompare(`${b.lang} - ${b.name}`);\n\n const renderVoicesMenu = (voicesMenu) => {\n voicesMenu.empty();\n const bookLanguage = this.ttsEngine.opts.bookLanguage;\n const bookLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);\n const otherLanguages = this.ttsEngine.getVoices().filter(v => !v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);\n\n if (this.ttsEngine.getVoices().length > 1) {\n voicesMenu.append($(`<optgroup label=\"Book Language (${bookLanguage})\"> ${renderVoiceOption(bookLanguages)} </optgroup>`));\n voicesMenu.append($(`<optgroup label=\"Other Languages\"> ${renderVoiceOption(otherLanguages)} </optgroup>`));\n\n voicesMenu.val(this.ttsEngine.voice.voiceURI);\n voicesMenu.show();\n } else {\n voicesMenu.hide();\n }\n };\n\n const voicesMenu = this.refs.$BRReadAloudToolbar.find('[name=playback-voice]');\n renderVoicesMenu(voicesMenu);\n voicesMenu.on(\"change\", ev => this.ttsEngine.setVoice(voicesMenu.val()));\n this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());\n this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));\n this.refs.$BRReadAloudToolbar.find('[name=play]').on(\"click\", this.ttsPlayPause.bind(this));\n this.refs.$BRReadAloudToolbar.find('[name=advance]').on(\"click\", this.ttsJumpForward.bind(this));\n this.refs.$BRReadAloudToolbar.find('[name=review]').on(\"click\", this.ttsJumpBackward.bind(this));\n const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name=\"playback-speed\"]');\n $rateSelector.on(\"change\", ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));\n $(`<li>\n <button class=\"BRicon read js-tooltip\" title=\"${tooltips.readAloud}\">\n <div class=\"icon icon-read-aloud\"></div>\n <span class=\"tooltip\">${tooltips.readAloud}</span>\n </button>\n </li>`).insertBefore($el.find('.BRcontrols .BRicon.zoom_out').closest('li'));\n }\n return $el;\n };\n})(BookReader.prototype.initNavbar);\n\n// ttsToggle()\n//______________________________________________________________________________\nBookReader.prototype.ttsToggle = function () {\n if (this.autoStop) this.autoStop();\n if (this.ttsEngine.playing) {\n this.ttsStop();\n } else {\n this.ttsStart();\n }\n};\n\n// ttsStart(\n//______________________________________________________________________________\nBookReader.prototype.ttsStart = function (startTTSEngine = true) {\n if (this.constModeThumb == this.mode)\n this.switchMode(this.constMode1up);\n\n this.refs.$BRReadAloudToolbar.addClass('visible');\n this.$('.BRicon.read').addClass('unread active');\n this.ttsSendAnalyticsEvent('Start');\n if (startTTSEngine)\n this.ttsEngine.start(this.currentIndex(), this.book.getNumLeafs());\n};\n\nBookReader.prototype.ttsJumpForward = function () {\n if (this.ttsEngine.paused) {\n this.ttsEngine.resume();\n }\n this.ttsEngine.jumpForward();\n};\n\nBookReader.prototype.ttsJumpBackward = function () {\n if (this.ttsEngine.paused) {\n this.ttsEngine.resume();\n }\n this.ttsEngine.jumpBackward();\n};\n\nBookReader.prototype.ttsUpdateState = function() {\n const isPlaying = !(this.ttsEngine.paused || !this.ttsEngine.playing);\n this.$('.read-aloud [name=play]').toggleClass('playing', isPlaying);\n};\n\nBookReader.prototype.ttsPlayPause = function() {\n if (!this.ttsEngine.playing) {\n this.ttsToggle();\n } else {\n this.ttsEngine.togglePlayPause();\n this.ttsUpdateState(this.ttsEngine.paused);\n }\n};\n\n// ttsStop()\n//______________________________________________________________________________\nBookReader.prototype.ttsStop = function () {\n this.refs.$BRReadAloudToolbar.removeClass('visible');\n this.$('.BRicon.read').removeClass('unread active');\n this.ttsSendAnalyticsEvent('Stop');\n this.ttsEngine.stop();\n this.ttsRemoveHilites();\n this.removeProgressPopup();\n};\n\n/**\n * @param {PageChunk} chunk\n * @return {PromiseLike<void>} returns once the flip is done\n */\nBookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {\n await this.ttsMaybeFlipToIndex(chunk.leafIndex);\n this.ttsHighlightChunk(chunk);\n this.ttsScrollToChunk(chunk);\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsSendChunkFinishedAnalyticsEvent = function(chunk) {\n this.ttsSendAnalyticsEvent('ChunkFinished-Words', approximateWordCount(chunk.text));\n};\n\n/**\n * Flip the page if the provided leaf index is not visible\n * @param {Number} leafIndex\n * @return {PromiseLike<void>} resolves once the flip animation has completed\n */\nBookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {\n const in2PageMode = this.constMode2up == this.mode;\n let resolve = null;\n const promise = new Promise(res => resolve = res);\n\n if (!in2PageMode) {\n this.jumpToIndex(leafIndex);\n resolve();\n } else {\n const leafVisible = leafIndex == this.twoPage.currentIndexR || leafIndex == this.twoPage.currentIndexL;\n if (leafVisible) {\n resolve();\n } else {\n this.animationFinishedCallback = resolve;\n this.jumpToIndex(leafIndex);\n }\n }\n\n return promise;\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsHighlightChunk = function(chunk) {\n // The poorly-named variable leafIndex\n const pageIndex = chunk.leafIndex;\n\n this.ttsRemoveHilites();\n\n // group by index; currently only possible to have chunks on one page :/\n this._ttsBoxesByIndex = {\n [pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t}))\n };\n\n // update any already created pages\n for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {\n const pageIndex = parseFloat(pageIndexString);\n const page = this.book.getPage(pageIndex);\n const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);\n pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));\n }\n};\n\n/**\n * @param {PageChunk} chunk\n */\nBookReader.prototype.ttsScrollToChunk = function(chunk) {\n // It behaves weird if used in thumb mode\n if (this.constModeThumb == this.mode) return;\n\n $(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({\n // Only vertically center the highlight if we're in 1up or in full screen. In\n // 2up, if we're not fullscreen, the whole body gets scrolled around to try to\n // center the highlight 🙄 See:\n // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376\n // Note: nearest doesn't quite work great, because the ReadAloud toolbar is now\n // full-width, and covers up the last line of the highlight.\n block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',\n inline: 'center',\n behavior: 'smooth',\n });\n};\n\n// ttsRemoveHilites()\n//______________________________________________________________________________\nBookReader.prototype.ttsRemoveHilites = function () {\n $(this.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();\n this._ttsBoxesByIndex = {};\n};\n\n/**\n * @private\n * Send an analytics event with an optional value. Also attaches the book's language.\n * @param {string} action\n * @param {number} [value]\n */\nBookReader.prototype.ttsSendAnalyticsEvent = function(action, value) {\n if (this.archiveAnalyticsSendEvent) {\n const extraValues = {};\n const mediaLanguage = this.ttsEngine.opts.bookLanguage;\n if (mediaLanguage) extraValues.mediaLanguage = mediaLanguage;\n this.archiveAnalyticsSendEvent('BRReadAloud', action, value, extraValues);\n }\n};\n","/* global br */\nimport { isChrome, isFirefox } from '../../util/browserSniffing.js';\nimport { promisifyEvent, isAndroid } from './utils.js';\nimport { sleep } from '../../BookReader/utils.js';\nimport AbstractTTSEngine from './AbstractTTSEngine.js';\n/** @typedef {import(\"./AbstractTTSEngine.js\").PageChunk} PageChunk */\n/** @typedef {import(\"./AbstractTTSEngine.js\").AbstractTTSSound} AbstractTTSSound */\n/** @typedef {import(\"./AbstractTTSEngine.js\").TTSEngineOptions} TTSEngineOptions */\n\n/**\n * @extends AbstractTTSEngine\n * TTS using Web Speech APIs\n **/\nexport default class WebTTSEngine extends AbstractTTSEngine {\n static isSupported() {\n return typeof(window.speechSynthesis) !== 'undefined' && !/samsungbrowser/i.test(navigator.userAgent);\n }\n\n /** @param {TTSEngineOptions} options */\n constructor(options) {\n super(options);\n\n // SAFARI doesn't have addEventListener on speechSynthesis\n if (speechSynthesis.addEventListener) {\n speechSynthesis.addEventListener('voiceschanged', () => this.events.trigger('voiceschanged'));\n }\n }\n\n /** @override */\n start(leafIndex, numLeafs) {\n // Need to run in this function to capture user intent to start playing audio\n if ('mediaSession' in navigator) {\n const audio = new Audio(SILENCE_6S_MP3);\n audio.loop = true;\n\n this.events.on('pause', () => audio.pause());\n this.events.on('resume', () => audio.play());\n // apparently this is what you need to do to make the media session notification go away\n // See https://developers.google.com/web/updates/2017/02/media-session#implementation_notes\n this.events.on('stop', () => audio.src = '');\n audio.play().then(() => {\n navigator.mediaSession.metadata = new MediaMetadata({\n title: br.bookTitle,\n artist: br.options.metadata.filter(m => m.label == 'Author').map(m => m.value)[0],\n // album: 'The Ultimate Collection (Remastered)',\n artwork: [\n { src: br.options.thumbnail, type: 'image/jpg' },\n ]\n });\n\n navigator.mediaSession.setActionHandler('play', () => {\n audio.play();\n this.resume();\n });\n navigator.mediaSession.setActionHandler('pause', () => {\n audio.pause();\n this.pause();\n });\n\n // navigator.mediaSession.setActionHandler('seekbackward', () => this.jumpBackward());\n // navigator.mediaSession.setActionHandler('seekforward', () => this.jumpForward());\n // Some devices only support the previoustrack/nexttrack (e.g. Win10), so show those.\n // Android devices do support the seek actions, but we don't want to show both buttons\n // and have them do the same thing.\n navigator.mediaSession.setActionHandler('previoustrack', () => this.jumpBackward());\n navigator.mediaSession.setActionHandler('nexttrack', () => this.jumpForward());\n });\n }\n\n return super.start(leafIndex, numLeafs);\n }\n\n /** @override */\n getVoices() { return speechSynthesis.getVoices(); }\n\n /** @override */\n createSound(chunk) {\n return new WebTTSSound(chunk.text);\n }\n}\n\n/** @extends AbstractTTSSound */\nexport class WebTTSSound {\n /** @param {string} text **/\n constructor(text) {\n this.text = text;\n this.loaded = false;\n this.paused = false;\n this.started = false;\n /** Whether the audio was stopped with a .stop() call */\n this.stopped = false;\n this.rate = 1;\n\n /** @type {SpeechSynthesisUtterance} */\n this.utterance = null;\n\n /** @type {SpeechSynthesisVoice} */\n this.voice = null;\n\n this._lastEvents = {\n /** @type {SpeechSynthesisEvent} */\n pause: null,\n /** @type {SpeechSynthesisEvent} */\n boundary: null,\n /** @type {SpeechSynthesisEvent} */\n start: null,\n };\n\n /** Store where we are in the text. Only works on some browsers. */\n this._charIndex = 0;\n\n /** @type {Function} resolve function called when playback finished */\n this._finishResolver = null;\n\n /** @type {Promise} promise resolved by _finishResolver */\n this._finishPromise = null;\n }\n\n /** @override **/\n load(onload) {\n this.loaded = false;\n this.started = false;\n\n this.utterance = new SpeechSynthesisUtterance(this.text.slice(this._charIndex));\n this.utterance.voice = this.voice;\n // Need to also set lang (for some reason); won't set voice on Chrome@Android otherwise\n if (this.voice) this.utterance.lang = this.voice.lang;\n this.utterance.rate = this.rate;\n\n // Useful for debugging things\n if (location.toString().indexOf('_debugReadAloud=true') != -1) {\n this.utterance.addEventListener('pause', () => console.log('pause'));\n this.utterance.addEventListener('resume', () => console.log('resume'));\n this.utterance.addEventListener('start', () => console.log('start'));\n this.utterance.addEventListener('end', () => console.log('end'));\n this.utterance.addEventListener('error', () => console.log('error'));\n this.utterance.addEventListener('boundary', () => console.log('boundary'));\n this.utterance.addEventListener('mark', () => console.log('mark'));\n this.utterance.addEventListener('finish', () => console.log('finish'));\n }\n\n // Keep track of the speech synthesis events that come in; they have useful info\n // about progress (like charIndex)\n this.utterance.addEventListener('start', ev => this._lastEvents.start = ev);\n this.utterance.addEventListener('boundary', ev => this._lastEvents.boundary = ev);\n this.utterance.addEventListener('pause', ev => this._lastEvents.pause = ev);\n\n // Update our state\n this.utterance.addEventListener('start', () => {\n this.started = true;\n this.stopped = false;\n this.paused = false;\n });\n this.utterance.addEventListener('pause', () => this.paused = true);\n this.utterance.addEventListener('resume', () => this.paused = false);\n this.utterance.addEventListener('end', ev => {\n if (!this.paused && !this.stopped) {\n // Trigger a new event, finish, which only fires when audio fully completed\n this.utterance.dispatchEvent(new CustomEvent('finish', ev));\n }\n });\n this.loaded = true;\n onload && onload();\n }\n\n /**\n * Run whenever properties have changed. Tries to restart in the same spot it\n * left off.\n * @return {Promise<void>}\n */\n async reload() {\n // We'll restore the pause state, so copy it here\n const wasPaused = this.paused;\n // Use recent event to determine where we'll restart from\n // Browser support for this is mixed, but it degrades to restarting the chunk\n // and that's ok\n const recentEvent = this._lastEvents.boundary || this._lastEvents.pause;\n if (recentEvent) {\n this._charIndex = this.text.indexOf(recentEvent.target.text) + recentEvent.charIndex;\n }\n\n // We can't modify the utterance object, so we have to make a new one\n await this.stop();\n this.load();\n // Instead of playing and immediately pausing, we don't start playing. Note\n // this is a requirement because pause doesn't work consistently across\n // browsers.\n if (!wasPaused) this.play();\n }\n\n play() {\n this._finishPromise = this._finishPromise || new Promise(res => this._finishResolver = res);\n this.utterance.addEventListener('finish', this._finishResolver);\n\n // clear the queue\n speechSynthesis.cancel();\n // reset pause state\n speechSynthesis.resume();\n // Speak\n speechSynthesis.speak(this.utterance);\n\n const isLocalVoice = this.utterance.voice && this.utterance.voice.localService;\n if (isChrome() && !isLocalVoice) this._chromePausingBugFix();\n\n return this._finishPromise;\n }\n\n /** @return {Promise} */\n stop() {\n // 'end' won't fire if already stopped\n let endPromise = Promise.resolve();\n if (!this.stopped) {\n endPromise = Promise.race([\n promisifyEvent(this.utterance, 'end'),\n // Safari triggers an error when you call cancel mid-sound\n promisifyEvent(this.utterance, 'error'),\n ]);\n }\n this.stopped = true;\n speechSynthesis.cancel();\n return endPromise;\n }\n\n async finish() {\n await this.stop();\n this.utterance.dispatchEvent(new Event('finish'));\n }\n\n /**\n * @override\n * Will fire a pause event unless already paused\n **/\n async pause() {\n if (this.paused) return;\n\n const pausePromise = promisifyEvent(this.utterance, 'pause');\n speechSynthesis.pause();\n\n // There are a few awful browser cases:\n // 1. Pause works and fires\n // 2. Pause doesn't work and doesn't fire\n // 3. Pause works but doesn't fire\n const pauseMightNotWork = (isFirefox() && isAndroid());\n const pauseMightNotFire = isChrome() || pauseMightNotWork;\n\n if (pauseMightNotFire) {\n // wait for it just in case\n const timeoutPromise = sleep(100).then(() => 'timeout');\n const result = await Promise.race([pausePromise, timeoutPromise]);\n // We got our pause event; nothing to do!\n if (result != 'timeout') return;\n\n this.utterance.dispatchEvent(new CustomEvent('pause', this._lastEvents.start));\n\n // if pause might not work, then we'll stop entirely and restart later\n if (pauseMightNotWork) this.stop();\n }\n }\n\n async resume() {\n if (!this.started) {\n this.play();\n return;\n }\n\n if (!this.paused) return;\n\n // Browser cases:\n // 1. Resume works + fires\n // 2. Resume works + doesn't fire (Chrome Desktop)\n // 3. Resume doesn't work + doesn't fire (Chrome/FF Android)\n const resumeMightNotWork = (isChrome() && isAndroid()) || (isFirefox() && isAndroid());\n const resumeMightNotFire = isChrome() || resumeMightNotWork;\n\n // Try resume\n const resumePromise = promisifyEvent(this.utterance, 'resume');\n speechSynthesis.resume();\n\n if (resumeMightNotFire) {\n const result = await Promise.race([resumePromise, sleep(100).then(() => 'timeout')]);\n\n if (result != 'timeout') return;\n\n this.utterance.dispatchEvent(new CustomEvent('resume', {}));\n if (resumeMightNotWork) {\n await this.reload();\n this.play();\n }\n }\n }\n\n setPlaybackRate(rate) {\n this.rate = rate;\n this.reload();\n }\n\n /** @param {SpeechSynthesisVoice} voice */\n setVoice(voice) {\n this.voice = voice;\n this.reload();\n }\n /**\n * @private\n * Chrome has a bug where it only plays 15 seconds of TTS and then\n * suddenly stops (see https://bugs.chromium.org/p/chromium/issues/detail?id=679437 )\n * We avoid this (as described here: https://bugs.chromium.org/p/chromium/issues/detail?id=679437#c15 )\n * by pausing after 14 seconds and ~instantly resuming.\n */\n async _chromePausingBugFix() {\n const timeoutPromise = sleep(14000).then(() => 'timeout');\n const pausePromise = promisifyEvent(this.utterance, 'pause').then(() => 'paused');\n const endPromise = promisifyEvent(this.utterance, 'end').then(() => 'ended');\n const result = await Promise.race([timeoutPromise, pausePromise, endPromise]);\n if (location.toString().indexOf('_debugReadAloud=true') != -1) {\n console.log(`CHROME-PAUSE-HACK: ${result}`);\n }\n switch (result) {\n case 'ended':\n // audio was stopped/finished; nothing to do\n break;\n case 'paused':\n // audio was paused; wait for resume\n // Chrome won't let you resume the audio if 14s have passed 🤷\n // We could do the same as before (but resume+pause instead of pause+resume),\n // but that means we'd _constantly_ be running in the background. So in that\n // case, let's just restart the chunk\n await Promise.race([\n promisifyEvent(this.utterance, 'resume'),\n sleep(14000).then(() => 'timeout'),\n ]);\n result == 'timeout' ? this.reload() : this._chromePausingBugFix();\n break;\n case 'timeout':\n // We hit Chrome's secret cut off time. Pause/resume\n // to be able to keep TTS-ing\n speechSynthesis.pause();\n await sleep(25);\n speechSynthesis.resume();\n this._chromePausingBugFix();\n break;\n }\n }\n}\n\n/**\n * According to https://developers.google.com/web/updates/2017/02/media-session#implementation_notes , it needs to be at least 5 seconds\n * long to allow usage of the media sessions api\n */\nconst SILENCE_6S_MP3 = 'data:audio/mp3;base64,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';\n","export const en = {\n advance: 'Advance 10 seconds',\n play: 'Play',\n playbackSpeed: 'Playback speed',\n readAloud: 'Read this book aloud',\n review: 'Review 10 seconds',\n};\n\nexport const es = {\n advance: 'Avance 10 segundos',\n play: 'Jugar',\n playbackSpeed: 'Velocidad de reproducción',\n readAloud: 'Lee este libro en voz alta',\n review: 'Revisar 10 segundos',\n};\n","\n/**\n * Checks whether the current browser is a Chrome/Chromium browser\n * Code from https://stackoverflow.com/a/4565120/2317712\n * @param {string} [userAgent]\n * @param {string} [vendor]\n * @return {boolean}\n */\nexport function isChrome(userAgent = navigator.userAgent, vendor = navigator.vendor) {\n return /chrome/i.test(userAgent) && /google inc/i.test(vendor);\n}\n\n/**\n * Checks whether the current browser is firefox\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isFirefox(userAgent = navigator.userAgent) {\n return /firefox/i.test(userAgent);\n}\n\n/**\n * Checks whether the current browser is safari\n * https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#Browser_Name\n * @param {string} [userAgent]\n * @return {boolean}\n */\nexport function isSafari(userAgent = navigator.userAgent) {\n return /safari/i.test(userAgent) && !/chrome|chromium/i.test(userAgent);\n}\n","var global = require('../internals/global');\nvar fails = require('../internals/fails');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar toString = require('../internals/to-string');\nvar trim = require('../internals/string-trim').trim;\nvar whitespaces = require('../internals/whitespaces');\n\nvar charAt = uncurryThis(''.charAt);\nvar n$ParseFloat = global.parseFloat;\nvar Symbol = global.Symbol;\nvar ITERATOR = Symbol && Symbol.iterator;\nvar FORCED = 1 / n$ParseFloat(whitespaces + '-0') !== -Infinity\n // MS Edge 18- broken with boxed symbols\n || (ITERATOR && !fails(function () { n$ParseFloat(Object(ITERATOR)); }));\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\nmodule.exports = FORCED ? function parseFloat(string) {\n var trimmedString = trim(toString(string));\n var result = n$ParseFloat(trimmedString);\n return result === 0 && charAt(trimmedString, 0) == '-' ? -0 : result;\n} : n$ParseFloat;\n","var $ = require('../internals/export');\nvar $entries = require('../internals/object-to-array').entries;\n\n// `Object.entries` method\n// https://tc39.es/ecma262/#sec-object.entries\n$({ target: 'Object', stat: true }, {\n entries: function entries(O) {\n return $entries(O);\n }\n});\n","var $ = require('../internals/export');\nvar $parseFloat = require('../internals/number-parse-float');\n\n// `parseFloat` method\n// https://tc39.es/ecma262/#sec-parsefloat-string\n$({ global: true, forced: parseFloat != $parseFloat }, {\n parseFloat: $parseFloat\n});\n","'use strict';\nvar call = require('../internals/function-call');\nvar fixRegExpWellKnownSymbolLogic = require('../internals/fix-regexp-well-known-symbol-logic');\nvar anObject = require('../internals/an-object');\nvar toLength = require('../internals/to-length');\nvar toString = require('../internals/to-string');\nvar requireObjectCoercible = require('../internals/require-object-coercible');\nvar getMethod = require('../internals/get-method');\nvar advanceStringIndex = require('../internals/advance-string-index');\nvar regExpExec = require('../internals/regexp-exec-abstract');\n\n// @@match logic\nfixRegExpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {\n return [\n // `String.prototype.match` method\n // https://tc39.es/ecma262/#sec-string.prototype.match\n function match(regexp) {\n var O = requireObjectCoercible(this);\n var matcher = regexp == undefined ? undefined : getMethod(regexp, MATCH);\n return matcher ? call(matcher, regexp, O) : new RegExp(regexp)[MATCH](toString(O));\n },\n // `RegExp.prototype[@@match]` method\n // https://tc39.es/ecma262/#sec-regexp.prototype-@@match\n function (string) {\n var rx = anObject(this);\n var S = toString(string);\n var res = maybeCallNative(nativeMatch, rx, S);\n\n if (res.done) return res.value;\n\n if (!rx.global) return regExpExec(rx, S);\n\n var fullUnicode = rx.unicode;\n rx.lastIndex = 0;\n var A = [];\n var n = 0;\n var result;\n while ((result = regExpExec(rx, S)) !== null) {\n var matchStr = toString(result[0]);\n A[n] = matchStr;\n if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);\n n++;\n }\n return n === 0 ? null : A;\n }\n ];\n});\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports[\"default\"] = void 0;\nvar _default = [['Serbian', 'српски језик', 'sr', 'srp', 'srp'], ['Romanian, Moldavian, Moldovan', 'Română', 'ro', 'ron', 'rum'], ['Sichuan Yi, Nuosu', 'ꆈꌠ꒿ Nuosuhxop', 'ii', 'iii', 'iii'], ['Tahitian', 'Reo Tahiti', 'ty', 'tah', 'tah'], ['Tagalog', 'Wikang Tagalog', 'tl', 'tgl', 'tgl'], ['Yiddish', 'ייִדיש', 'yi', 'yid', 'yid'], ['Akan', 'Akan', 'ak', 'aka', 'aka'], ['Malay', 'Bahasa Melayu, بهاس ملايو', 'ms', 'msa', 'may'], ['Arabic', 'العربية', 'ar', 'ara', 'ara'], ['Norwegian', 'Norsk', 'no', 'nor', 'nor'], ['Ojibwa', 'ᐊᓂᔑᓈᐯᒧᐎᓐ', 'oj', 'oji', 'oji'], ['Fulah', 'Fulfulde, Pulaar, Pular', 'ff', 'ful', 'ful'], ['Persian', 'فارسی', 'fa', 'fas', 'per'], ['Albanian', 'Shqip', 'sq', 'sqi', 'alb'], ['Aymara', 'aymar aru', 'ay', 'aym', 'aym'], ['Azerbaijani', 'azərbaycan dili', 'az', 'aze', 'aze'], ['Chinese', '中文 (Zhōngwén), 汉语, 漢語', 'zh', 'zho', 'chi'], ['Cree', 'ᓀᐦᐃᔭᐍᐏᐣ', 'cr', 'cre', 'cre'], ['Estonian', 'eesti, eesti keel', 'et', 'est', 'est'], ['Guaraní', 'Avañe\\'ẽ', 'gn', 'grn', 'grn'], ['Inupiaq', 'Iñupiaq, Iñupiatun', 'ik', 'ipk', 'ipk'], ['Inuktitut', 'ᐃᓄᒃᑎᑐᑦ', 'iu', 'iku', 'iku'], ['Kanuri', 'Kanuri', 'kr', 'kau', 'kau'], ['Komi', 'коми кыв', 'kv', 'kom', 'kom'], ['Kongo', 'Kikongo', 'kg', 'kon', 'kon'], ['Kurdish', 'Kurdî, کوردی', 'ku', 'kur', 'kur'], ['Latvian', 'latviešu valoda', 'lv', 'lav', 'lav'], ['Malagasy', 'fiteny malagasy', 'mg', 'mlg', 'mlg'], ['Mongolian', 'Монгол хэл', 'mn', 'mon', 'mon'], ['Oromo', 'Afaan Oromoo', 'om', 'orm', 'orm'], ['Pashto, Pushto', 'پښتو', 'ps', 'pus', 'pus'], ['Quechua', 'Runa Simi, Kichwa', 'qu', 'que', 'que'], ['Sardinian', 'sardu', 'sc', 'srd', 'srd'], ['Swahili', 'Kiswahili', 'sw', 'swa', 'swa'], ['Uzbek', 'Oʻzbek, Ўзбек, أۇزبېك', 'uz', 'uzb', 'uzb'], ['Zhuang, Chuang', 'Saɯ cueŋƅ, Saw cuengh', 'za', 'zha', 'zha'], ['Bislama', 'Bislama', 'bi', 'bis', 'bis'], ['Norwegian Bokmål', 'Norsk Bokmål', 'nb', 'nob', 'nob'], ['Norwegian Nynorsk', 'Norsk Nynorsk', 'nn', 'nno', 'nno'], ['Indonesian', 'Bahasa Indonesia', 'id', 'ind', 'ind'], ['Twi', 'Twi', 'tw', 'twi', 'twi'], ['Esperanto', 'Esperanto', 'eo', 'epo', 'epo'], ['Interlingua', 'Interlingua', 'ia', 'ina', 'ina'], ['Interlingue', 'Originally called Occidental; then Interlingue after WWII', 'ie', 'ile', 'ile'], ['Ido', 'Ido', 'io', 'ido', 'ido'], ['Volapük', 'Volapük', 'vo', 'vol', 'vol'], ['Bihari languages', 'भोजपुरी', 'bh', 'bih', 'bih'], ['Hebrew (modern)', 'עברית', 'he', 'heb', 'heb'], ['Sanskrit', 'संस्कृतम्', 'sa', 'san', 'san'], ['Church Slavic, Church Slavonic, Old Church Slavonic, Old Slavonic, Old Bulgarian', 'ѩзыкъ словѣньскъ', 'cu', 'chu', 'chu'], ['Pali', 'पाऴि', 'pi', 'pli', 'pli'], ['Avestan', 'avesta', 'ae', 'ave', 'ave'], ['Latin', 'latine, lingua latina', 'la', 'lat', 'lat'], ['Armenian', 'Հայերեն', 'hy', 'hye', 'arm'], ['Swati', 'SiSwati', 'ss', 'ssw', 'ssw'], ['Tibetan', 'བོད་ཡིག', 'bo', 'bod', 'tib'], ['South Ndebele', 'isiNdebele', 'nr', 'nbl', 'nbl'], ['Slovene', 'Slovenski Jezik, Slovenščina', 'sl', 'slv', 'slv'], ['Oriya', 'ଓଡ଼ିଆ', 'or', 'ori', 'ori'], ['North Ndebele', 'isiNdebele', 'nd', 'nde', 'nde'], ['Nauru', 'Dorerin Naoero', 'na', 'nau', 'nau'], ['Maori', 'te reo Māori', 'mi', 'mri', 'mao'], ['Marathi', 'मराठी', 'mr', 'mar', 'mar'], ['Luba-Katanga', 'Kiluba', 'lu', 'lub', 'lub'], ['Rundi', 'Ikirundi', 'rn', 'run', 'run'], ['Central Khmer', 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ', 'km', 'khm', 'khm'], ['Western Frisian', 'Frysk', 'fy', 'fry', 'fry'], ['Bengali', 'বাংলা', 'bn', 'ben', 'ben'], ['Avaric', 'авар мацӀ, магӀарул мацӀ', 'av', 'ava', 'ava'], ['Abkhazian', 'аҧсуа бызшәа, аҧсшәа', 'ab', 'abk', 'abk'], ['Afar', 'Afaraf', 'aa', 'aar', 'aar'], ['Afrikaans', 'Afrikaans', 'af', 'afr', 'afr'], ['Amharic', 'አማርኛ', 'am', 'amh', 'amh'], ['Aragonese', 'aragonés', 'an', 'arg', 'arg'], ['Assamese', 'অসমীয়া', 'as', 'asm', 'asm'], ['Bambara', 'bamanankan', 'bm', 'bam', 'bam'], ['Bashkir', 'башҡорт теле', 'ba', 'bak', 'bak'], ['Basque', 'euskara, euskera', 'eu', 'eus', 'baq'], ['Belarusian', 'беларуская мова', 'be', 'bel', 'bel'], ['Bosnian', 'bosanski jezik', 'bs', 'bos', 'bos'], ['Breton', 'brezhoneg', 'br', 'bre', 'bre'], ['Bulgarian', 'български език', 'bg', 'bul', 'bul'], ['Burmese', 'ဗမာစာ', 'my', 'mya', 'bur'], ['Catalan, Valencian', 'català, valencià', 'ca', 'cat', 'cat'], ['Chamorro', 'Chamoru', 'ch', 'cha', 'cha'], ['Chechen', 'нохчийн мотт', 'ce', 'che', 'che'], ['Chichewa, Chewa, Nyanja', 'chiCheŵa, chinyanja', 'ny', 'nya', 'nya'], ['Chuvash', 'чӑваш чӗлхи', 'cv', 'chv', 'chv'], ['Cornish', 'Kernewek', 'kw', 'cor', 'cor'], ['Corsican', 'corsu, lingua corsa', 'co', 'cos', 'cos'], ['Croatian', 'hrvatski jezik', 'hr', 'hrv', 'hrv'], ['Czech', 'čeština, český jazyk', 'cs', 'ces', 'cze'], ['Danish', 'dansk', 'da', 'dan', 'dan'], ['Divehi, Dhivehi, Maldivian', 'ދިވެހި', 'dv', 'div', 'div'], ['Dutch, Flemish', 'Nederlands, Vlaams', 'nl', 'nld', 'dut'], ['Dzongkha', 'རྫོང་ཁ', 'dz', 'dzo', 'dzo'], ['English', 'English', 'en', 'eng', 'eng'], ['Ewe', 'Eʋegbe', 'ee', 'ewe', 'ewe'], ['Faroese', 'føroyskt', 'fo', 'fao', 'fao'], ['Fijian', 'vosa Vakaviti', 'fj', 'fij', 'fij'], ['Finnish', 'suomi, suomen kieli', 'fi', 'fin', 'fin'], ['French', 'français, langue française', 'fr', 'fra', 'fre'], ['Galician', 'Galego', 'gl', 'glg', 'glg'], ['Georgian', 'ქართული', 'ka', 'kat', 'geo'], ['German', 'Deutsch', 'de', 'deu', 'ger'], ['Greek (modern)', 'ελληνικά', 'el', 'ell', 'gre'], ['Gujarati', 'ગુજરાતી', 'gu', 'guj', 'guj'], ['Haitian, Haitian Creole', 'Kreyòl ayisyen', 'ht', 'hat', 'hat'], ['Hausa', '(Hausa) هَوُسَ', 'ha', 'hau', 'hau'], ['Herero', 'Otjiherero', 'hz', 'her', 'her'], ['Hindi', 'हिन्दी, हिंदी', 'hi', 'hin', 'hin'], ['Hiri Motu', 'Hiri Motu', 'ho', 'hmo', 'hmo'], ['Hungarian', 'magyar', 'hu', 'hun', 'hun'], ['Irish', 'Gaeilge', 'ga', 'gle', 'gle'], ['Igbo', 'Asụsụ Igbo', 'ig', 'ibo', 'ibo'], ['Icelandic', 'Íslenska', 'is', 'isl', 'ice'], ['Italian', 'Italiano', 'it', 'ita', 'ita'], ['Japanese', '日本語 (にほんご)', 'ja', 'jpn', 'jpn'], ['Javanese', 'ꦧꦱꦗꦮ, Basa Jawa', 'jv', 'jav', 'jav'], ['Kalaallisut, Greenlandic', 'kalaallisut, kalaallit oqaasii', 'kl', 'kal', 'kal'], ['Kannada', 'ಕನ್ನಡ', 'kn', 'kan', 'kan'], ['Kashmiri', 'कश्मीरी, كشميري', 'ks', 'kas', 'kas'], ['Kazakh', 'қазақ тілі', 'kk', 'kaz', 'kaz'], ['Kikuyu, Gikuyu', 'Gĩkũyũ', 'ki', 'kik', 'kik'], ['Kinyarwanda', 'Ikinyarwanda', 'rw', 'kin', 'kin'], ['Kirghiz, Kyrgyz', 'Кыргызча, Кыргыз тили', 'ky', 'kir', 'kir'], ['Korean', '한국어', 'ko', 'kor', 'kor'], ['Kuanyama, Kwanyama', 'Kuanyama', 'kj', 'kua', 'kua'], ['Luxembourgish, Letzeburgesch', 'Lëtzebuergesch', 'lb', 'ltz', 'ltz'], ['Ganda', 'Luganda', 'lg', 'lug', 'lug'], ['Limburgan, Limburger, Limburgish', 'Limburgs', 'li', 'lim', 'lim'], ['Lingala', 'Lingála', 'ln', 'lin', 'lin'], ['Lao', 'ພາສາລາວ', 'lo', 'lao', 'lao'], ['Lithuanian', 'lietuvių kalba', 'lt', 'lit', 'lit'], ['Manx', 'Gaelg, Gailck', 'gv', 'glv', 'glv'], ['Macedonian', 'македонски јазик', 'mk', 'mkd', 'mac'], ['Malayalam', 'മലയാളം', 'ml', 'mal', 'mal'], ['Maltese', 'Malti', 'mt', 'mlt', 'mlt'], ['Marshallese', 'Kajin M̧ajeļ', 'mh', 'mah', 'mah'], ['Navajo, Navaho', 'Diné bizaad', 'nv', 'nav', 'nav'], ['Nepali', 'नेपाली', 'ne', 'nep', 'nep'], ['Ndonga', 'Owambo', 'ng', 'ndo', 'ndo'], ['Occitan', 'occitan, lenga d\\'òc', 'oc', 'oci', 'oci'], ['Ossetian, Ossetic', 'ирон æвзаг', 'os', 'oss', 'oss'], ['Panjabi, Punjabi', 'ਪੰਜਾਬੀ', 'pa', 'pan', 'pan'], ['Polish', 'język polski, polszczyzna', 'pl', 'pol', 'pol'], ['Portuguese', 'Português', 'pt', 'por', 'por'], ['Romansh', 'Rumantsch Grischun', 'rm', 'roh', 'roh'], ['Russian', 'русский', 'ru', 'rus', 'rus'], ['Sindhi', 'सिन्धी, سنڌي، سندھی', 'sd', 'snd', 'snd'], ['Northern Sami', 'Davvisámegiella', 'se', 'sme', 'sme'], ['Samoan', 'gagana fa\\'a Samoa', 'sm', 'smo', 'smo'], ['Sango', 'yângâ tî sängö', 'sg', 'sag', 'sag'], ['Gaelic, Scottish Gaelic', 'Gàidhlig', 'gd', 'gla', 'gla'], ['Shona', 'chiShona', 'sn', 'sna', 'sna'], ['Sinhala, Sinhalese', 'සිංහල', 'si', 'sin', 'sin'], ['Slovak', 'Slovenčina, Slovenský Jazyk', 'sk', 'slk', 'slo'], ['Somali', 'Soomaaliga, af Soomaali', 'so', 'som', 'som'], ['Southern Sotho', 'Sesotho', 'st', 'sot', 'sot'], ['Spanish, Castilian', 'Español', 'es', 'spa', 'spa'], ['Sundanese', 'Basa Sunda', 'su', 'sun', 'sun'], ['Swedish', 'Svenska', 'sv', 'swe', 'swe'], ['Tamil', 'தமிழ்', 'ta', 'tam', 'tam'], ['Telugu', 'తెలుగు', 'te', 'tel', 'tel'], ['Tajik', 'тоҷикӣ, toçikī, تاجیکی', 'tg', 'tgk', 'tgk'], ['Thai', 'ไทย', 'th', 'tha', 'tha'], ['Tigrinya', 'ትግርኛ', 'ti', 'tir', 'tir'], ['Turkmen', 'Türkmen, Түркмен', 'tk', 'tuk', 'tuk'], ['Tswana', 'Setswana', 'tn', 'tsn', 'tsn'], ['Tongan (Tonga Islands)', 'Faka Tonga', 'to', 'ton', 'ton'], ['Turkish', 'Türkçe', 'tr', 'tur', 'tur'], ['Tsonga', 'Xitsonga', 'ts', 'tso', 'tso'], ['Tatar', 'татар теле, tatar tele', 'tt', 'tat', 'tat'], ['Uighur, Uyghur', 'ئۇيغۇرچە, Uyghurche', 'ug', 'uig', 'uig'], ['Ukrainian', 'Українська', 'uk', 'ukr', 'ukr'], ['Urdu', 'اردو', 'ur', 'urd', 'urd'], ['Venda', 'Tshivenḓa', 've', 'ven', 'ven'], ['Vietnamese', 'Tiếng Việt', 'vi', 'vie', 'vie'], ['Walloon', 'Walon', 'wa', 'wln', 'wln'], ['Welsh', 'Cymraeg', 'cy', 'cym', 'wel'], ['Wolof', 'Wollof', 'wo', 'wol', 'wol'], ['Xhosa', 'isiXhosa', 'xh', 'xho', 'xho'], ['Yoruba', 'Yorùbá', 'yo', 'yor', 'yor'], ['Zulu', 'isiZulu', 'zu', 'zul', 'zul']];\nexports[\"default\"] = _default;","/*!\n * jQuery Browser Plugin 0.1.0\n * https://github.com/gabceb/jquery-browser-plugin\n *\n * Original jquery-browser code Copyright 2005, 2015 jQuery Foundation, Inc. and other contributors\n * http://jquery.org/license\n *\n * Modifications Copyright 2015 Gabriel Cebrian\n * https://github.com/gabceb\n *\n * Released under the MIT license\n *\n * Date: 05-07-2015\n */\n/*global window: false */\n\n(function (factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['jquery'], function ($) {\n return factory($);\n });\n } else if (typeof module === 'object' && typeof module.exports === 'object') {\n // Node-like environment\n module.exports = factory(require('jquery'));\n } else {\n // Browser globals\n factory(window.jQuery);\n }\n}(function(jQuery) {\n \"use strict\";\n\n function uaMatch( ua ) {\n // If an UA is not provided, default to the current browser UA.\n if ( ua === undefined ) {\n ua = window.navigator.userAgent;\n }\n ua = ua.toLowerCase();\n\n var match = /(edge)\\/([\\w.]+)/.exec( ua ) ||\n /(opr)[\\/]([\\w.]+)/.exec( ua ) ||\n /(chrome)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(iemobile)[\\/]([\\w.]+)/.exec( ua ) ||\n /(version)(applewebkit)[ \\/]([\\w.]+).*(safari)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(webkit)[ \\/]([\\w.]+).*(version)[ \\/]([\\w.]+).*(safari)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(webkit)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec( ua ) ||\n /(msie) ([\\w.]+)/.exec( ua ) ||\n ua.indexOf(\"trident\") >= 0 && /(rv)(?::| )([\\w.]+)/.exec( ua ) ||\n ua.indexOf(\"compatible\") < 0 && /(mozilla)(?:.*? rv:([\\w.]+)|)/.exec( ua ) ||\n [];\n\n var platform_match = /(ipad)/.exec( ua ) ||\n /(ipod)/.exec( ua ) ||\n /(windows phone)/.exec( ua ) ||\n /(iphone)/.exec( ua ) ||\n /(kindle)/.exec( ua ) ||\n /(silk)/.exec( ua ) ||\n /(android)/.exec( ua ) ||\n /(win)/.exec( ua ) ||\n /(mac)/.exec( ua ) ||\n /(linux)/.exec( ua ) ||\n /(cros)/.exec( ua ) ||\n /(playbook)/.exec( ua ) ||\n /(bb)/.exec( ua ) ||\n /(blackberry)/.exec( ua ) ||\n [];\n\n var browser = {},\n matched = {\n browser: match[ 5 ] || match[ 3 ] || match[ 1 ] || \"\",\n version: match[ 2 ] || match[ 4 ] || \"0\",\n versionNumber: match[ 4 ] || match[ 2 ] || \"0\",\n platform: platform_match[ 0 ] || \"\"\n };\n\n if ( matched.browser ) {\n browser[ matched.browser ] = true;\n browser.version = matched.version;\n browser.versionNumber = parseInt(matched.versionNumber, 10);\n }\n\n if ( matched.platform ) {\n browser[ matched.platform ] = true;\n }\n\n // These are all considered mobile platforms, meaning they run a mobile browser\n if ( browser.android || browser.bb || browser.blackberry || browser.ipad || browser.iphone ||\n browser.ipod || browser.kindle || browser.playbook || browser.silk || browser[ \"windows phone\" ]) {\n browser.mobile = true;\n }\n\n // These are all considered desktop platforms, meaning they run a desktop browser\n if ( browser.cros || browser.mac || browser.linux || browser.win ) {\n browser.desktop = true;\n }\n\n // Chrome, Opera 15+ and Safari are webkit based browsers\n if ( browser.chrome || browser.opr || browser.safari ) {\n browser.webkit = true;\n }\n\n // IE11 has a new token so we will assign it msie to avoid breaking changes\n if ( browser.rv || browser.iemobile) {\n var ie = \"msie\";\n\n matched.browser = ie;\n browser[ie] = true;\n }\n\n // Edge is officially known as Microsoft Edge, so rewrite the key to match\n if ( browser.edge ) {\n delete browser.edge;\n var msedge = \"msedge\";\n\n matched.browser = msedge;\n browser[msedge] = true;\n }\n\n // Blackberry browsers are marked as Safari on BlackBerry\n if ( browser.safari && browser.blackberry ) {\n var blackberry = \"blackberry\";\n\n matched.browser = blackberry;\n browser[blackberry] = true;\n }\n\n // Playbook browsers are marked as Safari on Playbook\n if ( browser.safari && browser.playbook ) {\n var playbook = \"playbook\";\n\n matched.browser = playbook;\n browser[playbook] = true;\n }\n\n // BB10 is a newer OS version of BlackBerry\n if ( browser.bb ) {\n var bb = \"blackberry\";\n\n matched.browser = bb;\n browser[bb] = true;\n }\n\n // Opera 15+ are identified as opr\n if ( browser.opr ) {\n var opera = \"opera\";\n\n matched.browser = opera;\n browser[opera] = true;\n }\n\n // Stock Android browsers are marked as Safari on Android.\n if ( browser.safari && browser.android ) {\n var android = \"android\";\n\n matched.browser = android;\n browser[android] = true;\n }\n\n // Kindle browsers are marked as Safari on Kindle\n if ( browser.safari && browser.kindle ) {\n var kindle = \"kindle\";\n\n matched.browser = kindle;\n browser[kindle] = true;\n }\n\n // Kindle Silk browsers are marked as Safari on Kindle\n if ( browser.safari && browser.silk ) {\n var silk = \"silk\";\n\n matched.browser = silk;\n browser[silk] = true;\n }\n\n // Assign the name and platform variable\n browser.name = matched.browser;\n browser.platform = matched.platform;\n return browser;\n }\n\n // Run the matching process, also assign the function to the returned object\n // for manual, jQuery-free use if desired\n window.jQBrowser = uaMatch( window.navigator.userAgent );\n window.jQBrowser.uaMatch = uaMatch;\n\n // Only assign to jQuery.browser if jQuery is loaded\n if ( jQuery ) {\n jQuery.browser = window.jQBrowser;\n }\n\n return window.jQBrowser;\n}));\n","/** @license\r\n *\r\n * SoundManager 2: JavaScript Sound for the Web\r\n * ----------------------------------------------\r\n * http://schillmania.com/projects/soundmanager2/\r\n *\r\n * Copyright (c) 2007, Scott Schiller. All rights reserved.\r\n * Code provided under the BSD License:\r\n * http://schillmania.com/projects/soundmanager2/license.txt\r\n *\r\n * V2.97a.20170601\r\n */\r\n\r\n/**\r\n * About this file\r\n * -------------------------------------------------------------------------------------\r\n * This is the fully-commented source version of the SoundManager 2 API,\r\n * recommended for use during development and testing.\r\n *\r\n * See soundmanager2-nodebug-jsmin.js for an optimized build (~11KB with gzip.)\r\n * http://schillmania.com/projects/soundmanager2/doc/getstarted/#basic-inclusion\r\n * Alternately, serve this file with gzip for 75% compression savings (~30KB over HTTP.)\r\n *\r\n * You may notice <d> and </d> comments in this source; these are delimiters for\r\n * debug blocks which are removed in the -nodebug builds, further optimizing code size.\r\n *\r\n * Also, as you may note: Whoa, reliable cross-platform/device audio support is hard! ;)\r\n */\r\n\r\n(function SM2(window, _undefined) {\r\n\r\n/* global Audio, document, window, navigator, define, module, SM2_DEFER, opera, setTimeout, setInterval, clearTimeout, sm2Debugger */\r\n\r\n'use strict';\r\n\r\nif (!window || !window.document) {\r\n\r\n // Don't cross the [environment] streams. SM2 expects to be running in a browser, not under node.js etc.\r\n // Additionally, if a browser somehow manages to fail this test, as Egon said: \"It would be bad.\"\r\n\r\n throw new Error('SoundManager requires a browser with window and document objects.');\r\n\r\n}\r\n\r\nvar soundManager = null;\r\n\r\n/**\r\n * The SoundManager constructor.\r\n *\r\n * @constructor\r\n * @param {string} smURL Optional: Path to SWF files\r\n * @param {string} smID Optional: The ID to use for the SWF container element\r\n * @this {SoundManager}\r\n * @return {SoundManager} The new SoundManager instance\r\n */\r\n\r\nfunction SoundManager(smURL, smID) {\r\n\r\n /**\r\n * soundManager configuration options list\r\n * defines top-level configuration properties to be applied to the soundManager instance (eg. soundManager.flashVersion)\r\n * to set these properties, use the setup() method - eg., soundManager.setup({url: '/swf/', flashVersion: 9})\r\n */\r\n\r\n this.setupOptions = {\r\n\r\n url: (smURL || null), // path (directory) where SoundManager 2 SWFs exist, eg., /path/to/swfs/\r\n flashVersion: 8, // flash build to use (8 or 9.) Some API features require 9.\r\n debugMode: true, // enable debugging output (console.log() with HTML fallback)\r\n debugFlash: false, // enable debugging output inside SWF, troubleshoot Flash/browser issues\r\n useConsole: true, // use console.log() if available (otherwise, writes to #soundmanager-debug element)\r\n consoleOnly: true, // if console is being used, do not create/write to #soundmanager-debug\r\n waitForWindowLoad: false, // force SM2 to wait for window.onload() before trying to call soundManager.onload()\r\n bgColor: '#ffffff', // SWF background color. N/A when wmode = 'transparent'\r\n useHighPerformance: false, // position:fixed flash movie can help increase js/flash speed, minimize lag\r\n flashPollingInterval: null, // msec affecting whileplaying/loading callback frequency. If null, default of 50 msec is used.\r\n html5PollingInterval: null, // msec affecting whileplaying() for HTML5 audio, excluding mobile devices. If null, native HTML5 update events are used.\r\n flashLoadTimeout: 1000, // msec to wait for flash movie to load before failing (0 = infinity)\r\n wmode: null, // flash rendering mode - null, 'transparent', or 'opaque' (last two allow z-index to work)\r\n allowScriptAccess: 'always', // for scripting the SWF (object/embed property), 'always' or 'sameDomain'\r\n useFlashBlock: false, // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable.\r\n useHTML5Audio: true, // use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (MP3/MP4 support varies.) Ideally, transparent vs. Flash API where possible.\r\n forceUseGlobalHTML5Audio: false, // if true, a single Audio() object is used for all sounds - and only one can play at a time.\r\n ignoreMobileRestrictions: false, // if true, SM2 will not apply global HTML5 audio rules to mobile UAs. iOS > 7 and WebViews may allow multiple Audio() instances.\r\n html5Test: /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.\r\n preferFlash: false, // overrides useHTML5audio, will use Flash for MP3/MP4/AAC if present. Potential option if HTML5 playback with these formats is quirky.\r\n noSWFCache: false, // if true, appends ?ts={date} to break aggressive SWF caching.\r\n idPrefix: 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc.\r\n\r\n };\r\n\r\n this.defaultOptions = {\r\n\r\n /**\r\n * the default configuration for sound objects made with createSound() and related methods\r\n * eg., volume, auto-load behaviour and so forth\r\n */\r\n\r\n autoLoad: false, // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)\r\n autoPlay: false, // enable playing of file as soon as possible (much faster if \"stream\" is true)\r\n from: null, // position to start playback within a sound (msec), default = beginning\r\n loops: 1, // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0)\r\n onid3: null, // callback function for \"ID3 data is added/available\"\r\n onerror: null, // callback function for \"load failed\" (or, playback/network/decode error under HTML5.)\r\n onload: null, // callback function for \"load finished\"\r\n whileloading: null, // callback function for \"download progress update\" (X of Y bytes received)\r\n onplay: null, // callback for \"play\" start\r\n onpause: null, // callback for \"pause\"\r\n onresume: null, // callback for \"resume\" (pause toggle)\r\n whileplaying: null, // callback during play (position update)\r\n onposition: null, // object containing times and function callbacks for positions of interest\r\n onstop: null, // callback for \"user stop\"\r\n onfinish: null, // callback function for \"sound finished playing\"\r\n multiShot: true, // let sounds \"restart\" or layer on top of each other when played multiple times, rather than one-shot/one at a time\r\n multiShotEvents: false, // fire multiple sound events (currently onfinish() only) when multiShot is enabled\r\n position: null, // offset (milliseconds) to seek to within loaded sound data.\r\n pan: 0, // \"pan\" settings, left-to-right, -100 to 100\r\n playbackRate: 1, // rate at which to play the sound (HTML5-only)\r\n stream: true, // allows playing before entire file has loaded (recommended)\r\n to: null, // position to end playback within a sound (msec), default = end\r\n type: null, // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3\r\n usePolicyFile: false, // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access)\r\n volume: 100 // self-explanatory. 0-100, the latter being the max.\r\n\r\n };\r\n\r\n this.flash9Options = {\r\n\r\n /**\r\n * flash 9-only options,\r\n * merged into defaultOptions if flash 9 is being used\r\n */\r\n\r\n onfailure: null, // callback function for when playing fails (Flash 9, MovieStar + RTMP-only)\r\n isMovieStar: null, // \"MovieStar\" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL\r\n usePeakData: false, // enable left/right channel peak (level) data\r\n useWaveformData: false, // enable sound spectrum (raw waveform data) - NOTE: May increase CPU load.\r\n useEQData: false, // enable sound EQ (frequency spectrum data) - NOTE: May increase CPU load.\r\n onbufferchange: null, // callback for \"isBuffering\" property change\r\n ondataerror: null // callback for waveform/eq data access error (flash playing audio in other tabs/domains)\r\n\r\n };\r\n\r\n this.movieStarOptions = {\r\n\r\n /**\r\n * flash 9.0r115+ MPEG4 audio options,\r\n * merged into defaultOptions if flash 9+movieStar mode is enabled\r\n */\r\n\r\n bufferTime: 3, // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.)\r\n serverURL: null, // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants\r\n onconnect: null, // rtmp: callback for connection to flash media server\r\n duration: null // rtmp: song duration (msec)\r\n\r\n };\r\n\r\n this.audioFormats = {\r\n\r\n /**\r\n * determines HTML5 support + flash requirements.\r\n * if no support (via flash and/or HTML5) for a \"required\" format, SM2 will fail to start.\r\n * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true)\r\n */\r\n\r\n mp3: {\r\n type: ['audio/mpeg; codecs=\"mp3\"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'],\r\n required: true\r\n },\r\n\r\n mp4: {\r\n related: ['aac', 'm4a', 'm4b'], // additional formats under the MP4 container\r\n type: ['audio/mp4; codecs=\"mp4a.40.2\"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'],\r\n required: false\r\n },\r\n\r\n ogg: {\r\n type: ['audio/ogg; codecs=vorbis'],\r\n required: false\r\n },\r\n\r\n opus: {\r\n type: ['audio/ogg; codecs=opus', 'audio/opus'],\r\n required: false\r\n },\r\n\r\n wav: {\r\n type: ['audio/wav; codecs=\"1\"', 'audio/wav', 'audio/wave', 'audio/x-wav'],\r\n required: false\r\n },\r\n\r\n flac: {\r\n type: ['audio/flac'],\r\n required: false\r\n }\r\n\r\n };\r\n\r\n // HTML attributes (id + class names) for the SWF container\r\n\r\n this.movieID = 'sm2-container';\r\n this.id = (smID || 'sm2movie');\r\n\r\n this.debugID = 'soundmanager-debug';\r\n this.debugURLParam = /([#?&])debug=1/i;\r\n\r\n // dynamic attributes\r\n\r\n this.versionNumber = 'V2.97a.20170601';\r\n this.version = null;\r\n this.movieURL = null;\r\n this.altURL = null;\r\n this.swfLoaded = false;\r\n this.enabled = false;\r\n this.oMC = null;\r\n this.sounds = {};\r\n this.soundIDs = [];\r\n this.muted = false;\r\n this.didFlashBlock = false;\r\n this.filePattern = null;\r\n\r\n this.filePatterns = {\r\n flash8: /\\.mp3(\\?.*)?$/i,\r\n flash9: /\\.mp3(\\?.*)?$/i\r\n };\r\n\r\n // support indicators, set at init\r\n\r\n this.features = {\r\n buffering: false,\r\n peakData: false,\r\n waveformData: false,\r\n eqData: false,\r\n movieStar: false\r\n };\r\n\r\n // flash sandbox info, used primarily in troubleshooting\r\n\r\n this.sandbox = {\r\n // <d>\r\n type: null,\r\n types: {\r\n remote: 'remote (domain-based) rules',\r\n localWithFile: 'local with file access (no internet access)',\r\n localWithNetwork: 'local with network (internet access only, no local access)',\r\n localTrusted: 'local, trusted (local+internet access)'\r\n },\r\n description: null,\r\n noRemote: null,\r\n noLocal: null\r\n // </d>\r\n };\r\n\r\n /**\r\n * format support (html5/flash)\r\n * stores canPlayType() results based on audioFormats.\r\n * eg. { mp3: boolean, mp4: boolean }\r\n * treat as read-only.\r\n */\r\n\r\n this.html5 = {\r\n usingFlash: null // set if/when flash fallback is needed\r\n };\r\n\r\n // file type support hash\r\n this.flash = {};\r\n\r\n // determined at init time\r\n this.html5Only = false;\r\n\r\n // used for special cases (eg. iPad/iPhone/palm OS?)\r\n this.ignoreFlash = false;\r\n\r\n /**\r\n * a few private internals (OK, a lot. :D)\r\n */\r\n\r\n var SMSound,\r\n sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, rebootIntoHTML5, setVersionInfo, handleFocus, strings, initMovie, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [],\r\n canIgnoreFlash, needsFlash = null, featureCheck, html5OK, html5CanPlay, html5ErrorCodes, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0, didSetup, msecScale = 1000,\r\n is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie|trident/i),\r\n isWebkit = ua.match(/webkit/i),\r\n isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)),\r\n isOpera = (ua.match(/opera/i)),\r\n mobileHTML5 = (ua.match(/(mobile|pre\\/|xoom)/i) || is_iDevice || isAndroid),\r\n isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS\\sX\\s10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, \"Silk\") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159\r\n hasConsole = (window.console !== _undefined && console.log !== _undefined),\r\n isFocused = (doc.hasFocus !== _undefined ? doc.hasFocus() : null),\r\n tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())),\r\n okToDisable = !tryInitOnFocus,\r\n flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i,\r\n emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs)\r\n emptyWAV = 'data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==', // tiny WAV for HTML5 unloading\r\n overHTTP = (doc.location ? doc.location.protocol.match(/http/i) : null),\r\n http = (!overHTTP ? '//' : ''),\r\n // mp3, mp4, aac etc.\r\n netStreamMimeTypes = /^\\s*audio\\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4|m4v|m4a|m4b|mp4v|3gp|3g2)\\s*(?:$|;)/i,\r\n // Flash v9.0r115+ \"moviestar\" formats\r\n netStreamTypes = ['mpeg4', 'aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'm4b', 'mp4v', '3gp', '3g2'],\r\n netStreamPattern = new RegExp('\\\\.(' + netStreamTypes.join('|') + ')(\\\\?.*)?$', 'i');\r\n\r\n this.mimePattern = /^\\s*audio\\/(?:x-)?(?:mp(?:eg|3))\\s*(?:$|;)/i; // default mp3 set\r\n\r\n // use altURL if not \"online\"\r\n this.useAltURL = !overHTTP;\r\n\r\n swfCSS = {\r\n swfBox: 'sm2-object-box',\r\n swfDefault: 'movieContainer',\r\n swfError: 'swf_error', // SWF loaded, but SM2 couldn't start (other error)\r\n swfTimedout: 'swf_timedout',\r\n swfLoaded: 'swf_loaded',\r\n swfUnblocked: 'swf_unblocked', // or loaded OK\r\n sm2Debug: 'sm2_debug',\r\n highPerf: 'high_performance',\r\n flashDebug: 'flash_debug'\r\n };\r\n\r\n /**\r\n * HTML5 error codes, per W3C\r\n * Error code 1, MEDIA_ERR_ABORTED: Client aborted download at user's request.\r\n * Error code 2, MEDIA_ERR_NETWORK: A network error of some description caused the user agent to stop fetching the media resource, after the resource was established to be usable.\r\n * Error code 3, MEDIA_ERR_DECODE: An error of some description occurred while decoding the media resource, after the resource was established to be usable.\r\n * Error code 4, MEDIA_ERR_SRC_NOT_SUPPORTED: Media (audio file) not supported (\"not usable.\")\r\n * Reference: https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes\r\n */\r\n html5ErrorCodes = [\r\n null,\r\n 'MEDIA_ERR_ABORTED',\r\n 'MEDIA_ERR_NETWORK',\r\n 'MEDIA_ERR_DECODE',\r\n 'MEDIA_ERR_SRC_NOT_SUPPORTED'\r\n ];\r\n\r\n /**\r\n * basic HTML5 Audio() support test\r\n * try...catch because of IE 9 \"not implemented\" nonsense\r\n * https://github.com/Modernizr/Modernizr/issues/224\r\n */\r\n\r\n this.hasHTML5 = (function() {\r\n try {\r\n // new Audio(null) for stupid Opera 9.64 case, which throws not_enough_arguments exception otherwise.\r\n return (Audio !== _undefined && (isOpera && opera !== _undefined && opera.version() < 10 ? new Audio(null) : new Audio()).canPlayType !== _undefined);\r\n } catch(e) {\r\n return false;\r\n }\r\n }());\r\n\r\n /**\r\n * Public SoundManager API\r\n * -----------------------\r\n */\r\n\r\n /**\r\n * Configures top-level soundManager properties.\r\n *\r\n * @param {object} options Option parameters, eg. { flashVersion: 9, url: '/path/to/swfs/' }\r\n * onready and ontimeout are also accepted parameters. call soundManager.setup() to see the full list.\r\n */\r\n\r\n this.setup = function(options) {\r\n\r\n var noURL = (!sm2.url);\r\n\r\n // warn if flash options have already been applied\r\n\r\n if (options !== _undefined && didInit && needsFlash && sm2.ok() && (options.flashVersion !== _undefined || options.url !== _undefined || options.html5Test !== _undefined)) {\r\n complain(str('setupLate'));\r\n }\r\n\r\n // TODO: defer: true?\r\n\r\n assign(options);\r\n\r\n if (!useGlobalHTML5Audio) {\r\n\r\n if (mobileHTML5) {\r\n\r\n // force the singleton HTML5 pattern on mobile, by default.\r\n if (!sm2.setupOptions.ignoreMobileRestrictions || sm2.setupOptions.forceUseGlobalHTML5Audio) {\r\n messages.push(strings.globalHTML5);\r\n useGlobalHTML5Audio = true;\r\n }\r\n\r\n } else if (sm2.setupOptions.forceUseGlobalHTML5Audio) {\r\n\r\n // only apply singleton HTML5 on desktop if forced.\r\n messages.push(strings.globalHTML5);\r\n useGlobalHTML5Audio = true;\r\n\r\n }\r\n\r\n }\r\n\r\n if (!didSetup && mobileHTML5) {\r\n\r\n if (sm2.setupOptions.ignoreMobileRestrictions) {\r\n\r\n messages.push(strings.ignoreMobile);\r\n\r\n } else {\r\n\r\n // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point.\r\n\r\n // <d>\r\n if (!sm2.setupOptions.useHTML5Audio || sm2.setupOptions.preferFlash) {\r\n // notify that defaults are being changed.\r\n sm2._wD(strings.mobileUA);\r\n }\r\n // </d>\r\n\r\n sm2.setupOptions.useHTML5Audio = true;\r\n sm2.setupOptions.preferFlash = false;\r\n\r\n if (is_iDevice) {\r\n\r\n // no flash here.\r\n sm2.ignoreFlash = true;\r\n\r\n } else if ((isAndroid && !ua.match(/android\\s2\\.3/i)) || !isAndroid) {\r\n\r\n /**\r\n * Android devices tend to work better with a single audio instance, specifically for chained playback of sounds in sequence.\r\n * Common use case: exiting sound onfinish() -> createSound() -> play()\r\n * Presuming similar restrictions for other mobile, non-Android, non-iOS devices.\r\n */\r\n\r\n // <d>\r\n sm2._wD(strings.globalHTML5);\r\n // </d>\r\n\r\n useGlobalHTML5Audio = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n // special case 1: \"Late setup\". SM2 loaded normally, but user didn't assign flash URL eg., setup({url:...}) before SM2 init. Treat as delayed init.\r\n\r\n if (options) {\r\n\r\n if (noURL && didDCLoaded && options.url !== _undefined) {\r\n sm2.beginDelayedInit();\r\n }\r\n\r\n // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP.\r\n\r\n if (!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') {\r\n setTimeout(domContentLoaded, 1);\r\n }\r\n\r\n }\r\n\r\n didSetup = true;\r\n\r\n return sm2;\r\n\r\n };\r\n\r\n this.ok = function() {\r\n\r\n return (needsFlash ? (didInit && !disabled) : (sm2.useHTML5Audio && sm2.hasHTML5));\r\n\r\n };\r\n\r\n this.supported = this.ok; // legacy\r\n\r\n this.getMovie = function(movie_id) {\r\n\r\n // safety net: some old browsers differ on SWF references, possibly related to ExternalInterface / flash version\r\n return id(movie_id) || doc[movie_id] || window[movie_id];\r\n\r\n };\r\n\r\n /**\r\n * Creates a SMSound sound object instance. Can also be overloaded, e.g., createSound('mySound', '/some.mp3');\r\n *\r\n * @param {object} oOptions Sound options (at minimum, url parameter is required.)\r\n * @return {object} SMSound The new SMSound object.\r\n */\r\n\r\n this.createSound = function(oOptions, _url) {\r\n\r\n var cs, cs_string, options, oSound = null;\r\n\r\n // <d>\r\n cs = sm + '.createSound(): ';\r\n cs_string = cs + str(!didInit ? 'notReady' : 'notOK');\r\n // </d>\r\n\r\n if (!didInit || !sm2.ok()) {\r\n complain(cs_string);\r\n return false;\r\n }\r\n\r\n if (_url !== _undefined) {\r\n // function overloading in JS! :) ... assume simple createSound(id, url) use case.\r\n oOptions = {\r\n id: oOptions,\r\n url: _url\r\n };\r\n }\r\n\r\n // inherit from defaultOptions\r\n options = mixin(oOptions);\r\n\r\n options.url = parseURL(options.url);\r\n\r\n // generate an id, if needed.\r\n if (options.id === _undefined) {\r\n options.id = sm2.setupOptions.idPrefix + (idCounter++);\r\n }\r\n\r\n // <d>\r\n if (options.id.toString().charAt(0).match(/^[0-9]$/)) {\r\n sm2._wD(cs + str('badID', options.id), 2);\r\n }\r\n\r\n sm2._wD(cs + options.id + (options.url ? ' (' + options.url + ')' : ''), 1);\r\n // </d>\r\n\r\n if (idCheck(options.id, true)) {\r\n sm2._wD(cs + options.id + ' exists', 1);\r\n return sm2.sounds[options.id];\r\n }\r\n\r\n function make() {\r\n\r\n options = loopFix(options);\r\n sm2.sounds[options.id] = new SMSound(options);\r\n sm2.soundIDs.push(options.id);\r\n return sm2.sounds[options.id];\r\n\r\n }\r\n\r\n if (html5OK(options)) {\r\n\r\n oSound = make();\r\n // <d>\r\n if (!sm2.html5Only) {\r\n sm2._wD(options.id + ': Using HTML5');\r\n }\r\n // </d>\r\n oSound._setup_html5(options);\r\n\r\n } else {\r\n\r\n if (sm2.html5Only) {\r\n sm2._wD(options.id + ': No HTML5 support for this sound, and no Flash. Exiting.');\r\n return make();\r\n }\r\n\r\n // TODO: Move HTML5/flash checks into generic URL parsing/handling function.\r\n\r\n if (sm2.html5.usingFlash && options.url && options.url.match(/data:/i)) {\r\n // data: URIs not supported by Flash, either.\r\n sm2._wD(options.id + ': data: URIs not supported via Flash. Exiting.');\r\n return make();\r\n }\r\n\r\n if (fV > 8) {\r\n if (options.isMovieStar === null) {\r\n // attempt to detect MPEG-4 formats\r\n options.isMovieStar = !!(options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || (options.url && options.url.match(netStreamPattern)));\r\n }\r\n // <d>\r\n if (options.isMovieStar) {\r\n sm2._wD(cs + 'using MovieStar handling');\r\n if (options.loops > 1) {\r\n _wDS('noNSLoop');\r\n }\r\n }\r\n // </d>\r\n }\r\n\r\n options = policyFix(options, cs);\r\n oSound = make();\r\n\r\n if (fV === 8) {\r\n flash._createSound(options.id, options.loops || 1, options.usePolicyFile);\r\n } else {\r\n flash._createSound(options.id, options.url, options.usePeakData, options.useWaveformData, options.useEQData, options.isMovieStar, (options.isMovieStar ? options.bufferTime : false), options.loops || 1, options.serverURL, options.duration || null, options.autoPlay, true, options.autoLoad, options.usePolicyFile);\r\n if (!options.serverURL) {\r\n // We are connected immediately\r\n oSound.connected = true;\r\n if (options.onconnect) {\r\n options.onconnect.apply(oSound);\r\n }\r\n }\r\n }\r\n\r\n if (!options.serverURL && (options.autoLoad || options.autoPlay)) {\r\n // call load for non-rtmp streams\r\n oSound.load(options);\r\n }\r\n\r\n }\r\n\r\n // rtmp will play in onconnect\r\n if (!options.serverURL && options.autoPlay) {\r\n oSound.play();\r\n }\r\n\r\n return oSound;\r\n\r\n };\r\n\r\n /**\r\n * Destroys a SMSound sound object instance.\r\n *\r\n * @param {string} sID The ID of the sound to destroy\r\n */\r\n\r\n this.destroySound = function(sID, _bFromSound) {\r\n\r\n // explicitly destroy a sound before normal page unload, etc.\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n var oS = sm2.sounds[sID], i;\r\n\r\n oS.stop();\r\n\r\n // Disable all callbacks after stop(), when the sound is being destroyed\r\n oS._iO = {};\r\n\r\n oS.unload();\r\n\r\n for (i = 0; i < sm2.soundIDs.length; i++) {\r\n if (sm2.soundIDs[i] === sID) {\r\n sm2.soundIDs.splice(i, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (!_bFromSound) {\r\n // ignore if being called from SMSound instance\r\n oS.destruct(true);\r\n }\r\n\r\n oS = null;\r\n delete sm2.sounds[sID];\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Calls the load() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {object} oOptions Optional: Sound options\r\n */\r\n\r\n this.load = function(sID, oOptions) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].load(oOptions);\r\n\r\n };\r\n\r\n /**\r\n * Calls the unload() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n */\r\n\r\n this.unload = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].unload();\r\n\r\n };\r\n\r\n /**\r\n * Calls the onPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod The relevant callback to fire\r\n * @param {object} oScope Optional: The scope to apply the callback to\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.onPosition = function(sID, nPosition, oMethod, oScope) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].onposition(nPosition, oMethod, oScope);\r\n\r\n };\r\n\r\n // legacy/backwards-compability: lower-case method name\r\n this.onposition = this.onPosition;\r\n\r\n /**\r\n * Calls the clearOnPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod Optional: The relevant callback to fire\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.clearOnPosition = function(sID, nPosition, oMethod) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].clearOnPosition(nPosition, oMethod);\r\n\r\n };\r\n\r\n /**\r\n * Calls the play() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {object} oOptions Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.play = function(sID, oOptions) {\r\n\r\n var result = null,\r\n // legacy function-overloading use case: play('mySound', '/path/to/some.mp3');\r\n overloaded = (oOptions && !(oOptions instanceof Object));\r\n\r\n if (!didInit || !sm2.ok()) {\r\n complain(sm + '.play(): ' + str(!didInit ? 'notReady' : 'notOK'));\r\n return false;\r\n }\r\n\r\n if (!idCheck(sID, overloaded)) {\r\n\r\n // no sound found for the given ID. Bail.\r\n if (!overloaded) return false;\r\n\r\n if (overloaded) {\r\n oOptions = {\r\n url: oOptions\r\n };\r\n }\r\n\r\n if (oOptions && oOptions.url) {\r\n // overloading use case, create+play: .play('someID', {url:'/path/to.mp3'});\r\n sm2._wD(sm + '.play(): Attempting to create \"' + sID + '\"', 1);\r\n oOptions.id = sID;\r\n result = sm2.createSound(oOptions).play();\r\n }\r\n\r\n } else if (overloaded) {\r\n\r\n // existing sound object case\r\n oOptions = {\r\n url: oOptions\r\n };\r\n\r\n }\r\n\r\n if (result === null) {\r\n // default case\r\n result = sm2.sounds[sID].play(oOptions);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n // just for convenience\r\n this.start = this.play;\r\n\r\n /**\r\n * Calls the setPlaybackRate() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPlaybackRate = function(sID, rate, allowOverride) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPlaybackRate(rate, allowOverride);\r\n\r\n };\r\n\r\n /**\r\n * Calls the setPosition() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nMsecOffset Position (milliseconds)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPosition = function(sID, nMsecOffset) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPosition(nMsecOffset);\r\n\r\n };\r\n\r\n /**\r\n * Calls the stop() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.stop = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.stop(' + sID + ')', 1);\r\n\r\n return sm2.sounds[sID].stop();\r\n\r\n };\r\n\r\n /**\r\n * Stops all currently-playing sounds.\r\n */\r\n\r\n this.stopAll = function() {\r\n\r\n var oSound;\r\n sm2._wD(sm + '.stopAll()', 1);\r\n\r\n for (oSound in sm2.sounds) {\r\n if (sm2.sounds.hasOwnProperty(oSound)) {\r\n // apply only to sound objects\r\n sm2.sounds[oSound].stop();\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the pause() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.pause = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].pause();\r\n\r\n };\r\n\r\n /**\r\n * Pauses all currently-playing sounds.\r\n */\r\n\r\n this.pauseAll = function() {\r\n\r\n var i;\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].pause();\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the resume() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.resume = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].resume();\r\n\r\n };\r\n\r\n /**\r\n * Resumes all currently-paused sounds.\r\n */\r\n\r\n this.resumeAll = function() {\r\n\r\n var i;\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].resume();\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Calls the togglePause() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.togglePause = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].togglePause();\r\n\r\n };\r\n\r\n /**\r\n * Calls the setPan() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nPan The pan value (-100 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPan = function(sID, nPan) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setPan(nPan);\r\n\r\n };\r\n\r\n /**\r\n * Calls the setVolume() method of a SMSound object by ID\r\n * Overloaded case: pass only volume argument eg., setVolume(50) to apply to all sounds.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @param {number} nVol The volume value (0 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setVolume = function(sID, nVol) {\r\n\r\n // setVolume(50) function overloading case - apply to all sounds\r\n\r\n var i, j;\r\n\r\n if (sID !== _undefined && !isNaN(sID) && nVol === _undefined) {\r\n for (i = 0, j = sm2.soundIDs.length; i < j; i++) {\r\n sm2.sounds[sm2.soundIDs[i]].setVolume(sID);\r\n }\r\n return false;\r\n }\r\n\r\n // setVolume('mySound', 50) case\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].setVolume(nVol);\r\n\r\n };\r\n\r\n /**\r\n * Calls the mute() method of either a single SMSound object by ID, or all sound objects.\r\n *\r\n * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.)\r\n */\r\n\r\n this.mute = function(sID) {\r\n\r\n var i = 0;\r\n\r\n if (sID instanceof String) {\r\n sID = null;\r\n }\r\n\r\n if (!sID) {\r\n\r\n sm2._wD(sm + '.mute(): Muting all sounds');\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].mute();\r\n }\r\n sm2.muted = true;\r\n\r\n } else {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.mute(): Muting \"' + sID + '\"');\r\n return sm2.sounds[sID].mute();\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Mutes all sounds.\r\n */\r\n\r\n this.muteAll = function() {\r\n\r\n sm2.mute();\r\n\r\n };\r\n\r\n /**\r\n * Calls the unmute() method of either a single SMSound object by ID, or all sound objects.\r\n *\r\n * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.)\r\n */\r\n\r\n this.unmute = function(sID) {\r\n\r\n var i;\r\n\r\n if (sID instanceof String) {\r\n sID = null;\r\n }\r\n\r\n if (!sID) {\r\n\r\n sm2._wD(sm + '.unmute(): Unmuting all sounds');\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].unmute();\r\n }\r\n sm2.muted = false;\r\n\r\n } else {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n sm2._wD(sm + '.unmute(): Unmuting \"' + sID + '\"');\r\n\r\n return sm2.sounds[sID].unmute();\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Unmutes all sounds.\r\n */\r\n\r\n this.unmuteAll = function() {\r\n\r\n sm2.unmute();\r\n\r\n };\r\n\r\n /**\r\n * Calls the toggleMute() method of a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.toggleMute = function(sID) {\r\n\r\n if (!idCheck(sID)) return false;\r\n\r\n return sm2.sounds[sID].toggleMute();\r\n\r\n };\r\n\r\n /**\r\n * Retrieves the memory used by the flash plugin.\r\n *\r\n * @return {number} The amount of memory in use\r\n */\r\n\r\n this.getMemoryUse = function() {\r\n\r\n // flash-only\r\n var ram = 0;\r\n\r\n if (flash && fV !== 8) {\r\n ram = parseInt(flash._getMemoryUse(), 10);\r\n }\r\n\r\n return ram;\r\n\r\n };\r\n\r\n /**\r\n * Undocumented: NOPs soundManager and all SMSound objects.\r\n */\r\n\r\n this.disable = function(bNoDisable) {\r\n\r\n // destroy all functions\r\n var i;\r\n\r\n if (bNoDisable === _undefined) {\r\n bNoDisable = false;\r\n }\r\n\r\n // already disabled?\r\n if (disabled) return false;\r\n\r\n disabled = true;\r\n\r\n _wDS('shutdown', 1);\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n disableObject(sm2.sounds[sm2.soundIDs[i]]);\r\n }\r\n\r\n disableObject(sm2);\r\n\r\n // fire \"complete\", despite fail\r\n initComplete(bNoDisable);\r\n\r\n event.remove(window, 'load', initUserOnload);\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of a MIME type, eg. 'audio/mp3'.\r\n */\r\n\r\n this.canPlayMIME = function(sMIME) {\r\n\r\n var result;\r\n\r\n if (sm2.hasHTML5) {\r\n result = html5CanPlay({\r\n type: sMIME\r\n });\r\n }\r\n\r\n if (!result && needsFlash) {\r\n // if flash 9, test netStream (movieStar) types as well.\r\n result = (sMIME && sm2.ok() ? !!((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null); // TODO: make less \"weird\" (per JSLint)\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of a URL based on audio support.\r\n *\r\n * @param {string} sURL The URL to test\r\n * @return {boolean} URL playability\r\n */\r\n\r\n this.canPlayURL = function(sURL) {\r\n\r\n var result;\r\n\r\n if (sm2.hasHTML5) {\r\n result = html5CanPlay({\r\n url: sURL\r\n });\r\n }\r\n\r\n if (!result && needsFlash) {\r\n result = (sURL && sm2.ok() ? !!(sURL.match(sm2.filePattern)) : null);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Determines playability of an HTML DOM <a> object (or similar object literal) based on audio support.\r\n *\r\n * @param {object} oLink an HTML DOM <a> object or object literal including href and/or type attributes\r\n * @return {boolean} URL playability\r\n */\r\n\r\n this.canPlayLink = function(oLink) {\r\n\r\n if (oLink.type !== _undefined && oLink.type && sm2.canPlayMIME(oLink.type)) return true;\r\n\r\n return sm2.canPlayURL(oLink.href);\r\n\r\n };\r\n\r\n /**\r\n * Retrieves a SMSound object by ID.\r\n *\r\n * @param {string} sID The ID of the sound\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.getSoundById = function(sID, _suppressDebug) {\r\n\r\n if (!sID) return null;\r\n\r\n var result = sm2.sounds[sID];\r\n\r\n // <d>\r\n if (!result && !_suppressDebug) {\r\n sm2._wD(sm + '.getSoundById(): Sound \"' + sID + '\" not found.', 2);\r\n }\r\n // </d>\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Queues a callback for execution when SoundManager has successfully initialized.\r\n *\r\n * @param {function} oMethod The callback method to fire\r\n * @param {object} oScope Optional: The scope to apply to the callback\r\n */\r\n\r\n this.onready = function(oMethod, oScope) {\r\n\r\n var sType = 'onready',\r\n result = false;\r\n\r\n if (typeof oMethod === 'function') {\r\n\r\n // <d>\r\n if (didInit) {\r\n sm2._wD(str('queue', sType));\r\n }\r\n // </d>\r\n\r\n if (!oScope) {\r\n oScope = window;\r\n }\r\n\r\n addOnEvent(sType, oMethod, oScope);\r\n processOnEvents();\r\n\r\n result = true;\r\n\r\n } else {\r\n\r\n throw str('needFunction', sType);\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Queues a callback for execution when SoundManager has failed to initialize.\r\n *\r\n * @param {function} oMethod The callback method to fire\r\n * @param {object} oScope Optional: The scope to apply to the callback\r\n */\r\n\r\n this.ontimeout = function(oMethod, oScope) {\r\n\r\n var sType = 'ontimeout',\r\n result = false;\r\n\r\n if (typeof oMethod === 'function') {\r\n\r\n // <d>\r\n if (didInit) {\r\n sm2._wD(str('queue', sType));\r\n }\r\n // </d>\r\n\r\n if (!oScope) {\r\n oScope = window;\r\n }\r\n\r\n addOnEvent(sType, oMethod, oScope);\r\n processOnEvents({ type: sType });\r\n\r\n result = true;\r\n\r\n } else {\r\n\r\n throw str('needFunction', sType);\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Writes console.log()-style debug output to a console or in-browser element.\r\n * Applies when debugMode = true\r\n *\r\n * @param {string} sText The console message\r\n * @param {object} nType Optional log level (number), or object. Number case: Log type/style where 0 = 'info', 1 = 'warn', 2 = 'error'. Object case: Object to be dumped.\r\n */\r\n\r\n this._writeDebug = function(sText, sTypeOrObject) {\r\n\r\n // pseudo-private console.log()-style output\r\n // <d>\r\n\r\n var sDID = 'soundmanager-debug', o, oItem;\r\n\r\n if (!sm2.setupOptions.debugMode) return false;\r\n\r\n if (hasConsole && sm2.useConsole) {\r\n if (sTypeOrObject && typeof sTypeOrObject === 'object') {\r\n // object passed; dump to console.\r\n console.log(sText, sTypeOrObject);\r\n } else if (debugLevels[sTypeOrObject] !== _undefined) {\r\n console[debugLevels[sTypeOrObject]](sText);\r\n } else {\r\n console.log(sText);\r\n }\r\n if (sm2.consoleOnly) return true;\r\n }\r\n\r\n o = id(sDID);\r\n\r\n if (!o) return false;\r\n\r\n oItem = doc.createElement('div');\r\n\r\n if (++wdCount % 2 === 0) {\r\n oItem.className = 'sm2-alt';\r\n }\r\n\r\n if (sTypeOrObject === _undefined) {\r\n sTypeOrObject = 0;\r\n } else {\r\n sTypeOrObject = parseInt(sTypeOrObject, 10);\r\n }\r\n\r\n oItem.appendChild(doc.createTextNode(sText));\r\n\r\n if (sTypeOrObject) {\r\n if (sTypeOrObject >= 2) {\r\n oItem.style.fontWeight = 'bold';\r\n }\r\n if (sTypeOrObject === 3) {\r\n oItem.style.color = '#ff3333';\r\n }\r\n }\r\n\r\n // top-to-bottom\r\n // o.appendChild(oItem);\r\n\r\n // bottom-to-top\r\n o.insertBefore(oItem, o.firstChild);\r\n\r\n o = null;\r\n // </d>\r\n\r\n return true;\r\n\r\n };\r\n\r\n // <d>\r\n // last-resort debugging option\r\n if (wl.indexOf('sm2-debug=alert') !== -1) {\r\n this._writeDebug = function(sText) {\r\n window.alert(sText);\r\n };\r\n }\r\n // </d>\r\n\r\n // alias\r\n this._wD = this._writeDebug;\r\n\r\n /**\r\n * Provides debug / state information on all SMSound objects.\r\n */\r\n\r\n this._debug = function() {\r\n\r\n // <d>\r\n var i, j;\r\n _wDS('currentObj', 1);\r\n\r\n for (i = 0, j = sm2.soundIDs.length; i < j; i++) {\r\n sm2.sounds[sm2.soundIDs[i]]._debug();\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n /**\r\n * Restarts and re-initializes the SoundManager instance.\r\n *\r\n * @param {boolean} resetEvents Optional: When true, removes all registered onready and ontimeout event callbacks.\r\n * @param {boolean} excludeInit Options: When true, does not call beginDelayedInit() (which would restart SM2).\r\n * @return {object} soundManager The soundManager instance.\r\n */\r\n\r\n this.reboot = function(resetEvents, excludeInit) {\r\n\r\n // reset some (or all) state, and re-init unless otherwise specified.\r\n\r\n // <d>\r\n if (sm2.soundIDs.length) {\r\n sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound object' + (sm2.soundIDs.length !== 1 ? 's' : '') + '...');\r\n }\r\n // </d>\r\n\r\n var i, j, k;\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n sm2.sounds[sm2.soundIDs[i]].destruct();\r\n }\r\n\r\n // trash ze flash (remove from the DOM)\r\n\r\n if (flash) {\r\n\r\n try {\r\n\r\n if (isIE) {\r\n oRemovedHTML = flash.innerHTML;\r\n }\r\n\r\n oRemoved = flash.parentNode.removeChild(flash);\r\n\r\n } catch(e) {\r\n\r\n // Remove failed? May be due to flash blockers silently removing the SWF object/embed node from the DOM. Warn and continue.\r\n\r\n _wDS('badRemove', 2);\r\n\r\n }\r\n\r\n }\r\n\r\n // actually, force recreate of movie.\r\n\r\n oRemovedHTML = oRemoved = needsFlash = flash = null;\r\n\r\n sm2.enabled = didDCLoaded = didInit = waitingForEI = initPending = didAppend = appendSuccess = disabled = useGlobalHTML5Audio = sm2.swfLoaded = false;\r\n\r\n sm2.soundIDs = [];\r\n sm2.sounds = {};\r\n\r\n idCounter = 0;\r\n didSetup = false;\r\n\r\n if (!resetEvents) {\r\n // reset callbacks for onready, ontimeout etc. so that they will fire again on re-init\r\n for (i in on_queue) {\r\n if (on_queue.hasOwnProperty(i)) {\r\n for (j = 0, k = on_queue[i].length; j < k; j++) {\r\n on_queue[i][j].fired = false;\r\n }\r\n }\r\n }\r\n } else {\r\n // remove all callbacks entirely\r\n on_queue = [];\r\n }\r\n\r\n // <d>\r\n if (!excludeInit) {\r\n sm2._wD(sm + ': Rebooting...');\r\n }\r\n // </d>\r\n\r\n // reset HTML5 and flash canPlay test results\r\n\r\n sm2.html5 = {\r\n usingFlash: null\r\n };\r\n\r\n sm2.flash = {};\r\n\r\n // reset device-specific HTML/flash mode switches\r\n\r\n sm2.html5Only = false;\r\n sm2.ignoreFlash = false;\r\n\r\n window.setTimeout(function() {\r\n\r\n // by default, re-init\r\n\r\n if (!excludeInit) {\r\n sm2.beginDelayedInit();\r\n }\r\n\r\n }, 20);\r\n\r\n return sm2;\r\n\r\n };\r\n\r\n this.reset = function() {\r\n\r\n /**\r\n * Shuts down and restores the SoundManager instance to its original loaded state, without an explicit reboot. All onready/ontimeout handlers are removed.\r\n * After this call, SM2 may be re-initialized via soundManager.beginDelayedInit().\r\n * @return {object} soundManager The soundManager instance.\r\n */\r\n\r\n _wDS('reset');\r\n\r\n return sm2.reboot(true, true);\r\n\r\n };\r\n\r\n /**\r\n * Undocumented: Determines the SM2 flash movie's load progress.\r\n *\r\n * @return {number or null} Percent loaded, or if invalid/unsupported, null.\r\n */\r\n\r\n this.getMoviePercent = function() {\r\n\r\n /**\r\n * Interesting syntax notes...\r\n * Flash/ExternalInterface (ActiveX/NPAPI) bridge methods are not typeof \"function\" nor instanceof Function, but are still valid.\r\n * Furthermore, using (flash && flash.PercentLoaded) causes IE to throw \"object doesn't support this property or method\".\r\n * Thus, 'in' syntax must be used.\r\n */\r\n\r\n return (flash && 'PercentLoaded' in flash ? flash.PercentLoaded() : null);\r\n\r\n };\r\n\r\n /**\r\n * Additional helper for manually invoking SM2's init process after DOM Ready / window.onload().\r\n */\r\n\r\n this.beginDelayedInit = function() {\r\n\r\n windowLoaded = true;\r\n domContentLoaded();\r\n\r\n setTimeout(function() {\r\n\r\n if (initPending) return false;\r\n\r\n createMovie();\r\n initMovie();\r\n initPending = true;\r\n\r\n return true;\r\n\r\n }, 20);\r\n\r\n delayWaitForEI();\r\n\r\n };\r\n\r\n /**\r\n * Destroys the SoundManager instance and all SMSound instances.\r\n */\r\n\r\n this.destruct = function() {\r\n\r\n sm2._wD(sm + '.destruct()');\r\n sm2.disable(true);\r\n\r\n };\r\n\r\n /**\r\n * SMSound() (sound object) constructor\r\n * ------------------------------------\r\n *\r\n * @param {object} oOptions Sound options (id and url are required attributes)\r\n * @return {SMSound} The new SMSound object\r\n */\r\n\r\n SMSound = function(oOptions) {\r\n\r\n var s = this, resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, onPositionItems = [], onPositionFired = 0, detachOnPosition, applyFromTo, lastURL = null, lastHTML5State, urlOmitted;\r\n\r\n lastHTML5State = {\r\n // tracks duration + position (time)\r\n duration: null,\r\n time: null\r\n };\r\n\r\n this.id = oOptions.id;\r\n\r\n // legacy\r\n this.sID = this.id;\r\n\r\n this.url = oOptions.url;\r\n this.options = mixin(oOptions);\r\n\r\n // per-play-instance-specific options\r\n this.instanceOptions = this.options;\r\n\r\n // short alias\r\n this._iO = this.instanceOptions;\r\n\r\n // assign property defaults\r\n this.pan = this.options.pan;\r\n this.volume = this.options.volume;\r\n\r\n // whether or not this object is using HTML5\r\n this.isHTML5 = false;\r\n\r\n // internal HTML5 Audio() object reference\r\n this._a = null;\r\n\r\n // for flash 8 special-case createSound() without url, followed by load/play with url case\r\n urlOmitted = (!this.url);\r\n\r\n /**\r\n * SMSound() public methods\r\n * ------------------------\r\n */\r\n\r\n this.id3 = {};\r\n\r\n /**\r\n * Writes SMSound object parameters to debug console\r\n */\r\n\r\n this._debug = function() {\r\n\r\n // <d>\r\n sm2._wD(s.id + ': Merged options:', s.options);\r\n // </d>\r\n\r\n };\r\n\r\n /**\r\n * Begins loading a sound per its *url*.\r\n *\r\n * @param {object} options Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.load = function(options) {\r\n\r\n var oSound = null, instanceOptions;\r\n\r\n if (options !== _undefined) {\r\n s._iO = mixin(options, s.options);\r\n } else {\r\n options = s.options;\r\n s._iO = options;\r\n if (lastURL && lastURL !== s.url) {\r\n _wDS('manURL');\r\n s._iO.url = s.url;\r\n s.url = null;\r\n }\r\n }\r\n\r\n if (!s._iO.url) {\r\n s._iO.url = s.url;\r\n }\r\n\r\n s._iO.url = parseURL(s._iO.url);\r\n\r\n // ensure we're in sync\r\n s.instanceOptions = s._iO;\r\n\r\n // local shortcut\r\n instanceOptions = s._iO;\r\n\r\n sm2._wD(s.id + ': load (' + instanceOptions.url + ')');\r\n\r\n if (!instanceOptions.url && !s.url) {\r\n sm2._wD(s.id + ': load(): url is unassigned. Exiting.', 2);\r\n return s;\r\n }\r\n\r\n // <d>\r\n if (!s.isHTML5 && fV === 8 && !s.url && !instanceOptions.autoPlay) {\r\n // flash 8 load() -> play() won't work before onload has fired.\r\n sm2._wD(s.id + ': Flash 8 load() limitation: Wait for onload() before calling play().', 1);\r\n }\r\n // </d>\r\n\r\n if (instanceOptions.url === s.url && s.readyState !== 0 && s.readyState !== 2) {\r\n _wDS('onURL', 1);\r\n // if loaded and an onload() exists, fire immediately.\r\n if (s.readyState === 3 && instanceOptions.onload) {\r\n // assume success based on truthy duration.\r\n wrapCallback(s, function() {\r\n instanceOptions.onload.apply(s, [(!!s.duration)]);\r\n });\r\n }\r\n return s;\r\n }\r\n\r\n // reset a few state properties\r\n\r\n s.loaded = false;\r\n s.readyState = 1;\r\n s.playState = 0;\r\n s.id3 = {};\r\n\r\n // TODO: If switching from HTML5 -> flash (or vice versa), stop currently-playing audio.\r\n\r\n if (html5OK(instanceOptions)) {\r\n\r\n oSound = s._setup_html5(instanceOptions);\r\n\r\n if (!oSound._called_load) {\r\n\r\n s._html5_canplay = false;\r\n\r\n // TODO: review called_load / html5_canplay logic\r\n\r\n // if url provided directly to load(), assign it here.\r\n\r\n if (s.url !== instanceOptions.url) {\r\n\r\n sm2._wD(_wDS('manURL') + ': ' + instanceOptions.url);\r\n\r\n s._a.src = instanceOptions.url;\r\n\r\n // TODO: review / re-apply all relevant options (volume, loop, onposition etc.)\r\n\r\n // reset position for new URL\r\n s.setPosition(0);\r\n\r\n }\r\n\r\n // given explicit load call, try to preload.\r\n\r\n // early HTML5 implementation (non-standard)\r\n s._a.autobuffer = 'auto';\r\n\r\n // standard property, values: none / metadata / auto\r\n // reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx\r\n s._a.preload = 'auto';\r\n\r\n s._a._called_load = true;\r\n\r\n } else {\r\n\r\n sm2._wD(s.id + ': Ignoring request to load again');\r\n\r\n }\r\n\r\n } else {\r\n\r\n if (sm2.html5Only) {\r\n sm2._wD(s.id + ': No flash support. Exiting.');\r\n return s;\r\n }\r\n\r\n if (s._iO.url && s._iO.url.match(/data:/i)) {\r\n // data: URIs not supported by Flash, either.\r\n sm2._wD(s.id + ': data: URIs not supported via Flash. Exiting.');\r\n return s;\r\n }\r\n\r\n try {\r\n s.isHTML5 = false;\r\n s._iO = policyFix(loopFix(instanceOptions));\r\n // if we have \"position\", disable auto-play as we'll be seeking to that position at onload().\r\n if (s._iO.autoPlay && (s._iO.position || s._iO.from)) {\r\n sm2._wD(s.id + ': Disabling autoPlay because of non-zero offset case');\r\n s._iO.autoPlay = false;\r\n }\r\n // re-assign local shortcut\r\n instanceOptions = s._iO;\r\n if (fV === 8) {\r\n flash._load(s.id, instanceOptions.url, instanceOptions.stream, instanceOptions.autoPlay, instanceOptions.usePolicyFile);\r\n } else {\r\n flash._load(s.id, instanceOptions.url, !!(instanceOptions.stream), !!(instanceOptions.autoPlay), instanceOptions.loops || 1, !!(instanceOptions.autoLoad), instanceOptions.usePolicyFile);\r\n }\r\n } catch(e) {\r\n _wDS('smError', 2);\r\n debugTS('onload', false);\r\n catchError({\r\n type: 'SMSOUND_LOAD_JS_EXCEPTION',\r\n fatal: true\r\n });\r\n }\r\n\r\n }\r\n\r\n // after all of this, ensure sound url is up to date.\r\n s.url = instanceOptions.url;\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unloads a sound, canceling any open HTTP requests.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.unload = function() {\r\n\r\n // Flash 8/AS2 can't \"close\" a stream - fake it by loading an empty URL\r\n // Flash 9/AS3: Close stream, preventing further load\r\n // HTML5: Most UAs will use empty URL\r\n\r\n if (s.readyState !== 0) {\r\n\r\n sm2._wD(s.id + ': unload()');\r\n\r\n if (!s.isHTML5) {\r\n\r\n if (fV === 8) {\r\n flash._unload(s.id, emptyURL);\r\n } else {\r\n flash._unload(s.id);\r\n }\r\n\r\n } else {\r\n\r\n stop_html5_timer();\r\n\r\n if (s._a) {\r\n\r\n s._a.pause();\r\n\r\n // update empty URL, too\r\n lastURL = html5Unload(s._a);\r\n\r\n }\r\n\r\n }\r\n\r\n // reset load/status flags\r\n resetProperties();\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unloads and destroys a sound.\r\n */\r\n\r\n this.destruct = function(_bFromSM) {\r\n\r\n sm2._wD(s.id + ': Destruct');\r\n\r\n if (!s.isHTML5) {\r\n\r\n // kill sound within Flash\r\n // Disable the onfailure handler\r\n s._iO.onfailure = null;\r\n flash._destroySound(s.id);\r\n\r\n } else {\r\n\r\n stop_html5_timer();\r\n\r\n if (s._a) {\r\n s._a.pause();\r\n html5Unload(s._a);\r\n if (!useGlobalHTML5Audio) {\r\n remove_html5_events();\r\n }\r\n // break obvious circular reference\r\n s._a._s = null;\r\n s._a = null;\r\n }\r\n\r\n }\r\n\r\n if (!_bFromSM) {\r\n // ensure deletion from controller\r\n sm2.destroySound(s.id, true);\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Begins playing a sound.\r\n *\r\n * @param {object} options Optional: Sound options\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.play = function(options, _updatePlayState) {\r\n\r\n var fN, allowMulti, a, onready,\r\n audioClone, onended, oncanplay,\r\n startOK = true;\r\n\r\n // <d>\r\n fN = s.id + ': play(): ';\r\n // </d>\r\n\r\n // default to true\r\n _updatePlayState = (_updatePlayState === _undefined ? true : _updatePlayState);\r\n\r\n if (!options) {\r\n options = {};\r\n }\r\n\r\n // first, use local URL (if specified)\r\n if (s.url) {\r\n s._iO.url = s.url;\r\n }\r\n\r\n // mix in any options defined at createSound()\r\n s._iO = mixin(s._iO, s.options);\r\n\r\n // mix in any options specific to this method\r\n s._iO = mixin(options, s._iO);\r\n\r\n s._iO.url = parseURL(s._iO.url);\r\n\r\n s.instanceOptions = s._iO;\r\n\r\n // RTMP-only\r\n if (!s.isHTML5 && s._iO.serverURL && !s.connected) {\r\n if (!s.getAutoPlay()) {\r\n sm2._wD(fN + ' Netstream not connected yet - setting autoPlay');\r\n s.setAutoPlay(true);\r\n }\r\n // play will be called in onconnect()\r\n return s;\r\n }\r\n\r\n if (html5OK(s._iO)) {\r\n s._setup_html5(s._iO);\r\n start_html5_timer();\r\n }\r\n\r\n if (s.playState === 1 && !s.paused) {\r\n\r\n allowMulti = s._iO.multiShot;\r\n\r\n if (!allowMulti) {\r\n\r\n sm2._wD(fN + 'Already playing (one-shot)', 1);\r\n\r\n if (s.isHTML5) {\r\n // go back to original position.\r\n s.setPosition(s._iO.position);\r\n }\r\n\r\n return s;\r\n\r\n }\r\n\r\n sm2._wD(fN + 'Already playing (multi-shot)', 1);\r\n\r\n }\r\n\r\n // edge case: play() with explicit URL parameter\r\n if (options.url && options.url !== s.url) {\r\n\r\n // special case for createSound() followed by load() / play() with url; avoid double-load case.\r\n if (!s.readyState && !s.isHTML5 && fV === 8 && urlOmitted) {\r\n\r\n urlOmitted = false;\r\n\r\n } else {\r\n\r\n // load using merged options\r\n s.load(s._iO);\r\n\r\n }\r\n\r\n }\r\n\r\n if (!s.loaded) {\r\n\r\n if (s.readyState === 0) {\r\n\r\n sm2._wD(fN + 'Attempting to load');\r\n\r\n // try to get this sound playing ASAP\r\n if (!s.isHTML5 && !sm2.html5Only) {\r\n\r\n // flash: assign directly because setAutoPlay() increments the instanceCount\r\n s._iO.autoPlay = true;\r\n s.load(s._iO);\r\n\r\n } else if (s.isHTML5) {\r\n\r\n // iOS needs this when recycling sounds, loading a new URL on an existing object.\r\n s.load(s._iO);\r\n\r\n } else {\r\n\r\n sm2._wD(fN + 'Unsupported type. Exiting.');\r\n\r\n return s;\r\n\r\n }\r\n\r\n // HTML5 hack - re-set instanceOptions?\r\n s.instanceOptions = s._iO;\r\n\r\n } else if (s.readyState === 2) {\r\n\r\n sm2._wD(fN + 'Could not load - exiting', 2);\r\n\r\n return s;\r\n\r\n } else {\r\n\r\n sm2._wD(fN + 'Loading - attempting to play...');\r\n\r\n }\r\n\r\n } else {\r\n\r\n // \"play()\"\r\n sm2._wD(fN.substr(0, fN.lastIndexOf(':')));\r\n\r\n }\r\n\r\n if (!s.isHTML5 && fV === 9 && s.position > 0 && s.position === s.duration) {\r\n // flash 9 needs a position reset if play() is called while at the end of a sound.\r\n sm2._wD(fN + 'Sound at end, resetting to position: 0');\r\n options.position = 0;\r\n }\r\n\r\n /**\r\n * Streams will pause when their buffer is full if they are being loaded.\r\n * In this case paused is true, but the song hasn't started playing yet.\r\n * If we just call resume() the onplay() callback will never be called.\r\n * So only call resume() if the position is > 0.\r\n * Another reason is because options like volume won't have been applied yet.\r\n * For normal sounds, just resume.\r\n */\r\n\r\n if (s.paused && s.position >= 0 && (!s._iO.serverURL || s.position > 0)) {\r\n\r\n // https://gist.github.com/37b17df75cc4d7a90bf6\r\n sm2._wD(fN + 'Resuming from paused state', 1);\r\n s.resume();\r\n\r\n } else {\r\n\r\n s._iO = mixin(options, s._iO);\r\n\r\n /**\r\n * Preload in the event of play() with position under Flash,\r\n * or from/to parameters and non-RTMP case\r\n */\r\n if (((!s.isHTML5 && s._iO.position !== null && s._iO.position > 0) || (s._iO.from !== null && s._iO.from > 0) || s._iO.to !== null) && s.instanceCount === 0 && s.playState === 0 && !s._iO.serverURL) {\r\n\r\n onready = function() {\r\n // sound \"canplay\" or onload()\r\n // re-apply position/from/to to instance options, and start playback\r\n s._iO = mixin(options, s._iO);\r\n s.play(s._iO);\r\n };\r\n\r\n // HTML5 needs to at least have \"canplay\" fired before seeking.\r\n if (s.isHTML5 && !s._html5_canplay) {\r\n\r\n // this hasn't been loaded yet. load it first, and then do this again.\r\n sm2._wD(fN + 'Beginning load for non-zero offset case');\r\n\r\n s.load({\r\n // note: custom HTML5-only event added for from/to implementation.\r\n _oncanplay: onready\r\n });\r\n\r\n } else if (!s.isHTML5 && !s.loaded && (!s.readyState || s.readyState !== 2)) {\r\n\r\n // to be safe, preload the whole thing in Flash.\r\n\r\n sm2._wD(fN + 'Preloading for non-zero offset case');\r\n\r\n s.load({\r\n onload: onready\r\n });\r\n\r\n }\r\n\r\n // otherwise, we're ready to go. re-apply local options, and continue\r\n\r\n s._iO = applyFromTo();\r\n\r\n }\r\n\r\n // sm2._wD(fN + 'Starting to play');\r\n\r\n // increment instance counter, where enabled + supported\r\n if (!s.instanceCount || s._iO.multiShotEvents || (s.isHTML5 && s._iO.multiShot && !useGlobalHTML5Audio) || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) {\r\n s.instanceCount++;\r\n }\r\n\r\n // if first play and onposition parameters exist, apply them now\r\n if (s._iO.onposition && s.playState === 0) {\r\n attachOnPosition(s);\r\n }\r\n\r\n s.playState = 1;\r\n s.paused = false;\r\n\r\n s.position = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position : 0);\r\n\r\n if (!s.isHTML5) {\r\n s._iO = policyFix(loopFix(s._iO));\r\n }\r\n\r\n if (s._iO.onplay && _updatePlayState) {\r\n s._iO.onplay.apply(s);\r\n onplay_called = true;\r\n }\r\n\r\n s.setVolume(s._iO.volume, true);\r\n s.setPan(s._iO.pan, true);\r\n\r\n if (s._iO.playbackRate !== 1) {\r\n s.setPlaybackRate(s._iO.playbackRate);\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / msecScale), s._iO.multiShot || false);\r\n\r\n if (fV === 9 && !startOK) {\r\n // edge case: no sound hardware, or 32-channel flash ceiling hit.\r\n // applies only to Flash 9, non-NetStream/MovieStar sounds.\r\n // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play%28%29\r\n sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit', 2);\r\n if (s._iO.onplayerror) {\r\n s._iO.onplayerror.apply(s);\r\n }\r\n\r\n }\r\n\r\n } else if (s.instanceCount < 2) {\r\n\r\n // HTML5 single-instance case\r\n\r\n start_html5_timer();\r\n\r\n a = s._setup_html5();\r\n\r\n s.setPosition(s._iO.position);\r\n\r\n a.play();\r\n\r\n } else {\r\n\r\n // HTML5 multi-shot case\r\n\r\n sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...');\r\n\r\n audioClone = new Audio(s._iO.url);\r\n\r\n onended = function() {\r\n event.remove(audioClone, 'ended', onended);\r\n s._onfinish(s);\r\n // cleanup\r\n html5Unload(audioClone);\r\n audioClone = null;\r\n };\r\n\r\n oncanplay = function() {\r\n event.remove(audioClone, 'canplay', oncanplay);\r\n try {\r\n audioClone.currentTime = s._iO.position / msecScale;\r\n } catch(err) {\r\n complain(s.id + ': multiShot play() failed to apply position of ' + (s._iO.position / msecScale));\r\n }\r\n audioClone.play();\r\n };\r\n\r\n event.add(audioClone, 'ended', onended);\r\n\r\n // apply volume to clones, too\r\n if (s._iO.volume !== _undefined) {\r\n audioClone.volume = Math.max(0, Math.min(1, s._iO.volume / 100));\r\n }\r\n\r\n // playing multiple muted sounds? if you do this, you're weird ;) - but let's cover it.\r\n if (s.muted) {\r\n audioClone.muted = true;\r\n }\r\n\r\n if (s._iO.position) {\r\n // HTML5 audio can't seek before onplay() event has fired.\r\n // wait for canplay, then seek to position and start playback.\r\n event.add(audioClone, 'canplay', oncanplay);\r\n } else {\r\n // begin playback at currentTime: 0\r\n audioClone.play();\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n // just for convenience\r\n this.start = this.play;\r\n\r\n /**\r\n * Stops playing a sound (and optionally, all sounds)\r\n *\r\n * @param {boolean} bAll Optional: Whether to stop all sounds\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.stop = function(bAll) {\r\n\r\n var instanceOptions = s._iO,\r\n originalPosition;\r\n\r\n if (s.playState === 1) {\r\n\r\n sm2._wD(s.id + ': stop()');\r\n\r\n s._onbufferchange(0);\r\n s._resetOnPosition(0);\r\n s.paused = false;\r\n\r\n if (!s.isHTML5) {\r\n s.playState = 0;\r\n }\r\n\r\n // remove onPosition listeners, if any\r\n detachOnPosition();\r\n\r\n // and \"to\" position, if set\r\n if (instanceOptions.to) {\r\n s.clearOnPosition(instanceOptions.to);\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n flash._stop(s.id, bAll);\r\n\r\n // hack for netStream: just unload\r\n if (instanceOptions.serverURL) {\r\n s.unload();\r\n }\r\n\r\n } else if (s._a) {\r\n\r\n originalPosition = s.position;\r\n\r\n // act like Flash, though\r\n s.setPosition(0);\r\n\r\n // hack: reflect old position for onstop() (also like Flash)\r\n s.position = originalPosition;\r\n\r\n // html5 has no stop()\r\n // NOTE: pausing means iOS requires interaction to resume.\r\n s._a.pause();\r\n\r\n s.playState = 0;\r\n\r\n // and update UI\r\n s._onTimer();\r\n\r\n stop_html5_timer();\r\n\r\n }\r\n\r\n s.instanceCount = 0;\r\n s._iO = {};\r\n\r\n if (instanceOptions.onstop) {\r\n instanceOptions.onstop.apply(s);\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Undocumented/internal: Sets autoPlay for RTMP.\r\n *\r\n * @param {boolean} autoPlay state\r\n */\r\n\r\n this.setAutoPlay = function(autoPlay) {\r\n\r\n sm2._wD(s.id + ': Autoplay turned ' + (autoPlay ? 'on' : 'off'));\r\n s._iO.autoPlay = autoPlay;\r\n\r\n if (!s.isHTML5) {\r\n flash._setAutoPlay(s.id, autoPlay);\r\n if (autoPlay) {\r\n // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP)\r\n if (!s.instanceCount && s.readyState === 1) {\r\n s.instanceCount++;\r\n sm2._wD(s.id + ': Incremented instance count to ' + s.instanceCount);\r\n }\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Undocumented/internal: Returns the autoPlay boolean.\r\n *\r\n * @return {boolean} The current autoPlay value\r\n */\r\n\r\n this.getAutoPlay = function() {\r\n\r\n return s._iO.autoPlay;\r\n\r\n };\r\n\r\n /**\r\n * Sets the playback rate of a sound (HTML5-only.)\r\n *\r\n * @param {number} playbackRate (+/-)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPlaybackRate = function(playbackRate) {\r\n\r\n // Per Mozilla, limit acceptable values to prevent playback from stopping (unless allowOverride is truthy.)\r\n // https://developer.mozilla.org/en-US/Apps/Build/Audio_and_video_delivery/WebAudio_playbackRate_explained\r\n var normalizedRate = Math.max(0.5, Math.min(4, playbackRate));\r\n\r\n // <d>\r\n if (normalizedRate !== playbackRate) {\r\n sm2._wD(s.id + ': setPlaybackRate(' + playbackRate + '): limiting rate to ' + normalizedRate, 2);\r\n }\r\n // </d>\r\n\r\n if (s.isHTML5) {\r\n try {\r\n s._iO.playbackRate = normalizedRate;\r\n s._a.playbackRate = normalizedRate;\r\n } catch(e) {\r\n sm2._wD(s.id + ': setPlaybackRate(' + normalizedRate + ') failed: ' + e.message, 2);\r\n }\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the position of a sound.\r\n *\r\n * @param {number} nMsecOffset Position (milliseconds)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPosition = function(nMsecOffset) {\r\n\r\n if (nMsecOffset === _undefined) {\r\n nMsecOffset = 0;\r\n }\r\n\r\n var position, position1K,\r\n // Use the duration from the instance options, if we don't have a track duration yet.\r\n // position >= 0 and <= current available (loaded) duration\r\n offset = (s.isHTML5 ? Math.max(nMsecOffset, 0) : Math.min(s.duration || s._iO.duration, Math.max(nMsecOffset, 0)));\r\n\r\n s.position = offset;\r\n position1K = s.position / msecScale;\r\n s._resetOnPosition(s.position);\r\n s._iO.position = offset;\r\n\r\n if (!s.isHTML5) {\r\n\r\n position = (fV === 9 ? s.position : position1K);\r\n\r\n if (s.readyState && s.readyState !== 2) {\r\n // if paused or not playing, will not resume (by playing)\r\n flash._setPosition(s.id, position, (s.paused || !s.playState), s._iO.multiShot);\r\n }\r\n\r\n } else if (s._a) {\r\n\r\n // Set the position in the canplay handler if the sound is not ready yet\r\n if (s._html5_canplay) {\r\n\r\n if (s._a.currentTime.toFixed(3) !== position1K.toFixed(3)) {\r\n\r\n /**\r\n * DOM/JS errors/exceptions to watch out for:\r\n * if seek is beyond (loaded?) position, \"DOM exception 11\"\r\n * \"INDEX_SIZE_ERR\": DOM exception 1\r\n */\r\n sm2._wD(s.id + ': setPosition(' + position1K + ')');\r\n\r\n try {\r\n s._a.currentTime = position1K;\r\n if (s.playState === 0 || s.paused) {\r\n // allow seek without auto-play/resume\r\n s._a.pause();\r\n }\r\n } catch(e) {\r\n sm2._wD(s.id + ': setPosition(' + position1K + ') failed: ' + e.message, 2);\r\n }\r\n\r\n }\r\n\r\n } else if (position1K) {\r\n\r\n // warn on non-zero seek attempts\r\n sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready', 2);\r\n return s;\r\n\r\n }\r\n\r\n if (s.paused) {\r\n\r\n // if paused, refresh UI right away by forcing update\r\n s._onTimer(true);\r\n\r\n }\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Pauses sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.pause = function(_bCallFlash) {\r\n\r\n if (s.paused || (s.playState === 0 && s.readyState !== 1)) return s;\r\n\r\n sm2._wD(s.id + ': pause()');\r\n s.paused = true;\r\n\r\n if (!s.isHTML5) {\r\n if (_bCallFlash || _bCallFlash === _undefined) {\r\n flash._pause(s.id, s._iO.multiShot);\r\n }\r\n } else {\r\n s._setup_html5().pause();\r\n stop_html5_timer();\r\n }\r\n\r\n if (s._iO.onpause) {\r\n s._iO.onpause.apply(s);\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Resumes sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n /**\r\n * When auto-loaded streams pause on buffer full they have a playState of 0.\r\n * We need to make sure that the playState is set to 1 when these streams \"resume\".\r\n * When a paused stream is resumed, we need to trigger the onplay() callback if it\r\n * hasn't been called already. In this case since the sound is being played for the\r\n * first time, I think it's more appropriate to call onplay() rather than onresume().\r\n */\r\n\r\n this.resume = function() {\r\n\r\n var instanceOptions = s._iO;\r\n\r\n if (!s.paused) return s;\r\n\r\n sm2._wD(s.id + ': resume()');\r\n s.paused = false;\r\n s.playState = 1;\r\n\r\n if (!s.isHTML5) {\r\n\r\n if (instanceOptions.isMovieStar && !instanceOptions.serverURL) {\r\n // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition.\r\n s.setPosition(s.position);\r\n }\r\n\r\n // flash method is toggle-based (pause/resume)\r\n flash._pause(s.id, instanceOptions.multiShot);\r\n\r\n } else {\r\n\r\n s._setup_html5().play();\r\n start_html5_timer();\r\n\r\n }\r\n\r\n if (!onplay_called && instanceOptions.onplay) {\r\n\r\n instanceOptions.onplay.apply(s);\r\n onplay_called = true;\r\n\r\n } else if (instanceOptions.onresume) {\r\n\r\n instanceOptions.onresume.apply(s);\r\n\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Toggles sound playback.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.togglePause = function() {\r\n\r\n sm2._wD(s.id + ': togglePause()');\r\n\r\n if (s.playState === 0) {\r\n s.play({\r\n position: (fV === 9 && !s.isHTML5 ? s.position : s.position / msecScale)\r\n });\r\n return s;\r\n }\r\n\r\n if (s.paused) {\r\n s.resume();\r\n } else {\r\n s.pause();\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the panning (L-R) effect.\r\n *\r\n * @param {number} nPan The pan value (-100 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setPan = function(nPan, bInstanceOnly) {\r\n\r\n if (nPan === _undefined) {\r\n nPan = 0;\r\n }\r\n\r\n if (bInstanceOnly === _undefined) {\r\n bInstanceOnly = false;\r\n }\r\n\r\n if (!s.isHTML5) {\r\n flash._setPan(s.id, nPan);\r\n } // else { no HTML5 pan? }\r\n\r\n s._iO.pan = nPan;\r\n\r\n if (!bInstanceOnly) {\r\n s.pan = nPan;\r\n s.options.pan = nPan;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Sets the volume.\r\n *\r\n * @param {number} nVol The volume value (0 to 100)\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.setVolume = function(nVol, _bInstanceOnly) {\r\n\r\n /**\r\n * Note: Setting volume has no effect on iOS \"special snowflake\" devices.\r\n * Hardware volume control overrides software, and volume\r\n * will always return 1 per Apple docs. (iOS 4 + 5.)\r\n * http://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingSoundtoCanvasAnimations/AddingSoundtoCanvasAnimations.html\r\n */\r\n\r\n if (nVol === _undefined) {\r\n nVol = 100;\r\n }\r\n\r\n if (_bInstanceOnly === _undefined) {\r\n _bInstanceOnly = false;\r\n }\r\n\r\n if (!s.isHTML5) {\r\n\r\n flash._setVolume(s.id, (sm2.muted && !s.muted) || s.muted ? 0 : nVol);\r\n\r\n } else if (s._a) {\r\n\r\n if (sm2.muted && !s.muted) {\r\n s.muted = true;\r\n s._a.muted = true;\r\n }\r\n\r\n // valid range for native HTML5 Audio(): 0-1\r\n s._a.volume = Math.max(0, Math.min(1, nVol / 100));\r\n\r\n }\r\n\r\n s._iO.volume = nVol;\r\n\r\n if (!_bInstanceOnly) {\r\n s.volume = nVol;\r\n s.options.volume = nVol;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Mutes the sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.mute = function() {\r\n\r\n s.muted = true;\r\n\r\n if (!s.isHTML5) {\r\n flash._setVolume(s.id, 0);\r\n } else if (s._a) {\r\n s._a.muted = true;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Unmutes the sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.unmute = function() {\r\n\r\n s.muted = false;\r\n var hasIO = (s._iO.volume !== _undefined);\r\n\r\n if (!s.isHTML5) {\r\n flash._setVolume(s.id, hasIO ? s._iO.volume : s.options.volume);\r\n } else if (s._a) {\r\n s._a.muted = false;\r\n }\r\n\r\n return s;\r\n\r\n };\r\n\r\n /**\r\n * Toggles the muted state of a sound.\r\n *\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.toggleMute = function() {\r\n\r\n return (s.muted ? s.unmute() : s.mute());\r\n\r\n };\r\n\r\n /**\r\n * Registers a callback to be fired when a sound reaches a given position during playback.\r\n *\r\n * @param {number} nPosition The position to watch for\r\n * @param {function} oMethod The relevant callback to fire\r\n * @param {object} oScope Optional: The scope to apply the callback to\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.onPosition = function(nPosition, oMethod, oScope) {\r\n\r\n // TODO: basic dupe checking?\r\n\r\n onPositionItems.push({\r\n position: parseInt(nPosition, 10),\r\n method: oMethod,\r\n scope: (oScope !== _undefined ? oScope : s),\r\n fired: false\r\n });\r\n\r\n return s;\r\n\r\n };\r\n\r\n // legacy/backwards-compability: lower-case method name\r\n this.onposition = this.onPosition;\r\n\r\n /**\r\n * Removes registered callback(s) from a sound, by position and/or callback.\r\n *\r\n * @param {number} nPosition The position to clear callback(s) for\r\n * @param {function} oMethod Optional: Identify one callback to be removed when multiple listeners exist for one position\r\n * @return {SMSound} The SMSound object\r\n */\r\n\r\n this.clearOnPosition = function(nPosition, oMethod) {\r\n\r\n var i;\r\n\r\n nPosition = parseInt(nPosition, 10);\r\n\r\n if (isNaN(nPosition)) {\r\n // safety check\r\n return;\r\n }\r\n\r\n for (i = 0; i < onPositionItems.length; i++) {\r\n\r\n if (nPosition === onPositionItems[i].position) {\r\n // remove this item if no method was specified, or, if the method matches\r\n\r\n if (!oMethod || (oMethod === onPositionItems[i].method)) {\r\n\r\n if (onPositionItems[i].fired) {\r\n // decrement \"fired\" counter, too\r\n onPositionFired--;\r\n }\r\n\r\n onPositionItems.splice(i, 1);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._processOnPosition = function() {\r\n\r\n var i, item, j = onPositionItems.length;\r\n\r\n if (!j || !s.playState || onPositionFired >= j) return false;\r\n\r\n for (i = j - 1; i >= 0; i--) {\r\n\r\n item = onPositionItems[i];\r\n\r\n if (!item.fired && s.position >= item.position) {\r\n\r\n item.fired = true;\r\n onPositionFired++;\r\n item.method.apply(item.scope, [item.position]);\r\n\r\n // reset j -- onPositionItems.length can be changed in the item callback above... occasionally breaking the loop.\r\n j = onPositionItems.length;\r\n\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._resetOnPosition = function(nPosition) {\r\n\r\n // reset \"fired\" for items interested in this position\r\n var i, item, j = onPositionItems.length;\r\n\r\n if (!j) return false;\r\n\r\n for (i = j - 1; i >= 0; i--) {\r\n\r\n item = onPositionItems[i];\r\n\r\n if (item.fired && nPosition <= item.position) {\r\n item.fired = false;\r\n onPositionFired--;\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * SMSound() private internals\r\n * --------------------------------\r\n */\r\n\r\n applyFromTo = function() {\r\n\r\n var instanceOptions = s._iO,\r\n f = instanceOptions.from,\r\n t = instanceOptions.to,\r\n start, end;\r\n\r\n end = function() {\r\n\r\n // end has been reached.\r\n sm2._wD(s.id + ': \"To\" time of ' + t + ' reached.');\r\n\r\n // detach listener\r\n s.clearOnPosition(t, end);\r\n\r\n // stop should clear this, too\r\n s.stop();\r\n\r\n };\r\n\r\n start = function() {\r\n\r\n sm2._wD(s.id + ': Playing \"from\" ' + f);\r\n\r\n // add listener for end\r\n if (t !== null && !isNaN(t)) {\r\n s.onPosition(t, end);\r\n }\r\n\r\n };\r\n\r\n if (f !== null && !isNaN(f)) {\r\n\r\n // apply to instance options, guaranteeing correct start position.\r\n instanceOptions.position = f;\r\n\r\n // multiShot timing can't be tracked, so prevent that.\r\n instanceOptions.multiShot = false;\r\n\r\n start();\r\n\r\n }\r\n\r\n // return updated instanceOptions including starting position\r\n return instanceOptions;\r\n\r\n };\r\n\r\n attachOnPosition = function() {\r\n\r\n var item,\r\n op = s._iO.onposition;\r\n\r\n // attach onposition things, if any, now.\r\n\r\n if (op) {\r\n\r\n for (item in op) {\r\n if (op.hasOwnProperty(item)) {\r\n s.onPosition(parseInt(item, 10), op[item]);\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n detachOnPosition = function() {\r\n\r\n var item,\r\n op = s._iO.onposition;\r\n\r\n // detach any onposition()-style listeners.\r\n\r\n if (op) {\r\n\r\n for (item in op) {\r\n if (op.hasOwnProperty(item)) {\r\n s.clearOnPosition(parseInt(item, 10));\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n start_html5_timer = function() {\r\n\r\n if (s.isHTML5) {\r\n startTimer(s);\r\n }\r\n\r\n };\r\n\r\n stop_html5_timer = function() {\r\n\r\n if (s.isHTML5) {\r\n stopTimer(s);\r\n }\r\n\r\n };\r\n\r\n resetProperties = function(retainPosition) {\r\n\r\n if (!retainPosition) {\r\n onPositionItems = [];\r\n onPositionFired = 0;\r\n }\r\n\r\n onplay_called = false;\r\n\r\n s._hasTimer = null;\r\n s._a = null;\r\n s._html5_canplay = false;\r\n s.bytesLoaded = null;\r\n s.bytesTotal = null;\r\n s.duration = (s._iO && s._iO.duration ? s._iO.duration : null);\r\n s.durationEstimate = null;\r\n s.buffered = [];\r\n\r\n // legacy: 1D array\r\n s.eqData = [];\r\n\r\n s.eqData.left = [];\r\n s.eqData.right = [];\r\n\r\n s.failures = 0;\r\n s.isBuffering = false;\r\n s.instanceOptions = {};\r\n s.instanceCount = 0;\r\n s.loaded = false;\r\n s.metadata = {};\r\n\r\n // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success\r\n s.readyState = 0;\r\n\r\n s.muted = false;\r\n s.paused = false;\r\n\r\n s.peakData = {\r\n left: 0,\r\n right: 0\r\n };\r\n\r\n s.waveformData = {\r\n left: [],\r\n right: []\r\n };\r\n\r\n s.playState = 0;\r\n s.position = null;\r\n\r\n s.id3 = {};\r\n\r\n };\r\n\r\n resetProperties();\r\n\r\n /**\r\n * Pseudo-private SMSound internals\r\n * --------------------------------\r\n */\r\n\r\n this._onTimer = function(bForce) {\r\n\r\n /**\r\n * HTML5-only _whileplaying() etc.\r\n * called from both HTML5 native events, and polling/interval-based timers\r\n * mimics flash and fires only when time/duration change, so as to be polling-friendly\r\n */\r\n\r\n var duration, isNew = false, time, x = {};\r\n\r\n if (s._hasTimer || bForce) {\r\n\r\n // TODO: May not need to track readyState (1 = loading)\r\n\r\n if (s._a && (bForce || ((s.playState > 0 || s.readyState === 1) && !s.paused))) {\r\n\r\n duration = s._get_html5_duration();\r\n\r\n if (duration !== lastHTML5State.duration) {\r\n\r\n lastHTML5State.duration = duration;\r\n s.duration = duration;\r\n isNew = true;\r\n\r\n }\r\n\r\n // TODO: investigate why this goes wack if not set/re-set each time.\r\n s.durationEstimate = s.duration;\r\n\r\n time = (s._a.currentTime * msecScale || 0);\r\n\r\n if (time !== lastHTML5State.time) {\r\n\r\n lastHTML5State.time = time;\r\n isNew = true;\r\n\r\n }\r\n\r\n if (isNew || bForce) {\r\n\r\n s._whileplaying(time, x, x, x, x);\r\n\r\n }\r\n\r\n }/* else {\r\n\r\n // sm2._wD('_onTimer: Warn for \"'+s.id+'\": '+(!s._a?'Could not find element. ':'')+(s.playState === 0?'playState bad, 0?':'playState = '+s.playState+', OK'));\r\n\r\n return false;\r\n\r\n }*/\r\n\r\n }\r\n\r\n return isNew;\r\n\r\n };\r\n\r\n this._get_html5_duration = function() {\r\n\r\n var instanceOptions = s._iO,\r\n // if audio object exists, use its duration - else, instance option duration (if provided - it's a hack, really, and should be retired) OR null\r\n d = (s._a && s._a.duration ? s._a.duration * msecScale : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)),\r\n result = (d && !isNaN(d) && d !== Infinity ? d : null);\r\n\r\n return result;\r\n\r\n };\r\n\r\n this._apply_loop = function(a, nLoops) {\r\n\r\n /**\r\n * boolean instead of \"loop\", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop\r\n * note that loop is either off or infinite under HTML5, unlike Flash which allows arbitrary loop counts to be specified.\r\n */\r\n\r\n // <d>\r\n if (!a.loop && nLoops > 1) {\r\n sm2._wD('Note: Native HTML5 looping is infinite.', 1);\r\n }\r\n // </d>\r\n\r\n a.loop = (nLoops > 1 ? 'loop' : '');\r\n\r\n };\r\n\r\n this._setup_html5 = function(options) {\r\n\r\n var instanceOptions = mixin(s._iO, options),\r\n a = useGlobalHTML5Audio ? globalHTML5Audio : s._a,\r\n dURL = decodeURI(instanceOptions.url),\r\n sameURL;\r\n\r\n /**\r\n * \"First things first, I, Poppa...\" (reset the previous state of the old sound, if playing)\r\n * Fixes case with devices that can only play one sound at a time\r\n * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state\r\n */\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n if (dURL === decodeURI(lastGlobalHTML5URL)) {\r\n // global HTML5 audio: re-use of URL\r\n sameURL = true;\r\n }\r\n\r\n } else if (dURL === decodeURI(lastURL)) {\r\n\r\n // options URL is the same as the \"last\" URL, and we used (loaded) it\r\n sameURL = true;\r\n\r\n }\r\n\r\n if (a) {\r\n\r\n if (a._s) {\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n if (a._s && a._s.playState && !sameURL) {\r\n\r\n // global HTML5 audio case, and loading a new URL. stop the currently-playing one.\r\n a._s.stop();\r\n\r\n }\r\n\r\n } else if (!useGlobalHTML5Audio && dURL === decodeURI(lastURL)) {\r\n\r\n // non-global HTML5 reuse case: same url, ignore request\r\n s._apply_loop(a, instanceOptions.loops);\r\n\r\n return a;\r\n\r\n }\r\n\r\n }\r\n\r\n if (!sameURL) {\r\n\r\n // don't retain onPosition() stuff with new URLs.\r\n\r\n if (lastURL) {\r\n resetProperties(false);\r\n }\r\n\r\n // assign new HTML5 URL\r\n\r\n a.src = instanceOptions.url;\r\n\r\n s.url = instanceOptions.url;\r\n\r\n lastURL = instanceOptions.url;\r\n\r\n lastGlobalHTML5URL = instanceOptions.url;\r\n\r\n a._called_load = false;\r\n\r\n }\r\n\r\n } else {\r\n\r\n if (instanceOptions.autoLoad || instanceOptions.autoPlay) {\r\n\r\n s._a = new Audio(instanceOptions.url);\r\n s._a.load();\r\n\r\n } else {\r\n\r\n // null for stupid Opera 9.64 case\r\n s._a = (isOpera && opera.version() < 10 ? new Audio(null) : new Audio());\r\n\r\n }\r\n\r\n // assign local reference\r\n a = s._a;\r\n\r\n a._called_load = false;\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n globalHTML5Audio = a;\r\n\r\n }\r\n\r\n }\r\n\r\n s.isHTML5 = true;\r\n\r\n // store a ref on the track\r\n s._a = a;\r\n\r\n // store a ref on the audio\r\n a._s = s;\r\n\r\n add_html5_events();\r\n\r\n s._apply_loop(a, instanceOptions.loops);\r\n\r\n if (instanceOptions.autoLoad || instanceOptions.autoPlay) {\r\n\r\n s.load();\r\n\r\n } else {\r\n\r\n // early HTML5 implementation (non-standard)\r\n a.autobuffer = false;\r\n\r\n // standard ('none' is also an option.)\r\n a.preload = 'auto';\r\n\r\n }\r\n\r\n return a;\r\n\r\n };\r\n\r\n add_html5_events = function() {\r\n\r\n if (s._a._added_events) return false;\r\n\r\n var f;\r\n\r\n function add(oEvt, oFn, bCapture) {\r\n return s._a ? s._a.addEventListener(oEvt, oFn, bCapture || false) : null;\r\n }\r\n\r\n s._a._added_events = true;\r\n\r\n for (f in html5_events) {\r\n if (html5_events.hasOwnProperty(f)) {\r\n add(f, html5_events[f]);\r\n }\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n remove_html5_events = function() {\r\n\r\n // Remove event listeners\r\n\r\n var f;\r\n\r\n function remove(oEvt, oFn, bCapture) {\r\n return (s._a ? s._a.removeEventListener(oEvt, oFn, bCapture || false) : null);\r\n }\r\n\r\n sm2._wD(s.id + ': Removing event listeners');\r\n s._a._added_events = false;\r\n\r\n for (f in html5_events) {\r\n if (html5_events.hasOwnProperty(f)) {\r\n remove(f, html5_events[f]);\r\n }\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Pseudo-private event internals\r\n * ------------------------------\r\n */\r\n\r\n this._onload = function(nSuccess) {\r\n\r\n var fN,\r\n // check for duration to prevent false positives from flash 8 when loading from cache.\r\n loadOK = !!nSuccess || (!s.isHTML5 && fV === 8 && s.duration);\r\n\r\n // <d>\r\n fN = s.id + ': ';\r\n sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load / invalid sound?' + (!s.duration ? ' Zero-length duration reported.' : ' -') + ' (' + s.url + ')'), (loadOK ? 1 : 2));\r\n\r\n if (!loadOK && !s.isHTML5) {\r\n if (sm2.sandbox.noRemote === true) {\r\n sm2._wD(fN + str('noNet'), 1);\r\n }\r\n if (sm2.sandbox.noLocal === true) {\r\n sm2._wD(fN + str('noLocal'), 1);\r\n }\r\n }\r\n // </d>\r\n\r\n s.loaded = loadOK;\r\n s.readyState = (loadOK ? 3 : 2);\r\n s._onbufferchange(0);\r\n\r\n if (!loadOK && !s.isHTML5) {\r\n // note: no error code from Flash.\r\n s._onerror();\r\n }\r\n\r\n if (s._iO.onload) {\r\n wrapCallback(s, function() {\r\n s._iO.onload.apply(s, [loadOK]);\r\n });\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._onerror = function(errorCode, description) {\r\n\r\n // https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes\r\n if (s._iO.onerror) {\r\n wrapCallback(s, function() {\r\n s._iO.onerror.apply(s, [errorCode, description]);\r\n });\r\n }\r\n\r\n };\r\n\r\n this._onbufferchange = function(nIsBuffering) {\r\n\r\n // ignore if not playing\r\n if (s.playState === 0) return false;\r\n\r\n if ((nIsBuffering && s.isBuffering) || (!nIsBuffering && !s.isBuffering)) return false;\r\n\r\n s.isBuffering = (nIsBuffering === 1);\r\n\r\n if (s._iO.onbufferchange) {\r\n sm2._wD(s.id + ': Buffer state change: ' + nIsBuffering);\r\n s._iO.onbufferchange.apply(s, [nIsBuffering]);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * Playback may have stopped due to buffering, or related reason.\r\n * This state can be encountered on iOS < 6 when auto-play is blocked.\r\n */\r\n\r\n this._onsuspend = function() {\r\n\r\n if (s._iO.onsuspend) {\r\n sm2._wD(s.id + ': Playback suspended');\r\n s._iO.onsuspend.apply(s);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n /**\r\n * flash 9/movieStar + RTMP-only method, should fire only once at most\r\n * at this point we just recreate failed sounds rather than trying to reconnect\r\n */\r\n\r\n this._onfailure = function(msg, level, code) {\r\n\r\n s.failures++;\r\n sm2._wD(s.id + ': Failure (' + s.failures + '): ' + msg);\r\n\r\n if (s._iO.onfailure && s.failures === 1) {\r\n s._iO.onfailure(msg, level, code);\r\n } else {\r\n sm2._wD(s.id + ': Ignoring failure');\r\n }\r\n\r\n };\r\n\r\n /**\r\n * flash 9/movieStar + RTMP-only method for unhandled warnings/exceptions from Flash\r\n * e.g., RTMP \"method missing\" warning (non-fatal) for getStreamLength on server\r\n */\r\n\r\n this._onwarning = function(msg, level, code) {\r\n\r\n if (s._iO.onwarning) {\r\n s._iO.onwarning(msg, level, code);\r\n }\r\n\r\n };\r\n\r\n this._onfinish = function() {\r\n\r\n // store local copy before it gets trashed...\r\n var io_onfinish = s._iO.onfinish;\r\n\r\n s._onbufferchange(0);\r\n s._resetOnPosition(0);\r\n\r\n // reset some state items\r\n if (s.instanceCount) {\r\n\r\n s.instanceCount--;\r\n\r\n if (!s.instanceCount) {\r\n\r\n // remove onPosition listeners, if any\r\n detachOnPosition();\r\n\r\n // reset instance options\r\n s.playState = 0;\r\n s.paused = false;\r\n s.instanceCount = 0;\r\n s.instanceOptions = {};\r\n s._iO = {};\r\n stop_html5_timer();\r\n\r\n // reset position, too\r\n if (s.isHTML5) {\r\n s.position = 0;\r\n }\r\n\r\n }\r\n\r\n if (!s.instanceCount || s._iO.multiShotEvents) {\r\n // fire onfinish for last, or every instance\r\n if (io_onfinish) {\r\n sm2._wD(s.id + ': onfinish()');\r\n wrapCallback(s, function() {\r\n io_onfinish.apply(s);\r\n });\r\n }\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) {\r\n\r\n var instanceOptions = s._iO;\r\n\r\n s.bytesLoaded = nBytesLoaded;\r\n s.bytesTotal = nBytesTotal;\r\n s.duration = Math.floor(nDuration);\r\n s.bufferLength = nBufferLength;\r\n\r\n if (!s.isHTML5 && !instanceOptions.isMovieStar) {\r\n\r\n if (instanceOptions.duration) {\r\n // use duration from options, if specified and larger. nobody should be specifying duration in options, actually, and it should be retired.\r\n s.durationEstimate = (s.duration > instanceOptions.duration) ? s.duration : instanceOptions.duration;\r\n } else {\r\n s.durationEstimate = parseInt((s.bytesTotal / s.bytesLoaded) * s.duration, 10);\r\n }\r\n\r\n } else {\r\n\r\n s.durationEstimate = s.duration;\r\n\r\n }\r\n\r\n // for flash, reflect sequential-load-style buffering\r\n if (!s.isHTML5) {\r\n s.buffered = [{\r\n start: 0,\r\n end: s.duration\r\n }];\r\n }\r\n\r\n // allow whileloading to fire even if \"load\" fired under HTML5, due to HTTP range/partials\r\n if ((s.readyState !== 3 || s.isHTML5) && instanceOptions.whileloading) {\r\n instanceOptions.whileloading.apply(s);\r\n }\r\n\r\n };\r\n\r\n this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) {\r\n\r\n var instanceOptions = s._iO,\r\n eqLeft;\r\n\r\n // flash safety net\r\n if (isNaN(nPosition) || nPosition === null) return false;\r\n\r\n // Safari HTML5 play() may return small -ve values when starting from position: 0, eg. -50.120396875. Unexpected/invalid per W3, I think. Normalize to 0.\r\n s.position = Math.max(0, nPosition);\r\n\r\n s._processOnPosition();\r\n\r\n if (!s.isHTML5 && fV > 8) {\r\n\r\n if (instanceOptions.usePeakData && oPeakData !== _undefined && oPeakData) {\r\n s.peakData = {\r\n left: oPeakData.leftPeak,\r\n right: oPeakData.rightPeak\r\n };\r\n }\r\n\r\n if (instanceOptions.useWaveformData && oWaveformDataLeft !== _undefined && oWaveformDataLeft) {\r\n s.waveformData = {\r\n left: oWaveformDataLeft.split(','),\r\n right: oWaveformDataRight.split(',')\r\n };\r\n }\r\n\r\n if (instanceOptions.useEQData) {\r\n if (oEQData !== _undefined && oEQData && oEQData.leftEQ) {\r\n eqLeft = oEQData.leftEQ.split(',');\r\n s.eqData = eqLeft;\r\n s.eqData.left = eqLeft;\r\n if (oEQData.rightEQ !== _undefined && oEQData.rightEQ) {\r\n s.eqData.right = oEQData.rightEQ.split(',');\r\n }\r\n }\r\n }\r\n\r\n }\r\n\r\n if (s.playState === 1) {\r\n\r\n // special case/hack: ensure buffering is false if loading from cache (and not yet started)\r\n if (!s.isHTML5 && fV === 8 && !s.position && s.isBuffering) {\r\n s._onbufferchange(0);\r\n }\r\n\r\n if (instanceOptions.whileplaying) {\r\n // flash may call after actual finish\r\n instanceOptions.whileplaying.apply(s);\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n this._oncaptiondata = function(oData) {\r\n\r\n /**\r\n * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature\r\n *\r\n * @param {object} oData\r\n */\r\n\r\n sm2._wD(s.id + ': Caption data received.');\r\n\r\n s.captiondata = oData;\r\n\r\n if (s._iO.oncaptiondata) {\r\n s._iO.oncaptiondata.apply(s, [oData]);\r\n }\r\n\r\n };\r\n\r\n this._onmetadata = function(oMDProps, oMDData) {\r\n\r\n /**\r\n * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature\r\n * RTMP may include song title, MovieStar content may include encoding info\r\n *\r\n * @param {array} oMDProps (names)\r\n * @param {array} oMDData (values)\r\n */\r\n\r\n sm2._wD(s.id + ': Metadata received.');\r\n\r\n var oData = {}, i, j;\r\n\r\n for (i = 0, j = oMDProps.length; i < j; i++) {\r\n oData[oMDProps[i]] = oMDData[i];\r\n }\r\n\r\n s.metadata = oData;\r\n\r\n if (s._iO.onmetadata) {\r\n s._iO.onmetadata.call(s, s.metadata);\r\n }\r\n\r\n };\r\n\r\n this._onid3 = function(oID3Props, oID3Data) {\r\n\r\n /**\r\n * internal: flash 8 + flash 9 ID3 feature\r\n * may include artist, song title etc.\r\n *\r\n * @param {array} oID3Props (names)\r\n * @param {array} oID3Data (values)\r\n */\r\n\r\n sm2._wD(s.id + ': ID3 data received.');\r\n\r\n var oData = [], i, j;\r\n\r\n for (i = 0, j = oID3Props.length; i < j; i++) {\r\n oData[oID3Props[i]] = oID3Data[i];\r\n }\r\n\r\n s.id3 = mixin(s.id3, oData);\r\n\r\n if (s._iO.onid3) {\r\n s._iO.onid3.apply(s);\r\n }\r\n\r\n };\r\n\r\n // flash/RTMP-only\r\n\r\n this._onconnect = function(bSuccess) {\r\n\r\n bSuccess = (bSuccess === 1);\r\n sm2._wD(s.id + ': ' + (bSuccess ? 'Connected.' : 'Failed to connect? - ' + s.url), (bSuccess ? 1 : 2));\r\n s.connected = bSuccess;\r\n\r\n if (bSuccess) {\r\n\r\n s.failures = 0;\r\n\r\n if (idCheck(s.id)) {\r\n if (s.getAutoPlay()) {\r\n // only update the play state if auto playing\r\n s.play(_undefined, s.getAutoPlay());\r\n } else if (s._iO.autoLoad) {\r\n s.load();\r\n }\r\n }\r\n\r\n if (s._iO.onconnect) {\r\n s._iO.onconnect.apply(s, [bSuccess]);\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n this._ondataerror = function(sError) {\r\n\r\n // flash 9 wave/eq data handler\r\n // hack: called at start, and end from flash at/after onfinish()\r\n if (s.playState > 0) {\r\n sm2._wD(s.id + ': Data error: ' + sError);\r\n if (s._iO.ondataerror) {\r\n s._iO.ondataerror.apply(s);\r\n }\r\n }\r\n\r\n };\r\n\r\n // <d>\r\n this._debug();\r\n // </d>\r\n\r\n }; // SMSound()\r\n\r\n /**\r\n * Private SoundManager internals\r\n * ------------------------------\r\n */\r\n\r\n getDocument = function() {\r\n\r\n return (doc.body || doc.getElementsByTagName('div')[0]);\r\n\r\n };\r\n\r\n id = function(sID) {\r\n\r\n return doc.getElementById(sID);\r\n\r\n };\r\n\r\n mixin = function(oMain, oAdd) {\r\n\r\n // non-destructive merge\r\n var o1 = (oMain || {}), o2, o;\r\n\r\n // if unspecified, o2 is the default options object\r\n o2 = (oAdd === _undefined ? sm2.defaultOptions : oAdd);\r\n\r\n for (o in o2) {\r\n\r\n if (o2.hasOwnProperty(o) && o1[o] === _undefined) {\r\n\r\n if (typeof o2[o] !== 'object' || o2[o] === null) {\r\n\r\n // assign directly\r\n o1[o] = o2[o];\r\n\r\n } else {\r\n\r\n // recurse through o2\r\n o1[o] = mixin(o1[o], o2[o]);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return o1;\r\n\r\n };\r\n\r\n wrapCallback = function(oSound, callback) {\r\n\r\n /**\r\n * 03/03/2013: Fix for Flash Player 11.6.602.171 + Flash 8 (flashVersion = 8) SWF issue\r\n * setTimeout() fix for certain SMSound callbacks like onload() and onfinish(), where subsequent calls like play() and load() fail when Flash Player 11.6.602.171 is installed, and using soundManager with flashVersion = 8 (which is the default).\r\n * Not sure of exact cause. Suspect race condition and/or invalid (NaN-style) position argument trickling down to the next JS -> Flash _start() call, in the play() case.\r\n * Fix: setTimeout() to yield, plus safer null / NaN checking on position argument provided to Flash.\r\n * https://getsatisfaction.com/schillmania/topics/recent_chrome_update_seems_to_have_broken_my_sm2_audio_player\r\n */\r\n if (!oSound.isHTML5 && fV === 8) {\r\n window.setTimeout(callback, 0);\r\n } else {\r\n callback();\r\n }\r\n\r\n };\r\n\r\n // additional soundManager properties that soundManager.setup() will accept\r\n\r\n extraOptions = {\r\n onready: 1,\r\n ontimeout: 1,\r\n defaultOptions: 1,\r\n flash9Options: 1,\r\n movieStarOptions: 1\r\n };\r\n\r\n assign = function(o, oParent) {\r\n\r\n /**\r\n * recursive assignment of properties, soundManager.setup() helper\r\n * allows property assignment based on whitelist\r\n */\r\n\r\n var i,\r\n result = true,\r\n hasParent = (oParent !== _undefined),\r\n setupOptions = sm2.setupOptions,\r\n bonusOptions = extraOptions;\r\n\r\n // <d>\r\n\r\n // if soundManager.setup() called, show accepted parameters.\r\n\r\n if (o === _undefined) {\r\n\r\n result = [];\r\n\r\n for (i in setupOptions) {\r\n\r\n if (setupOptions.hasOwnProperty(i)) {\r\n result.push(i);\r\n }\r\n\r\n }\r\n\r\n for (i in bonusOptions) {\r\n\r\n if (bonusOptions.hasOwnProperty(i)) {\r\n\r\n if (typeof sm2[i] === 'object') {\r\n result.push(i + ': {...}');\r\n } else if (sm2[i] instanceof Function) {\r\n result.push(i + ': function() {...}');\r\n } else {\r\n result.push(i);\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n sm2._wD(str('setup', result.join(', ')));\r\n\r\n return false;\r\n\r\n }\r\n\r\n // </d>\r\n\r\n for (i in o) {\r\n\r\n if (o.hasOwnProperty(i)) {\r\n\r\n // if not an {object} we want to recurse through...\r\n\r\n if (typeof o[i] !== 'object' || o[i] === null || o[i] instanceof Array || o[i] instanceof RegExp) {\r\n\r\n // check \"allowed\" options\r\n\r\n if (hasParent && bonusOptions[oParent] !== _undefined) {\r\n\r\n // valid recursive / nested object option, eg., { defaultOptions: { volume: 50 } }\r\n sm2[oParent][i] = o[i];\r\n\r\n } else if (setupOptions[i] !== _undefined) {\r\n\r\n // special case: assign to setupOptions object, which soundManager property references\r\n sm2.setupOptions[i] = o[i];\r\n\r\n // assign directly to soundManager, too\r\n sm2[i] = o[i];\r\n\r\n } else if (bonusOptions[i] === _undefined) {\r\n\r\n // invalid or disallowed parameter. complain.\r\n complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2);\r\n\r\n result = false;\r\n\r\n } else if (sm2[i] instanceof Function) {\r\n\r\n /**\r\n * valid extraOptions (bonusOptions) parameter.\r\n * is it a method, like onready/ontimeout? call it.\r\n * multiple parameters should be in an array, eg. soundManager.setup({onready: [myHandler, myScope]});\r\n */\r\n sm2[i].apply(sm2, (o[i] instanceof Array ? o[i] : [o[i]]));\r\n\r\n } else {\r\n\r\n // good old-fashioned direct assignment\r\n sm2[i] = o[i];\r\n\r\n }\r\n\r\n } else if (bonusOptions[i] === _undefined) {\r\n\r\n // recursion case, eg., { defaultOptions: { ... } }\r\n\r\n // invalid or disallowed parameter. complain.\r\n complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2);\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n // recurse through object\r\n return assign(o[i], i);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n function preferFlashCheck(kind) {\r\n\r\n // whether flash should play a given type\r\n return (sm2.preferFlash && hasFlash && !sm2.ignoreFlash && (sm2.flash[kind] !== _undefined && sm2.flash[kind]));\r\n\r\n }\r\n\r\n /**\r\n * Internal DOM2-level event helpers\r\n * ---------------------------------\r\n */\r\n\r\n event = (function() {\r\n\r\n // normalize event methods\r\n var old = (window.attachEvent),\r\n evt = {\r\n add: (old ? 'attachEvent' : 'addEventListener'),\r\n remove: (old ? 'detachEvent' : 'removeEventListener')\r\n };\r\n\r\n // normalize \"on\" event prefix, optional capture argument\r\n function getArgs(oArgs) {\r\n\r\n var args = slice.call(oArgs),\r\n len = args.length;\r\n\r\n if (old) {\r\n // prefix\r\n args[1] = 'on' + args[1];\r\n if (len > 3) {\r\n // no capture\r\n args.pop();\r\n }\r\n } else if (len === 3) {\r\n args.push(false);\r\n }\r\n\r\n return args;\r\n\r\n }\r\n\r\n function apply(args, sType) {\r\n\r\n // normalize and call the event method, with the proper arguments\r\n var element = args.shift(),\r\n method = [evt[sType]];\r\n\r\n if (old) {\r\n // old IE can't do apply().\r\n element[method](args[0], args[1]);\r\n } else {\r\n element[method].apply(element, args);\r\n }\r\n\r\n }\r\n\r\n function add() {\r\n apply(getArgs(arguments), 'add');\r\n }\r\n\r\n function remove() {\r\n apply(getArgs(arguments), 'remove');\r\n }\r\n\r\n return {\r\n add: add,\r\n remove: remove\r\n };\r\n\r\n }());\r\n\r\n /**\r\n * Internal HTML5 event handling\r\n * -----------------------------\r\n */\r\n\r\n function html5_event(oFn) {\r\n\r\n // wrap html5 event handlers so we don't call them on destroyed and/or unloaded sounds\r\n\r\n return function(e) {\r\n\r\n var s = this._s,\r\n result;\r\n\r\n if (!s || !s._a) {\r\n // <d>\r\n if (s && s.id) {\r\n sm2._wD(s.id + ': Ignoring ' + e.type);\r\n } else {\r\n sm2._wD(h5 + 'Ignoring ' + e.type);\r\n }\r\n // </d>\r\n result = null;\r\n } else {\r\n result = oFn.call(this, e);\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n }\r\n\r\n html5_events = {\r\n\r\n // HTML5 event-name-to-handler map\r\n\r\n abort: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': abort');\r\n\r\n }),\r\n\r\n // enough has loaded to play\r\n\r\n canplay: html5_event(function() {\r\n\r\n var s = this._s,\r\n position1K;\r\n\r\n if (s._html5_canplay) {\r\n // this event has already fired. ignore.\r\n return;\r\n }\r\n\r\n s._html5_canplay = true;\r\n sm2._wD(s.id + ': canplay');\r\n s._onbufferchange(0);\r\n\r\n // position according to instance options\r\n position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position / msecScale : null);\r\n\r\n // set the position if position was provided before the sound loaded\r\n if (this.currentTime !== position1K) {\r\n sm2._wD(s.id + ': canplay: Setting position to ' + position1K);\r\n try {\r\n this.currentTime = position1K;\r\n } catch(ee) {\r\n sm2._wD(s.id + ': canplay: Setting position of ' + position1K + ' failed: ' + ee.message, 2);\r\n }\r\n }\r\n\r\n // hack for HTML5 from/to case\r\n if (s._iO._oncanplay) {\r\n s._iO._oncanplay();\r\n }\r\n\r\n }),\r\n\r\n canplaythrough: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n if (!s.loaded) {\r\n s._onbufferchange(0);\r\n s._whileloading(s.bytesLoaded, s.bytesTotal, s._get_html5_duration());\r\n s._onload(true);\r\n }\r\n\r\n }),\r\n\r\n durationchange: html5_event(function() {\r\n\r\n // durationchange may fire at various times, probably the safest way to capture accurate/final duration.\r\n\r\n var s = this._s,\r\n duration;\r\n\r\n duration = s._get_html5_duration();\r\n\r\n if (!isNaN(duration) && duration !== s.duration) {\r\n\r\n sm2._wD(this._s.id + ': durationchange (' + duration + ')' + (s.duration ? ', previously ' + s.duration : ''));\r\n\r\n s.durationEstimate = s.duration = duration;\r\n\r\n }\r\n\r\n }),\r\n\r\n // TODO: Reserved for potential use\r\n /*\r\n emptied: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': emptied');\r\n\r\n }),\r\n */\r\n\r\n ended: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n sm2._wD(s.id + ': ended');\r\n\r\n s._onfinish();\r\n\r\n }),\r\n\r\n error: html5_event(function() {\r\n\r\n var description = (html5ErrorCodes[this.error.code] || null);\r\n sm2._wD(this._s.id + ': HTML5 error, code ' + this.error.code + (description ? ' (' + description + ')' : ''));\r\n this._s._onload(false);\r\n this._s._onerror(this.error.code, description);\r\n\r\n }),\r\n\r\n loadeddata: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n sm2._wD(s.id + ': loadeddata');\r\n\r\n // safari seems to nicely report progress events, eventually totalling 100%\r\n if (!s._loaded && !isSafari) {\r\n s.duration = s._get_html5_duration();\r\n }\r\n\r\n }),\r\n\r\n loadedmetadata: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': loadedmetadata');\r\n\r\n }),\r\n\r\n loadstart: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': loadstart');\r\n // assume buffering at first\r\n this._s._onbufferchange(1);\r\n\r\n }),\r\n\r\n play: html5_event(function() {\r\n\r\n // sm2._wD(this._s.id + ': play()');\r\n // once play starts, no buffering\r\n this._s._onbufferchange(0);\r\n\r\n }),\r\n\r\n playing: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': playing ' + String.fromCharCode(9835));\r\n // once play starts, no buffering\r\n this._s._onbufferchange(0);\r\n\r\n }),\r\n\r\n progress: html5_event(function(e) {\r\n\r\n // note: can fire repeatedly after \"loaded\" event, due to use of HTTP range/partials\r\n\r\n var s = this._s,\r\n i, j, progStr, buffered = 0,\r\n isProgress = (e.type === 'progress'),\r\n ranges = e.target.buffered,\r\n // firefox 3.6 implements e.loaded/total (bytes)\r\n loaded = (e.loaded || 0),\r\n total = (e.total || 1);\r\n\r\n // reset the \"buffered\" (loaded byte ranges) array\r\n s.buffered = [];\r\n\r\n if (ranges && ranges.length) {\r\n\r\n // if loaded is 0, try TimeRanges implementation as % of load\r\n // https://developer.mozilla.org/en/DOM/TimeRanges\r\n\r\n // re-build \"buffered\" array\r\n // HTML5 returns seconds. SM2 API uses msec for setPosition() etc., whether Flash or HTML5.\r\n for (i = 0, j = ranges.length; i < j; i++) {\r\n s.buffered.push({\r\n start: ranges.start(i) * msecScale,\r\n end: ranges.end(i) * msecScale\r\n });\r\n }\r\n\r\n // use the last value locally\r\n buffered = (ranges.end(0) - ranges.start(0)) * msecScale;\r\n\r\n // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges\r\n loaded = Math.min(1, buffered / (e.target.duration * msecScale));\r\n\r\n // <d>\r\n if (isProgress && ranges.length > 1) {\r\n progStr = [];\r\n j = ranges.length;\r\n for (i = 0; i < j; i++) {\r\n progStr.push((e.target.buffered.start(i) * msecScale) + '-' + (e.target.buffered.end(i) * msecScale));\r\n }\r\n sm2._wD(this._s.id + ': progress, timeRanges: ' + progStr.join(', '));\r\n }\r\n\r\n if (isProgress && !isNaN(loaded)) {\r\n sm2._wD(this._s.id + ': progress, ' + Math.floor(loaded * 100) + '% loaded');\r\n }\r\n // </d>\r\n\r\n }\r\n\r\n if (!isNaN(loaded)) {\r\n\r\n // TODO: prevent calls with duplicate values.\r\n s._whileloading(loaded, total, s._get_html5_duration());\r\n if (loaded && total && loaded === total) {\r\n // in case \"onload\" doesn't fire (eg. gecko 1.9.2)\r\n html5_events.canplaythrough.call(this, e);\r\n }\r\n\r\n }\r\n\r\n }),\r\n\r\n ratechange: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': ratechange');\r\n\r\n }),\r\n\r\n suspend: html5_event(function(e) {\r\n\r\n // download paused/stopped, may have finished (eg. onload)\r\n var s = this._s;\r\n\r\n sm2._wD(this._s.id + ': suspend');\r\n html5_events.progress.call(this, e);\r\n s._onsuspend();\r\n\r\n }),\r\n\r\n stalled: html5_event(function() {\r\n\r\n sm2._wD(this._s.id + ': stalled');\r\n\r\n }),\r\n\r\n timeupdate: html5_event(function() {\r\n\r\n this._s._onTimer();\r\n\r\n }),\r\n\r\n waiting: html5_event(function() {\r\n\r\n var s = this._s;\r\n\r\n // see also: seeking\r\n sm2._wD(this._s.id + ': waiting');\r\n\r\n // playback faster than download rate, etc.\r\n s._onbufferchange(1);\r\n\r\n })\r\n\r\n };\r\n\r\n html5OK = function(iO) {\r\n\r\n // playability test based on URL or MIME type\r\n\r\n var result;\r\n\r\n if (!iO || (!iO.type && !iO.url && !iO.serverURL)) {\r\n\r\n // nothing to check\r\n result = false;\r\n\r\n } else if (iO.serverURL || (iO.type && preferFlashCheck(iO.type))) {\r\n\r\n // RTMP, or preferring flash\r\n result = false;\r\n\r\n } else {\r\n\r\n // Use type, if specified. Pass data: URIs to HTML5. If HTML5-only mode, no other options, so just give 'er\r\n result = ((iO.type ? html5CanPlay({ type: iO.type }) : html5CanPlay({ url: iO.url }) || sm2.html5Only || iO.url.match(/data:/i)));\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n html5Unload = function(oAudio) {\r\n\r\n /**\r\n * Internal method: Unload media, and cancel any current/pending network requests.\r\n * Firefox can load an empty URL, which allegedly destroys the decoder and stops the download.\r\n * https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media\r\n * However, Firefox has been seen loading a relative URL from '' and thus requesting the hosting page on unload.\r\n * Other UA behaviour is unclear, so everyone else gets an about:blank-style URL.\r\n */\r\n\r\n var url;\r\n\r\n if (oAudio) {\r\n\r\n // Firefox and Chrome accept short WAVe data: URIs. Chome dislikes audio/wav, but accepts audio/wav for data: MIME.\r\n // Desktop Safari complains / fails on data: URI, so it gets about:blank.\r\n url = (isSafari ? emptyURL : (sm2.html5.canPlayType('audio/wav') ? emptyWAV : emptyURL));\r\n\r\n oAudio.src = url;\r\n\r\n // reset some state, too\r\n if (oAudio._called_unload !== _undefined) {\r\n oAudio._called_load = false;\r\n }\r\n\r\n }\r\n\r\n if (useGlobalHTML5Audio) {\r\n\r\n // ensure URL state is trashed, also\r\n lastGlobalHTML5URL = null;\r\n\r\n }\r\n\r\n return url;\r\n\r\n };\r\n\r\n html5CanPlay = function(o) {\r\n\r\n /**\r\n * Try to find MIME, test and return truthiness\r\n * o = {\r\n * url: '/path/to/an.mp3',\r\n * type: 'audio/mp3'\r\n * }\r\n */\r\n\r\n if (!sm2.useHTML5Audio || !sm2.hasHTML5) return false;\r\n\r\n var url = (o.url || null),\r\n mime = (o.type || null),\r\n aF = sm2.audioFormats,\r\n result,\r\n offset,\r\n fileExt,\r\n item;\r\n\r\n // account for known cases like audio/mp3\r\n\r\n if (mime && sm2.html5[mime] !== _undefined) return (sm2.html5[mime] && !preferFlashCheck(mime));\r\n\r\n if (!html5Ext) {\r\n\r\n html5Ext = [];\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n html5Ext.push(item);\r\n\r\n if (aF[item].related) {\r\n html5Ext = html5Ext.concat(aF[item].related);\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n html5Ext = new RegExp('\\\\.(' + html5Ext.join('|') + ')(\\\\?.*)?$', 'i');\r\n\r\n }\r\n\r\n // TODO: Strip URL queries, etc.\r\n fileExt = (url ? url.toLowerCase().match(html5Ext) : null);\r\n\r\n if (!fileExt || !fileExt.length) {\r\n\r\n if (!mime) {\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n // audio/mp3 -> mp3, result should be known\r\n offset = mime.indexOf(';');\r\n\r\n // strip \"audio/X; codecs...\"\r\n fileExt = (offset !== -1 ? mime.substr(0, offset) : mime).substr(6);\r\n\r\n }\r\n\r\n } else {\r\n\r\n // match the raw extension name - \"mp3\", for example\r\n fileExt = fileExt[1];\r\n\r\n }\r\n\r\n if (fileExt && sm2.html5[fileExt] !== _undefined) {\r\n\r\n // result known\r\n result = (sm2.html5[fileExt] && !preferFlashCheck(fileExt));\r\n\r\n } else {\r\n\r\n mime = 'audio/' + fileExt;\r\n result = sm2.html5.canPlayType({ type: mime });\r\n\r\n sm2.html5[fileExt] = result;\r\n\r\n // sm2._wD('canPlayType, found result: ' + result);\r\n result = (result && sm2.html5[mime] && !preferFlashCheck(mime));\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n testHTML5 = function() {\r\n\r\n /**\r\n * Internal: Iterates over audioFormats, determining support eg. audio/mp3, audio/mpeg and so on\r\n * assigns results to html5[] and flash[].\r\n */\r\n\r\n if (!sm2.useHTML5Audio || !sm2.hasHTML5) {\r\n\r\n // without HTML5, we need Flash.\r\n sm2.html5.usingFlash = true;\r\n needsFlash = true;\r\n\r\n return false;\r\n\r\n }\r\n\r\n // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load \"null\" as a URL. :/\r\n var a = (Audio !== _undefined ? (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()) : null),\r\n item, lookup, support = {}, aF, i;\r\n\r\n function cp(m) {\r\n\r\n var canPlay, j,\r\n result = false,\r\n isOK = false;\r\n\r\n if (!a || typeof a.canPlayType !== 'function') return result;\r\n\r\n if (m instanceof Array) {\r\n\r\n // iterate through all mime types, return any successes\r\n\r\n for (i = 0, j = m.length; i < j; i++) {\r\n\r\n if (sm2.html5[m[i]] || a.canPlayType(m[i]).match(sm2.html5Test)) {\r\n\r\n isOK = true;\r\n sm2.html5[m[i]] = true;\r\n\r\n // note flash support, too\r\n sm2.flash[m[i]] = !!(m[i].match(flashMIME));\r\n\r\n }\r\n\r\n }\r\n\r\n result = isOK;\r\n\r\n } else {\r\n\r\n canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false);\r\n result = !!(canPlay && (canPlay.match(sm2.html5Test)));\r\n\r\n }\r\n\r\n return result;\r\n\r\n }\r\n\r\n // test all registered formats + codecs\r\n\r\n aF = sm2.audioFormats;\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n lookup = 'audio/' + item;\r\n\r\n support[item] = cp(aF[item].type);\r\n\r\n // write back generic type too, eg. audio/mp3\r\n support[lookup] = support[item];\r\n\r\n // assign flash\r\n if (item.match(flashMIME)) {\r\n\r\n sm2.flash[item] = true;\r\n sm2.flash[lookup] = true;\r\n\r\n } else {\r\n\r\n sm2.flash[item] = false;\r\n sm2.flash[lookup] = false;\r\n\r\n }\r\n\r\n // assign result to related formats, too\r\n\r\n if (aF[item] && aF[item].related) {\r\n\r\n for (i = aF[item].related.length - 1; i >= 0; i--) {\r\n\r\n // eg. audio/m4a\r\n support['audio/' + aF[item].related[i]] = support[item];\r\n sm2.html5[aF[item].related[i]] = support[item];\r\n sm2.flash[aF[item].related[i]] = support[item];\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n support.canPlayType = (a ? cp : null);\r\n sm2.html5 = mixin(sm2.html5, support);\r\n\r\n sm2.html5.usingFlash = featureCheck();\r\n needsFlash = sm2.html5.usingFlash;\r\n\r\n return true;\r\n\r\n };\r\n\r\n strings = {\r\n\r\n // <d>\r\n notReady: 'Unavailable - wait until onready() has fired.',\r\n notOK: 'Audio support is not available.',\r\n domError: sm + 'exception caught while appending SWF to DOM.',\r\n spcWmode: 'Removing wmode, preventing known SWF loading issue(s)',\r\n swf404: smc + 'Verify that %s is a valid path.',\r\n tryDebug: 'Try ' + sm + '.debugFlash = true for more security details (output goes to SWF.)',\r\n checkSWF: 'See SWF output for more debug info.',\r\n localFail: smc + 'Non-HTTP page (' + doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/',\r\n waitFocus: smc + 'Special case: Waiting for SWF to load with window focus...',\r\n waitForever: smc + 'Waiting indefinitely for Flash (will recover if unblocked)...',\r\n waitSWF: smc + 'Waiting for 100% SWF load...',\r\n needFunction: smc + 'Function object expected for %s',\r\n badID: 'Sound ID \"%s\" should be a string, starting with a non-numeric character',\r\n currentObj: smc + '_debug(): Current sound objects',\r\n waitOnload: smc + 'Waiting for window.onload()',\r\n docLoaded: smc + 'Document already loaded',\r\n onload: smc + 'initComplete(): calling soundManager.onload()',\r\n onloadOK: sm + '.onload() complete',\r\n didInit: smc + 'init(): Already called?',\r\n secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',\r\n badRemove: smc + 'Failed to remove Flash node.',\r\n shutdown: sm + '.disable(): Shutting down',\r\n queue: smc + 'Queueing %s handler',\r\n smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.',\r\n fbTimeout: 'No flash response, applying .' + swfCSS.swfTimedout + ' CSS...',\r\n fbLoaded: 'Flash loaded',\r\n fbHandler: smc + 'flashBlockHandler()',\r\n manURL: 'SMSound.load(): Using manually-assigned URL',\r\n onURL: sm + '.load(): current URL already assigned.',\r\n badFV: sm + '.flashVersion must be 8 or 9. \"%s\" is invalid. Reverting to %s.',\r\n as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)',\r\n noNSLoop: 'Note: Looping not implemented for MovieStar formats',\r\n needfl9: 'Note: Switching to flash 9, required for MP4 formats.',\r\n mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case',\r\n needFlash: smc + 'Fatal error: Flash is needed to play some required formats, but is not available.',\r\n gotFocus: smc + 'Got window focus.',\r\n policy: 'Enabling usePolicyFile for data access',\r\n setup: sm + '.setup(): allowed parameters: %s',\r\n setupError: sm + '.setup(): \"%s\" cannot be assigned with this method.',\r\n setupUndef: sm + '.setup(): Could not find option \"%s\"',\r\n setupLate: sm + '.setup(): url, flashVersion and html5Test property changes will not take effect until reboot().',\r\n noURL: smc + 'Flash URL required. Call soundManager.setup({url:...}) to get started.',\r\n sm2Loaded: 'SoundManager 2: Ready. ' + String.fromCharCode(10003),\r\n reset: sm + '.reset(): Removing event callbacks',\r\n mobileUA: 'Mobile UA detected, preferring HTML5 by default.',\r\n globalHTML5: 'Using singleton HTML5 Audio() pattern for this device.',\r\n ignoreMobile: 'Ignoring mobile restrictions for this device.'\r\n // </d>\r\n\r\n };\r\n\r\n str = function() {\r\n\r\n // internal string replace helper.\r\n // arguments: o [,items to replace]\r\n // <d>\r\n\r\n var args,\r\n i, j, o,\r\n sstr;\r\n\r\n // real array, please\r\n args = slice.call(arguments);\r\n\r\n // first argument\r\n o = args.shift();\r\n\r\n sstr = (strings && strings[o] ? strings[o] : '');\r\n\r\n if (sstr && args && args.length) {\r\n for (i = 0, j = args.length; i < j; i++) {\r\n sstr = sstr.replace('%s', args[i]);\r\n }\r\n }\r\n\r\n return sstr;\r\n // </d>\r\n\r\n };\r\n\r\n loopFix = function(sOpt) {\r\n\r\n // flash 8 requires stream = false for looping to work\r\n if (fV === 8 && sOpt.loops > 1 && sOpt.stream) {\r\n _wDS('as2loop');\r\n sOpt.stream = false;\r\n }\r\n\r\n return sOpt;\r\n\r\n };\r\n\r\n policyFix = function(sOpt, sPre) {\r\n\r\n if (sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) {\r\n sm2._wD((sPre || '') + str('policy'));\r\n sOpt.usePolicyFile = true;\r\n }\r\n\r\n return sOpt;\r\n\r\n };\r\n\r\n complain = function(sMsg) {\r\n\r\n // <d>\r\n if (hasConsole && console.warn !== _undefined) {\r\n console.warn(sMsg);\r\n } else {\r\n sm2._wD(sMsg);\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n doNothing = function() {\r\n\r\n return false;\r\n\r\n };\r\n\r\n disableObject = function(o) {\r\n\r\n var oProp;\r\n\r\n for (oProp in o) {\r\n if (o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') {\r\n o[oProp] = doNothing;\r\n }\r\n }\r\n\r\n oProp = null;\r\n\r\n };\r\n\r\n failSafely = function(bNoDisable) {\r\n\r\n // general failure exception handler\r\n\r\n if (bNoDisable === _undefined) {\r\n bNoDisable = false;\r\n }\r\n\r\n if (disabled || bNoDisable) {\r\n sm2.disable(bNoDisable);\r\n }\r\n\r\n };\r\n\r\n normalizeMovieURL = function(movieURL) {\r\n\r\n var urlParams = null, url;\r\n\r\n if (movieURL) {\r\n\r\n if (movieURL.match(/\\.swf(\\?.*)?$/i)) {\r\n\r\n urlParams = movieURL.substr(movieURL.toLowerCase().lastIndexOf('.swf?') + 4);\r\n\r\n // assume user knows what they're doing\r\n if (urlParams) return movieURL;\r\n\r\n } else if (movieURL.lastIndexOf('/') !== movieURL.length - 1) {\r\n\r\n // append trailing slash, if needed\r\n movieURL += '/';\r\n\r\n }\r\n\r\n }\r\n\r\n url = (movieURL && movieURL.lastIndexOf('/') !== -1 ? movieURL.substr(0, movieURL.lastIndexOf('/') + 1) : './') + sm2.movieURL;\r\n\r\n if (sm2.noSWFCache) {\r\n url += ('?ts=' + new Date().getTime());\r\n }\r\n\r\n return url;\r\n\r\n };\r\n\r\n setVersionInfo = function() {\r\n\r\n // short-hand for internal use\r\n\r\n fV = parseInt(sm2.flashVersion, 10);\r\n\r\n if (fV !== 8 && fV !== 9) {\r\n sm2._wD(str('badFV', fV, defaultFlashVersion));\r\n sm2.flashVersion = fV = defaultFlashVersion;\r\n }\r\n\r\n // debug flash movie, if applicable\r\n\r\n var isDebug = (sm2.debugMode || sm2.debugFlash ? '_debug.swf' : '.swf');\r\n\r\n if (sm2.useHTML5Audio && !sm2.html5Only && sm2.audioFormats.mp4.required && fV < 9) {\r\n sm2._wD(str('needfl9'));\r\n sm2.flashVersion = fV = 9;\r\n }\r\n\r\n sm2.version = sm2.versionNumber + (sm2.html5Only ? ' (HTML5-only mode)' : (fV === 9 ? ' (AS3/Flash 9)' : ' (AS2/Flash 8)'));\r\n\r\n // set up default options\r\n if (fV > 8) {\r\n\r\n // +flash 9 base options\r\n sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.flash9Options);\r\n sm2.features.buffering = true;\r\n\r\n // +moviestar support\r\n sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.movieStarOptions);\r\n sm2.filePatterns.flash9 = new RegExp('\\\\.(mp3|' + netStreamTypes.join('|') + ')(\\\\?.*)?$', 'i');\r\n sm2.features.movieStar = true;\r\n\r\n } else {\r\n\r\n sm2.features.movieStar = false;\r\n\r\n }\r\n\r\n // regExp for flash canPlay(), etc.\r\n sm2.filePattern = sm2.filePatterns[(fV !== 8 ? 'flash9' : 'flash8')];\r\n\r\n // if applicable, use _debug versions of SWFs\r\n sm2.movieURL = (fV === 8 ? 'soundmanager2.swf' : 'soundmanager2_flash9.swf').replace('.swf', isDebug);\r\n\r\n sm2.features.peakData = sm2.features.waveformData = sm2.features.eqData = (fV > 8);\r\n\r\n };\r\n\r\n setPolling = function(bPolling, bHighPerformance) {\r\n\r\n if (!flash) {\r\n return;\r\n }\r\n\r\n flash._setPolling(bPolling, bHighPerformance);\r\n\r\n };\r\n\r\n initDebug = function() {\r\n\r\n // starts debug mode, creating output <div> for UAs without console object\r\n\r\n // allow force of debug mode via URL\r\n // <d>\r\n if (sm2.debugURLParam.test(wl)) {\r\n sm2.setupOptions.debugMode = sm2.debugMode = true;\r\n }\r\n\r\n if (id(sm2.debugID)) {\r\n return;\r\n }\r\n\r\n var oD, oDebug, oTarget, oToggle, tmp;\r\n\r\n if (sm2.debugMode && !id(sm2.debugID) && (!hasConsole || !sm2.useConsole || !sm2.consoleOnly)) {\r\n\r\n oD = doc.createElement('div');\r\n oD.id = sm2.debugID + '-toggle';\r\n\r\n oToggle = {\r\n position: 'fixed',\r\n bottom: '0px',\r\n right: '0px',\r\n width: '1.2em',\r\n height: '1.2em',\r\n lineHeight: '1.2em',\r\n margin: '2px',\r\n textAlign: 'center',\r\n border: '1px solid #999',\r\n cursor: 'pointer',\r\n background: '#fff',\r\n color: '#333',\r\n zIndex: 10001\r\n };\r\n\r\n oD.appendChild(doc.createTextNode('-'));\r\n oD.onclick = toggleDebug;\r\n oD.title = 'Toggle SM2 debug console';\r\n\r\n if (ua.match(/msie 6/i)) {\r\n oD.style.position = 'absolute';\r\n oD.style.cursor = 'hand';\r\n }\r\n\r\n for (tmp in oToggle) {\r\n if (oToggle.hasOwnProperty(tmp)) {\r\n oD.style[tmp] = oToggle[tmp];\r\n }\r\n }\r\n\r\n oDebug = doc.createElement('div');\r\n oDebug.id = sm2.debugID;\r\n oDebug.style.display = (sm2.debugMode ? 'block' : 'none');\r\n\r\n if (sm2.debugMode && !id(oD.id)) {\r\n try {\r\n oTarget = getDocument();\r\n oTarget.appendChild(oD);\r\n } catch(e2) {\r\n throw new Error(str('domError') + ' \\n' + e2.toString());\r\n }\r\n oTarget.appendChild(oDebug);\r\n }\r\n\r\n }\r\n\r\n oTarget = null;\r\n // </d>\r\n\r\n };\r\n\r\n idCheck = this.getSoundById;\r\n\r\n // <d>\r\n _wDS = function(o, errorLevel) {\r\n\r\n return (!o ? '' : sm2._wD(str(o), errorLevel));\r\n\r\n };\r\n\r\n toggleDebug = function() {\r\n\r\n var o = id(sm2.debugID),\r\n oT = id(sm2.debugID + '-toggle');\r\n\r\n if (!o) {\r\n return;\r\n }\r\n\r\n if (debugOpen) {\r\n // minimize\r\n oT.innerHTML = '+';\r\n o.style.display = 'none';\r\n } else {\r\n oT.innerHTML = '-';\r\n o.style.display = 'block';\r\n }\r\n\r\n debugOpen = !debugOpen;\r\n\r\n };\r\n\r\n debugTS = function(sEventType, bSuccess, sMessage) {\r\n\r\n // troubleshooter debug hooks\r\n\r\n if (window.sm2Debugger !== _undefined) {\r\n try {\r\n sm2Debugger.handleEvent(sEventType, bSuccess, sMessage);\r\n } catch(e) {\r\n // oh well\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n\r\n };\r\n // </d>\r\n\r\n getSWFCSS = function() {\r\n\r\n var css = [];\r\n\r\n if (sm2.debugMode) {\r\n css.push(swfCSS.sm2Debug);\r\n }\r\n\r\n if (sm2.debugFlash) {\r\n css.push(swfCSS.flashDebug);\r\n }\r\n\r\n if (sm2.useHighPerformance) {\r\n css.push(swfCSS.highPerf);\r\n }\r\n\r\n return css.join(' ');\r\n\r\n };\r\n\r\n flashBlockHandler = function() {\r\n\r\n // *possible* flash block situation.\r\n\r\n var name = str('fbHandler'),\r\n p = sm2.getMoviePercent(),\r\n css = swfCSS,\r\n error = {\r\n type: 'FLASHBLOCK'\r\n };\r\n\r\n if (sm2.html5Only) {\r\n // no flash, or unused\r\n return;\r\n }\r\n\r\n if (!sm2.ok()) {\r\n\r\n if (needsFlash) {\r\n // make the movie more visible, so user can fix\r\n sm2.oMC.className = getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null ? css.swfTimedout : css.swfError);\r\n sm2._wD(name + ': ' + str('fbTimeout') + (p ? ' (' + str('fbLoaded') + ')' : ''));\r\n }\r\n\r\n sm2.didFlashBlock = true;\r\n\r\n // fire onready(), complain lightly\r\n processOnEvents({\r\n type: 'ontimeout',\r\n ignoreInit: true,\r\n error: error\r\n });\r\n\r\n catchError(error);\r\n\r\n } else {\r\n\r\n // SM2 loaded OK (or recovered)\r\n\r\n // <d>\r\n if (sm2.didFlashBlock) {\r\n sm2._wD(name + ': Unblocked');\r\n }\r\n // </d>\r\n\r\n if (sm2.oMC) {\r\n sm2.oMC.className = [getSWFCSS(), css.swfDefault, css.swfLoaded + (sm2.didFlashBlock ? ' ' + css.swfUnblocked : '')].join(' ');\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n addOnEvent = function(sType, oMethod, oScope) {\r\n\r\n if (on_queue[sType] === _undefined) {\r\n on_queue[sType] = [];\r\n }\r\n\r\n on_queue[sType].push({\r\n method: oMethod,\r\n scope: (oScope || null),\r\n fired: false\r\n });\r\n\r\n };\r\n\r\n processOnEvents = function(oOptions) {\r\n\r\n // if unspecified, assume OK/error\r\n\r\n if (!oOptions) {\r\n oOptions = {\r\n type: (sm2.ok() ? 'onready' : 'ontimeout')\r\n };\r\n }\r\n\r\n // not ready yet.\r\n if (!didInit && oOptions && !oOptions.ignoreInit) return false;\r\n\r\n // invalid case\r\n if (oOptions.type === 'ontimeout' && (sm2.ok() || (disabled && !oOptions.ignoreInit))) return false;\r\n\r\n var status = {\r\n success: (oOptions && oOptions.ignoreInit ? sm2.ok() : !disabled)\r\n },\r\n\r\n // queue specified by type, or none\r\n srcQueue = (oOptions && oOptions.type ? on_queue[oOptions.type] || [] : []),\r\n\r\n queue = [], i, j,\r\n args = [status],\r\n canRetry = (needsFlash && !sm2.ok());\r\n\r\n if (oOptions.error) {\r\n args[0].error = oOptions.error;\r\n }\r\n\r\n for (i = 0, j = srcQueue.length; i < j; i++) {\r\n if (srcQueue[i].fired !== true) {\r\n queue.push(srcQueue[i]);\r\n }\r\n }\r\n\r\n if (queue.length) {\r\n\r\n // sm2._wD(sm + ': Firing ' + queue.length + ' ' + oOptions.type + '() item' + (queue.length === 1 ? '' : 's'));\r\n for (i = 0, j = queue.length; i < j; i++) {\r\n\r\n if (queue[i].scope) {\r\n queue[i].method.apply(queue[i].scope, args);\r\n } else {\r\n queue[i].method.apply(this, args);\r\n }\r\n\r\n if (!canRetry) {\r\n // useFlashBlock and SWF timeout case doesn't count here.\r\n queue[i].fired = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n initUserOnload = function() {\r\n\r\n window.setTimeout(function() {\r\n\r\n if (sm2.useFlashBlock) {\r\n flashBlockHandler();\r\n }\r\n\r\n processOnEvents();\r\n\r\n // call user-defined \"onload\", scoped to window\r\n\r\n if (typeof sm2.onload === 'function') {\r\n _wDS('onload', 1);\r\n sm2.onload.apply(window);\r\n _wDS('onloadOK', 1);\r\n }\r\n\r\n if (sm2.waitForWindowLoad) {\r\n event.add(window, 'load', initUserOnload);\r\n }\r\n\r\n }, 1);\r\n\r\n };\r\n\r\n detectFlash = function() {\r\n\r\n /**\r\n * Hat tip: Flash Detect library (BSD, (C) 2007) by Carl \"DocYes\" S. Yestrau\r\n * http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt\r\n */\r\n\r\n // this work has already been done.\r\n if (hasFlash !== _undefined) return hasFlash;\r\n\r\n var hasPlugin = false, n = navigator, obj, type, types, AX = window.ActiveXObject;\r\n\r\n // MS Edge 14 throws an \"Unspecified Error\" because n.plugins is inaccessible due to permissions\r\n var nP;\r\n\r\n try {\r\n nP = n.plugins;\r\n } catch(e) {\r\n nP = undefined;\r\n }\r\n\r\n if (nP && nP.length) {\r\n\r\n type = 'application/x-shockwave-flash';\r\n types = n.mimeTypes;\r\n\r\n if (types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) {\r\n hasPlugin = true;\r\n }\r\n\r\n } else if (AX !== _undefined && !ua.match(/MSAppHost/i)) {\r\n\r\n // Windows 8 Store Apps (MSAppHost) are weird (compatibility?) and won't complain here, but will barf if Flash/ActiveX object is appended to the DOM.\r\n try {\r\n obj = new AX('ShockwaveFlash.ShockwaveFlash');\r\n } catch(e) {\r\n // oh well\r\n obj = null;\r\n }\r\n\r\n hasPlugin = (!!obj);\r\n\r\n // cleanup, because it is ActiveX after all\r\n obj = null;\r\n\r\n }\r\n\r\n hasFlash = hasPlugin;\r\n\r\n return hasPlugin;\r\n\r\n };\r\n\r\n featureCheck = function() {\r\n\r\n var flashNeeded,\r\n item,\r\n formats = sm2.audioFormats,\r\n // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (original iPad) + iOS4 works.\r\n isSpecial = (is_iDevice && !!(ua.match(/os (1|2|3_0|3_1)\\s/i)));\r\n\r\n if (isSpecial) {\r\n\r\n // has Audio(), but is broken; let it load links directly.\r\n sm2.hasHTML5 = false;\r\n\r\n // ignore flash case, however\r\n sm2.html5Only = true;\r\n\r\n // hide the SWF, if present\r\n if (sm2.oMC) {\r\n sm2.oMC.style.display = 'none';\r\n }\r\n\r\n } else if (sm2.useHTML5Audio) {\r\n\r\n if (!sm2.html5 || !sm2.html5.canPlayType) {\r\n sm2._wD('SoundManager: No HTML5 Audio() support detected.');\r\n sm2.hasHTML5 = false;\r\n }\r\n\r\n // <d>\r\n if (isBadSafari) {\r\n sm2._wD(smc + 'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - ' + (!hasFlash ? ' would use flash fallback for MP3/MP4, but none detected.' : 'will use flash fallback for MP3/MP4, if available'), 1);\r\n }\r\n // </d>\r\n\r\n }\r\n\r\n if (sm2.useHTML5Audio && sm2.hasHTML5) {\r\n\r\n // sort out whether flash is optional, required or can be ignored.\r\n\r\n // innocent until proven guilty.\r\n canIgnoreFlash = true;\r\n\r\n for (item in formats) {\r\n\r\n if (formats.hasOwnProperty(item)) {\r\n\r\n if (formats[item].required) {\r\n\r\n if (!sm2.html5.canPlayType(formats[item].type)) {\r\n\r\n // 100% HTML5 mode is not possible.\r\n canIgnoreFlash = false;\r\n flashNeeded = true;\r\n\r\n } else if (sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type])) {\r\n\r\n // flash may be required, or preferred for this format.\r\n flashNeeded = true;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n // sanity check...\r\n if (sm2.ignoreFlash) {\r\n flashNeeded = false;\r\n canIgnoreFlash = true;\r\n }\r\n\r\n sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !flashNeeded);\r\n\r\n return (!sm2.html5Only);\r\n\r\n };\r\n\r\n parseURL = function(url) {\r\n\r\n /**\r\n * Internal: Finds and returns the first playable URL (or failing that, the first URL.)\r\n * @param {string or array} url A single URL string, OR, an array of URL strings or {url:'/path/to/resource', type:'audio/mp3'} objects.\r\n */\r\n\r\n var i, j, urlResult = 0, result;\r\n\r\n if (url instanceof Array) {\r\n\r\n // find the first good one\r\n for (i = 0, j = url.length; i < j; i++) {\r\n\r\n if (url[i] instanceof Object) {\r\n\r\n // MIME check\r\n if (sm2.canPlayMIME(url[i].type)) {\r\n urlResult = i;\r\n break;\r\n }\r\n\r\n } else if (sm2.canPlayURL(url[i])) {\r\n\r\n // URL string check\r\n urlResult = i;\r\n break;\r\n\r\n }\r\n\r\n }\r\n\r\n // normalize to string\r\n if (url[urlResult].url) {\r\n url[urlResult] = url[urlResult].url;\r\n }\r\n\r\n result = url[urlResult];\r\n\r\n } else {\r\n\r\n // single URL case\r\n result = url;\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n\r\n startTimer = function(oSound) {\r\n\r\n /**\r\n * attach a timer to this sound, and start an interval if needed\r\n */\r\n\r\n if (!oSound._hasTimer) {\r\n\r\n oSound._hasTimer = true;\r\n\r\n if (!mobileHTML5 && sm2.html5PollingInterval) {\r\n\r\n if (h5IntervalTimer === null && h5TimerCount === 0) {\r\n\r\n h5IntervalTimer = setInterval(timerExecute, sm2.html5PollingInterval);\r\n\r\n }\r\n\r\n h5TimerCount++;\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n stopTimer = function(oSound) {\r\n\r\n /**\r\n * detach a timer\r\n */\r\n\r\n if (oSound._hasTimer) {\r\n\r\n oSound._hasTimer = false;\r\n\r\n if (!mobileHTML5 && sm2.html5PollingInterval) {\r\n\r\n // interval will stop itself at next execution.\r\n\r\n h5TimerCount--;\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n timerExecute = function() {\r\n\r\n /**\r\n * manual polling for HTML5 progress events, ie., whileplaying()\r\n * (can achieve greater precision than conservative default HTML5 interval)\r\n */\r\n\r\n var i;\r\n\r\n if (h5IntervalTimer !== null && !h5TimerCount) {\r\n\r\n // no active timers, stop polling interval.\r\n\r\n clearInterval(h5IntervalTimer);\r\n\r\n h5IntervalTimer = null;\r\n\r\n return;\r\n\r\n }\r\n\r\n // check all HTML5 sounds with timers\r\n\r\n for (i = sm2.soundIDs.length - 1; i >= 0; i--) {\r\n\r\n if (sm2.sounds[sm2.soundIDs[i]].isHTML5 && sm2.sounds[sm2.soundIDs[i]]._hasTimer) {\r\n sm2.sounds[sm2.soundIDs[i]]._onTimer();\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n catchError = function(options) {\r\n\r\n options = (options !== _undefined ? options : {});\r\n\r\n if (typeof sm2.onerror === 'function') {\r\n sm2.onerror.apply(window, [{\r\n type: (options.type !== _undefined ? options.type : null)\r\n }]);\r\n }\r\n\r\n if (options.fatal !== _undefined && options.fatal) {\r\n sm2.disable();\r\n }\r\n\r\n };\r\n\r\n badSafariFix = function() {\r\n\r\n // special case: \"bad\" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4\r\n if (!isBadSafari || !detectFlash()) {\r\n // doesn't apply\r\n return;\r\n }\r\n\r\n var aF = sm2.audioFormats, i, item;\r\n\r\n for (item in aF) {\r\n\r\n if (aF.hasOwnProperty(item)) {\r\n\r\n if (item === 'mp3' || item === 'mp4') {\r\n\r\n sm2._wD(sm + ': Using flash fallback for ' + item + ' format');\r\n sm2.html5[item] = false;\r\n\r\n // assign result to related formats, too\r\n if (aF[item] && aF[item].related) {\r\n for (i = aF[item].related.length - 1; i >= 0; i--) {\r\n sm2.html5[aF[item].related[i]] = false;\r\n }\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Pseudo-private flash/ExternalInterface methods\r\n * ----------------------------------------------\r\n */\r\n\r\n this._setSandboxType = function(sandboxType) {\r\n\r\n // <d>\r\n // Security sandbox according to Flash plugin\r\n var sb = sm2.sandbox;\r\n\r\n sb.type = sandboxType;\r\n sb.description = sb.types[(sb.types[sandboxType] !== _undefined ? sandboxType : 'unknown')];\r\n\r\n if (sb.type === 'localWithFile') {\r\n\r\n sb.noRemote = true;\r\n sb.noLocal = false;\r\n _wDS('secNote', 2);\r\n\r\n } else if (sb.type === 'localWithNetwork') {\r\n\r\n sb.noRemote = false;\r\n sb.noLocal = true;\r\n\r\n } else if (sb.type === 'localTrusted') {\r\n\r\n sb.noRemote = false;\r\n sb.noLocal = false;\r\n\r\n }\r\n // </d>\r\n\r\n };\r\n\r\n this._externalInterfaceOK = function(swfVersion) {\r\n\r\n // flash callback confirming flash loaded, EI working etc.\r\n // swfVersion: SWF build string\r\n\r\n if (sm2.swfLoaded) {\r\n return;\r\n }\r\n\r\n var e;\r\n\r\n debugTS('swf', true);\r\n debugTS('flashtojs', true);\r\n sm2.swfLoaded = true;\r\n tryInitOnFocus = false;\r\n\r\n if (isBadSafari) {\r\n badSafariFix();\r\n }\r\n\r\n // complain if JS + SWF build/version strings don't match, excluding +DEV builds\r\n // <d>\r\n if (!swfVersion || swfVersion.replace(/\\+dev/i, '') !== sm2.versionNumber.replace(/\\+dev/i, '')) {\r\n\r\n e = sm + ': Fatal: JavaScript file build \"' + sm2.versionNumber + '\" does not match Flash SWF build \"' + swfVersion + '\" at ' + sm2.url + '. Ensure both are up-to-date.';\r\n\r\n // escape flash -> JS stack so this error fires in window.\r\n setTimeout(function() {\r\n throw new Error(e);\r\n }, 0);\r\n\r\n // exit, init will fail with timeout\r\n return;\r\n\r\n }\r\n // </d>\r\n\r\n // IE needs a larger timeout\r\n setTimeout(init, isIE ? 100 : 1);\r\n\r\n };\r\n\r\n /**\r\n * Private initialization helpers\r\n * ------------------------------\r\n */\r\n\r\n createMovie = function(movieID, movieURL) {\r\n\r\n // ignore if already connected\r\n if (didAppend && appendSuccess) return false;\r\n\r\n function initMsg() {\r\n\r\n // <d>\r\n\r\n var options = [],\r\n title,\r\n msg = [],\r\n delimiter = ' + ';\r\n\r\n title = 'SoundManager ' + sm2.version + (!sm2.html5Only && sm2.useHTML5Audio ? (sm2.hasHTML5 ? ' + HTML5 audio' : ', no HTML5 audio support') : '');\r\n\r\n if (!sm2.html5Only) {\r\n\r\n if (sm2.preferFlash) {\r\n options.push('preferFlash');\r\n }\r\n\r\n if (sm2.useHighPerformance) {\r\n options.push('useHighPerformance');\r\n }\r\n\r\n if (sm2.flashPollingInterval) {\r\n options.push('flashPollingInterval (' + sm2.flashPollingInterval + 'ms)');\r\n }\r\n\r\n if (sm2.html5PollingInterval) {\r\n options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)');\r\n }\r\n\r\n if (sm2.wmode) {\r\n options.push('wmode (' + sm2.wmode + ')');\r\n }\r\n\r\n if (sm2.debugFlash) {\r\n options.push('debugFlash');\r\n }\r\n\r\n if (sm2.useFlashBlock) {\r\n options.push('flashBlock');\r\n }\r\n\r\n } else if (sm2.html5PollingInterval) {\r\n options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)');\r\n }\r\n\r\n if (options.length) {\r\n msg = msg.concat([options.join(delimiter)]);\r\n }\r\n\r\n sm2._wD(title + (msg.length ? delimiter + msg.join(', ') : ''), 1);\r\n\r\n showSupport();\r\n\r\n // </d>\r\n\r\n }\r\n\r\n if (sm2.html5Only) {\r\n\r\n // 100% HTML5 mode\r\n setVersionInfo();\r\n\r\n initMsg();\r\n sm2.oMC = id(sm2.movieID);\r\n init();\r\n\r\n // prevent multiple init attempts\r\n didAppend = true;\r\n\r\n appendSuccess = true;\r\n\r\n return false;\r\n\r\n }\r\n\r\n // flash path\r\n var remoteURL = (movieURL || sm2.url),\r\n localURL = (sm2.altURL || remoteURL),\r\n swfTitle = 'JS/Flash audio component (SoundManager 2)',\r\n oTarget = getDocument(),\r\n extraClass = getSWFCSS(),\r\n isRTL = null,\r\n html = doc.getElementsByTagName('html')[0],\r\n oEmbed, oMovie, tmp, movieHTML, oEl, s, x, sClass;\r\n\r\n isRTL = (html && html.dir && html.dir.match(/rtl/i));\r\n movieID = (movieID === _undefined ? sm2.id : movieID);\r\n\r\n function param(name, value) {\r\n return '<param name=\"' + name + '\" value=\"' + value + '\" />';\r\n }\r\n\r\n // safety check for legacy (change to Flash 9 URL)\r\n setVersionInfo();\r\n sm2.url = normalizeMovieURL(overHTTP ? remoteURL : localURL);\r\n movieURL = sm2.url;\r\n\r\n sm2.wmode = (!sm2.wmode && sm2.useHighPerformance ? 'transparent' : sm2.wmode);\r\n\r\n if (sm2.wmode !== null && (ua.match(/msie 8/i) || (!isIE && !sm2.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) {\r\n /**\r\n * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here\r\n * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout\r\n * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?)\r\n */\r\n messages.push(strings.spcWmode);\r\n sm2.wmode = null;\r\n }\r\n\r\n oEmbed = {\r\n name: movieID,\r\n id: movieID,\r\n src: movieURL,\r\n quality: 'high',\r\n allowScriptAccess: sm2.allowScriptAccess,\r\n bgcolor: sm2.bgColor,\r\n pluginspage: http + 'www.macromedia.com/go/getflashplayer',\r\n title: swfTitle,\r\n type: 'application/x-shockwave-flash',\r\n wmode: sm2.wmode,\r\n // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html\r\n hasPriority: 'true'\r\n };\r\n\r\n if (sm2.debugFlash) {\r\n oEmbed.FlashVars = 'debug=1';\r\n }\r\n\r\n if (!sm2.wmode) {\r\n // don't write empty attribute\r\n delete oEmbed.wmode;\r\n }\r\n\r\n if (isIE) {\r\n\r\n // IE is \"special\".\r\n oMovie = doc.createElement('div');\r\n movieHTML = [\r\n '<object id=\"' + movieID + '\" data=\"' + movieURL + '\" type=\"' + oEmbed.type + '\" title=\"' + oEmbed.title + '\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0\">',\r\n param('movie', movieURL),\r\n param('AllowScriptAccess', sm2.allowScriptAccess),\r\n param('quality', oEmbed.quality),\r\n (sm2.wmode ? param('wmode', sm2.wmode) : ''),\r\n param('bgcolor', sm2.bgColor),\r\n param('hasPriority', 'true'),\r\n (sm2.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''),\r\n '</object>'\r\n ].join('');\r\n\r\n } else {\r\n\r\n oMovie = doc.createElement('embed');\r\n for (tmp in oEmbed) {\r\n if (oEmbed.hasOwnProperty(tmp)) {\r\n oMovie.setAttribute(tmp, oEmbed[tmp]);\r\n }\r\n }\r\n\r\n }\r\n\r\n initDebug();\r\n extraClass = getSWFCSS();\r\n oTarget = getDocument();\r\n\r\n if (oTarget) {\r\n\r\n sm2.oMC = (id(sm2.movieID) || doc.createElement('div'));\r\n\r\n if (!sm2.oMC.id) {\r\n\r\n sm2.oMC.id = sm2.movieID;\r\n sm2.oMC.className = swfCSS.swfDefault + ' ' + extraClass;\r\n s = null;\r\n oEl = null;\r\n\r\n if (!sm2.useFlashBlock) {\r\n if (sm2.useHighPerformance) {\r\n // on-screen at all times\r\n s = {\r\n position: 'fixed',\r\n width: '8px',\r\n height: '8px',\r\n // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes.\r\n bottom: '0px',\r\n left: '0px',\r\n overflow: 'hidden'\r\n };\r\n } else {\r\n // hide off-screen, lower priority\r\n s = {\r\n position: 'absolute',\r\n width: '6px',\r\n height: '6px',\r\n top: '-9999px',\r\n left: '-9999px'\r\n };\r\n if (isRTL) {\r\n s.left = Math.abs(parseInt(s.left, 10)) + 'px';\r\n }\r\n }\r\n }\r\n\r\n if (isWebkit) {\r\n // soundcloud-reported render/crash fix, safari 5\r\n sm2.oMC.style.zIndex = 10000;\r\n }\r\n\r\n if (!sm2.debugFlash) {\r\n for (x in s) {\r\n if (s.hasOwnProperty(x)) {\r\n sm2.oMC.style[x] = s[x];\r\n }\r\n }\r\n }\r\n\r\n try {\r\n\r\n if (!isIE) {\r\n sm2.oMC.appendChild(oMovie);\r\n }\r\n\r\n oTarget.appendChild(sm2.oMC);\r\n\r\n if (isIE) {\r\n oEl = sm2.oMC.appendChild(doc.createElement('div'));\r\n oEl.className = swfCSS.swfBox;\r\n oEl.innerHTML = movieHTML;\r\n }\r\n\r\n appendSuccess = true;\r\n\r\n } catch(e) {\r\n\r\n throw new Error(str('domError') + ' \\n' + e.toString());\r\n\r\n }\r\n\r\n } else {\r\n\r\n // SM2 container is already in the document (eg. flashblock use case)\r\n sClass = sm2.oMC.className;\r\n sm2.oMC.className = (sClass ? sClass + ' ' : swfCSS.swfDefault) + (extraClass ? ' ' + extraClass : '');\r\n sm2.oMC.appendChild(oMovie);\r\n\r\n if (isIE) {\r\n oEl = sm2.oMC.appendChild(doc.createElement('div'));\r\n oEl.className = swfCSS.swfBox;\r\n oEl.innerHTML = movieHTML;\r\n }\r\n\r\n appendSuccess = true;\r\n\r\n }\r\n\r\n }\r\n\r\n didAppend = true;\r\n\r\n initMsg();\r\n\r\n // sm2._wD(sm + ': Trying to load ' + movieURL + (!overHTTP && sm2.altURL ? ' (alternate URL)' : ''), 1);\r\n\r\n return true;\r\n\r\n };\r\n\r\n initMovie = function() {\r\n\r\n if (sm2.html5Only) {\r\n createMovie();\r\n return false;\r\n }\r\n\r\n // attempt to get, or create, movie (may already exist)\r\n if (flash) return false;\r\n\r\n if (!sm2.url) {\r\n\r\n /**\r\n * Something isn't right - we've reached init, but the soundManager url property has not been set.\r\n * User has not called setup({url: ...}), or has not set soundManager.url (legacy use case) directly before init time.\r\n * Notify and exit. If user calls setup() with a url: property, init will be restarted as in the deferred loading case.\r\n */\r\n\r\n _wDS('noURL');\r\n return false;\r\n\r\n }\r\n\r\n // inline markup case\r\n flash = sm2.getMovie(sm2.id);\r\n\r\n if (!flash) {\r\n\r\n if (!oRemoved) {\r\n\r\n // try to create\r\n createMovie(sm2.id, sm2.url);\r\n\r\n } else {\r\n\r\n // try to re-append removed movie after reboot()\r\n if (!isIE) {\r\n sm2.oMC.appendChild(oRemoved);\r\n } else {\r\n sm2.oMC.innerHTML = oRemovedHTML;\r\n }\r\n\r\n oRemoved = null;\r\n didAppend = true;\r\n\r\n }\r\n\r\n flash = sm2.getMovie(sm2.id);\r\n\r\n }\r\n\r\n if (typeof sm2.oninitmovie === 'function') {\r\n setTimeout(sm2.oninitmovie, 1);\r\n }\r\n\r\n // <d>\r\n flushMessages();\r\n // </d>\r\n\r\n return true;\r\n\r\n };\r\n\r\n delayWaitForEI = function() {\r\n\r\n setTimeout(waitForEI, 1000);\r\n\r\n };\r\n\r\n rebootIntoHTML5 = function() {\r\n\r\n // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled.\r\n\r\n window.setTimeout(function() {\r\n\r\n complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...');\r\n\r\n sm2.setup({\r\n preferFlash: false\r\n }).reboot();\r\n\r\n // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true.\r\n sm2.didFlashBlock = true;\r\n\r\n sm2.beginDelayedInit();\r\n\r\n }, 1);\r\n\r\n };\r\n\r\n waitForEI = function() {\r\n\r\n var p,\r\n loadIncomplete = false;\r\n\r\n if (!sm2.url) {\r\n // No SWF url to load (noURL case) - exit for now. Will be retried when url is set.\r\n return;\r\n }\r\n\r\n if (waitingForEI) {\r\n return;\r\n }\r\n\r\n waitingForEI = true;\r\n event.remove(window, 'load', delayWaitForEI);\r\n\r\n if (hasFlash && tryInitOnFocus && !isFocused) {\r\n // Safari won't load flash in background tabs, only when focused.\r\n _wDS('waitFocus');\r\n return;\r\n }\r\n\r\n if (!didInit) {\r\n p = sm2.getMoviePercent();\r\n if (p > 0 && p < 100) {\r\n loadIncomplete = true;\r\n }\r\n }\r\n\r\n setTimeout(function() {\r\n\r\n p = sm2.getMoviePercent();\r\n\r\n if (loadIncomplete) {\r\n // special case: if movie *partially* loaded, retry until it's 100% before assuming failure.\r\n waitingForEI = false;\r\n sm2._wD(str('waitSWF'));\r\n window.setTimeout(delayWaitForEI, 1);\r\n return;\r\n }\r\n\r\n // <d>\r\n if (!didInit) {\r\n\r\n sm2._wD(sm + ': No Flash response within expected time. Likely causes: ' + (p === 0 ? 'SWF load failed, ' : '') + 'Flash blocked or JS-Flash security error.' + (sm2.debugFlash ? ' ' + str('checkSWF') : ''), 2);\r\n\r\n if (!overHTTP && p) {\r\n\r\n _wDS('localFail', 2);\r\n\r\n if (!sm2.debugFlash) {\r\n _wDS('tryDebug', 2);\r\n }\r\n\r\n }\r\n\r\n if (p === 0) {\r\n\r\n // if 0 (not null), probably a 404.\r\n sm2._wD(str('swf404', sm2.url), 1);\r\n\r\n }\r\n\r\n debugTS('flashtojs', false, ': Timed out' + (overHTTP ? ' (Check flash security or flash blockers)' : ' (No plugin/missing SWF?)'));\r\n\r\n }\r\n // </d>\r\n\r\n // give up / time-out, depending\r\n\r\n if (!didInit && okToDisable) {\r\n\r\n if (p === null) {\r\n\r\n // SWF failed to report load progress. Possibly blocked.\r\n\r\n if (sm2.useFlashBlock || sm2.flashLoadTimeout === 0) {\r\n\r\n if (sm2.useFlashBlock) {\r\n\r\n flashBlockHandler();\r\n\r\n }\r\n\r\n _wDS('waitForever');\r\n\r\n } else if (!sm2.useFlashBlock && canIgnoreFlash) {\r\n\r\n // no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load.\r\n rebootIntoHTML5();\r\n\r\n } else {\r\n\r\n _wDS('waitForever');\r\n\r\n // fire any regular registered ontimeout() listeners.\r\n processOnEvents({\r\n type: 'ontimeout',\r\n ignoreInit: true,\r\n error: {\r\n type: 'INIT_FLASHBLOCK'\r\n }\r\n });\r\n\r\n }\r\n\r\n } else if (sm2.flashLoadTimeout === 0) {\r\n\r\n // SWF loaded? Shouldn't be a blocking issue, then.\r\n\r\n _wDS('waitForever');\r\n\r\n } else if (!sm2.useFlashBlock && canIgnoreFlash) {\r\n\r\n rebootIntoHTML5();\r\n\r\n } else {\r\n\r\n failSafely(true);\r\n\r\n }\r\n\r\n }\r\n\r\n }, sm2.flashLoadTimeout);\r\n\r\n };\r\n\r\n handleFocus = function() {\r\n\r\n function cleanup() {\r\n event.remove(window, 'focus', handleFocus);\r\n }\r\n\r\n if (isFocused || !tryInitOnFocus) {\r\n // already focused, or not special Safari background tab case\r\n cleanup();\r\n return true;\r\n }\r\n\r\n okToDisable = true;\r\n isFocused = true;\r\n _wDS('gotFocus');\r\n\r\n // allow init to restart\r\n waitingForEI = false;\r\n\r\n // kick off ExternalInterface timeout, now that the SWF has started\r\n delayWaitForEI();\r\n\r\n cleanup();\r\n return true;\r\n\r\n };\r\n\r\n flushMessages = function() {\r\n\r\n // <d>\r\n\r\n // SM2 pre-init debug messages\r\n if (messages.length) {\r\n sm2._wD('SoundManager 2: ' + messages.join(' '), 1);\r\n messages = [];\r\n }\r\n\r\n // </d>\r\n\r\n };\r\n\r\n showSupport = function() {\r\n\r\n // <d>\r\n\r\n flushMessages();\r\n\r\n var item, tests = [];\r\n\r\n if (sm2.useHTML5Audio && sm2.hasHTML5) {\r\n for (item in sm2.audioFormats) {\r\n if (sm2.audioFormats.hasOwnProperty(item)) {\r\n tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && needsFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && needsFlash ? ' (preferring flash)' : (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ' : '') + 'and no flash support)' : ''))));\r\n }\r\n }\r\n sm2._wD('SoundManager 2 HTML5 support: ' + tests.join(', '), 1);\r\n }\r\n\r\n // </d>\r\n\r\n };\r\n\r\n initComplete = function(bNoDisable) {\r\n\r\n if (didInit) return false;\r\n\r\n if (sm2.html5Only) {\r\n // all good.\r\n _wDS('sm2Loaded', 1);\r\n didInit = true;\r\n initUserOnload();\r\n debugTS('onload', true);\r\n return true;\r\n }\r\n\r\n var wasTimeout = (sm2.useFlashBlock && sm2.flashLoadTimeout && !sm2.getMoviePercent()),\r\n result = true,\r\n error;\r\n\r\n if (!wasTimeout) {\r\n didInit = true;\r\n }\r\n\r\n error = {\r\n type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')\r\n };\r\n\r\n sm2._wD('SoundManager 2 ' + (disabled ? 'failed to load' : 'loaded') + ' (' + (disabled ? 'Flash security/load error' : 'OK') + ') ' + String.fromCharCode(disabled ? 10006 : 10003), disabled ? 2 : 1);\r\n\r\n if (disabled || bNoDisable) {\r\n\r\n if (sm2.useFlashBlock && sm2.oMC) {\r\n sm2.oMC.className = getSWFCSS() + ' ' + (sm2.getMoviePercent() === null ? swfCSS.swfTimedout : swfCSS.swfError);\r\n }\r\n\r\n processOnEvents({\r\n type: 'ontimeout',\r\n error: error,\r\n ignoreInit: true\r\n });\r\n\r\n debugTS('onload', false);\r\n catchError(error);\r\n\r\n result = false;\r\n\r\n } else {\r\n\r\n debugTS('onload', true);\r\n\r\n }\r\n\r\n if (!disabled) {\r\n\r\n if (sm2.waitForWindowLoad && !windowLoaded) {\r\n\r\n _wDS('waitOnload');\r\n event.add(window, 'load', initUserOnload);\r\n\r\n } else {\r\n\r\n // <d>\r\n if (sm2.waitForWindowLoad && windowLoaded) {\r\n _wDS('docLoaded');\r\n }\r\n // </d>\r\n\r\n initUserOnload();\r\n\r\n }\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * apply top-level setupOptions object as local properties, eg., this.setupOptions.flashVersion -> this.flashVersion (soundManager.flashVersion)\r\n * this maintains backward compatibility, and allows properties to be defined separately for use by soundManager.setup().\r\n */\r\n\r\n setProperties = function() {\r\n\r\n var i,\r\n o = sm2.setupOptions;\r\n\r\n for (i in o) {\r\n\r\n if (o.hasOwnProperty(i)) {\r\n\r\n // assign local property if not already defined\r\n\r\n if (sm2[i] === _undefined) {\r\n\r\n sm2[i] = o[i];\r\n\r\n } else if (sm2[i] !== o[i]) {\r\n\r\n // legacy support: write manually-assigned property (eg., soundManager.url) back to setupOptions to keep things in sync\r\n sm2.setupOptions[i] = sm2[i];\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n\r\n init = function() {\r\n\r\n // called after onload()\r\n\r\n if (didInit) {\r\n _wDS('didInit');\r\n return false;\r\n }\r\n\r\n function cleanup() {\r\n event.remove(window, 'load', sm2.beginDelayedInit);\r\n }\r\n\r\n if (sm2.html5Only) {\r\n\r\n if (!didInit) {\r\n // we don't need no steenking flash!\r\n cleanup();\r\n sm2.enabled = true;\r\n initComplete();\r\n }\r\n\r\n return true;\r\n\r\n }\r\n\r\n // flash path\r\n initMovie();\r\n\r\n try {\r\n\r\n // attempt to talk to Flash\r\n flash._externalInterfaceTest(false);\r\n\r\n /**\r\n * Apply user-specified polling interval, OR, if \"high performance\" set, faster vs. default polling\r\n * (determines frequency of whileloading/whileplaying callbacks, effectively driving UI framerates)\r\n */\r\n setPolling(true, (sm2.flashPollingInterval || (sm2.useHighPerformance ? 10 : 50)));\r\n\r\n if (!sm2.debugMode) {\r\n // stop the SWF from making debug output calls to JS\r\n flash._disableDebug();\r\n }\r\n\r\n sm2.enabled = true;\r\n debugTS('jstoflash', true);\r\n\r\n if (!sm2.html5Only) {\r\n // prevent browser from showing cached page state (or rather, restoring \"suspended\" page state) via back button, because flash may be dead\r\n // http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/\r\n event.add(window, 'unload', doNothing);\r\n }\r\n\r\n } catch(e) {\r\n\r\n sm2._wD('js/flash exception: ' + e.toString());\r\n\r\n debugTS('jstoflash', false);\r\n\r\n catchError({\r\n type: 'JS_TO_FLASH_EXCEPTION',\r\n fatal: true\r\n });\r\n\r\n // don't disable, for reboot()\r\n failSafely(true);\r\n\r\n initComplete();\r\n\r\n return false;\r\n\r\n }\r\n\r\n initComplete();\r\n\r\n // disconnect events\r\n cleanup();\r\n\r\n return true;\r\n\r\n };\r\n\r\n domContentLoaded = function() {\r\n\r\n if (didDCLoaded) return false;\r\n\r\n didDCLoaded = true;\r\n\r\n // assign top-level soundManager properties eg. soundManager.url\r\n setProperties();\r\n\r\n initDebug();\r\n\r\n if (!hasFlash && sm2.hasHTML5) {\r\n\r\n sm2._wD('SoundManager 2: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1);\r\n\r\n sm2.setup({\r\n useHTML5Audio: true,\r\n // make sure we aren't preferring flash, either\r\n // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak.\r\n preferFlash: false\r\n });\r\n\r\n }\r\n\r\n testHTML5();\r\n\r\n if (!hasFlash && needsFlash) {\r\n\r\n messages.push(strings.needFlash);\r\n\r\n // TODO: Fatal here vs. timeout approach, etc.\r\n // hack: fail sooner.\r\n sm2.setup({\r\n flashLoadTimeout: 1\r\n });\r\n\r\n }\r\n\r\n if (doc.removeEventListener) {\r\n doc.removeEventListener('DOMContentLoaded', domContentLoaded, false);\r\n }\r\n\r\n initMovie();\r\n\r\n return true;\r\n\r\n };\r\n\r\n domContentLoadedIE = function() {\r\n\r\n if (doc.readyState === 'complete') {\r\n domContentLoaded();\r\n doc.detachEvent('onreadystatechange', domContentLoadedIE);\r\n }\r\n\r\n return true;\r\n\r\n };\r\n\r\n winOnLoad = function() {\r\n\r\n // catch edge case of initComplete() firing after window.load()\r\n windowLoaded = true;\r\n\r\n // catch case where DOMContentLoaded has been sent, but we're still in doc.readyState = 'interactive'\r\n domContentLoaded();\r\n\r\n event.remove(window, 'load', winOnLoad);\r\n\r\n };\r\n\r\n // sniff up-front\r\n detectFlash();\r\n\r\n // focus and window load, init (primarily flash-driven)\r\n event.add(window, 'focus', handleFocus);\r\n event.add(window, 'load', delayWaitForEI);\r\n event.add(window, 'load', winOnLoad);\r\n\r\n if (doc.addEventListener) {\r\n\r\n doc.addEventListener('DOMContentLoaded', domContentLoaded, false);\r\n\r\n } else if (doc.attachEvent) {\r\n\r\n doc.attachEvent('onreadystatechange', domContentLoadedIE);\r\n\r\n } else {\r\n\r\n // no add/attachevent support - safe to assume no JS -> Flash either\r\n debugTS('onload', false);\r\n catchError({\r\n type: 'NO_DOM2_EVENTS',\r\n fatal: true\r\n });\r\n\r\n }\r\n\r\n} // SoundManager()\r\n\r\n// SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading\r\n\r\nif (window.SM2_DEFER === _undefined || !SM2_DEFER) {\r\n soundManager = new SoundManager();\r\n}\r\n\r\n/**\r\n * SoundManager public interfaces\r\n * ------------------------------\r\n */\r\n\r\nif (typeof module === 'object' && module && typeof module.exports === 'object') {\r\n\r\n /**\r\n * commonJS module\r\n */\r\n\r\n module.exports.SoundManager = SoundManager;\r\n module.exports.soundManager = soundManager;\r\n\r\n} else if (typeof define === 'function' && define.amd) {\r\n\r\n /**\r\n * AMD - requireJS\r\n * basic usage:\r\n * require([\"/path/to/soundmanager2.js\"], function(SoundManager) {\r\n * SoundManager.getInstance().setup({\r\n * url: '/swf/',\r\n * onready: function() { ... }\r\n * })\r\n * });\r\n *\r\n * SM2_DEFER usage:\r\n * window.SM2_DEFER = true;\r\n * require([\"/path/to/soundmanager2.js\"], function(SoundManager) {\r\n * SoundManager.getInstance(function() {\r\n * var soundManager = new SoundManager.constructor();\r\n * soundManager.setup({\r\n * url: '/swf/',\r\n * ...\r\n * });\r\n * ...\r\n * soundManager.beginDelayedInit();\r\n * return soundManager;\r\n * })\r\n * });\r\n */\r\n\r\n define(function() {\r\n /**\r\n * Retrieve the global instance of SoundManager.\r\n * If a global instance does not exist it can be created using a callback.\r\n *\r\n * @param {Function} smBuilder Optional: Callback used to create a new SoundManager instance\r\n * @return {SoundManager} The global SoundManager instance\r\n */\r\n function getInstance(smBuilder) {\r\n if (!window.soundManager && smBuilder instanceof Function) {\r\n var instance = smBuilder(SoundManager);\r\n if (instance instanceof SoundManager) {\r\n window.soundManager = instance;\r\n }\r\n }\r\n return window.soundManager;\r\n }\r\n return {\r\n constructor: SoundManager,\r\n getInstance: getInstance\r\n };\r\n });\r\n\r\n}\r\n\r\n// standard browser case\r\n\r\n// constructor\r\nwindow.SoundManager = SoundManager;\r\n\r\n/**\r\n * note: SM2 requires a window global due to Flash, which makes calls to window.soundManager.\r\n * Flash may not always be needed, but this is not known until async init and SM2 may even \"reboot\" into Flash mode.\r\n */\r\n\r\n// public API, flash callbacks etc.\r\nwindow.soundManager = soundManager;\r\n\r\n}(window));\r\n"],"names":["PageChunk","leafIndex","chunkIndex","text","lineRects","this","server","bookPath","$","ajax","type","url","dataType","cache","data","path","page","chunks","_fromTextWrapperResponse","chunksResponse","map","c","i","correctedLineRects","_fixChunkRects","slice","correctedText","_removeDanglingHyphens","rects","length","firstRect","secondRect","left","bottom","width","secondHeight","secondWidth","secondRight","replace","PageChunkIterator","pageCount","start","opts","Object","assign","DEFAULT_OPTS","_cursor","chunk","_bufferedPages","_bufferingPages","_cursorLock","Promise","resolve","then","_nextUncontrolled","_decrementUncontrolled","AT_END","_recenterBuffer","_fetchPageChunks","cursorChangePromise","prevPageChunks","index","Math","max","pageBufferSize","end","min","_removePageFromBuffer","_fetchPageChunksDirect","fetch","AbstractTTSEngine","options","voice","getBestBookVoice","getVoices","bookLanguage","playing","paused","_chunkIterator","activeSound","playbackRate","events","on","updateBestVoice","trigger","Error","voices","userLanguages","navigator","languages","bookLangVoices","filter","v","lang","startsWith","matchingUserLangs","language","getMatchingVoice","find","default","matchingVoices","numLeafs","onLoadingStart","step","stop","fireEvent","pause","resume","finish","all","decrement","voiceURI","off","setVoice","newRate","setPlaybackRate","next","onDone","sound","createSound","rate","load","onLoadingComplete","beforeChunkPlay","playSound","afterChunkPlay","playPromise","loaded","play","FestivalTTSEngine","audioFormat","browser","mozilla","localService","name","soundManager","setup","debugMode","preferFlash","useHTML5Audio","flashVersion","promise","userAgent","match","iOSCaptureUserIntentHack","FestivalTTSSound","getSoundUrl","dataString","encodeURIComponent","SILENCE_1MS","res","onfinish","destruct","supported","soundUrl","_finishResolver","onload","onresume","sleep","mp3","ogg","promisifyEvent","target","eventType","addEventListener","resolver","ev","removeEventListener","isAndroid","test","COLUMN_TO_LANG_INDEX","searchForISO6391","columnsToSearch","langs","colI","column","split","x","toLowerCase","indexOf","super_","WebTTSEngine","speechSynthesis","audio","Audio","SILENCE_6S_MP3","loop","src","mediaSession","metadata","MediaMetadata","title","br","bookTitle","artist","m","label","value","artwork","thumbnail","setActionHandler","jumpBackward","jumpForward","WebTTSSound","window","started","stopped","utterance","_lastEvents","boundary","_charIndex","_finishPromise","SpeechSynthesisUtterance","location","toString","console","log","dispatchEvent","CustomEvent","wasPaused","recentEvent","charIndex","cancel","speak","isLocalVoice","isChrome","_chromePausingBugFix","endPromise","race","Event","pausePromise","pauseMightNotWork","isFirefox","timeoutPromise","resumeMightNotWork","resumeMightNotFire","resumePromise","reload","result","en","jQuery","extend","BookReader","defaultOptions","enableTtsPlugin","prototype","call","_ttsBoxesByIndex","TTSEngine","isSupported","engineName","festival","web","ttsEngine","showProgressPopup","bind","removeProgressPopup","ttsStop","ttsBeforeChunkPlay","ttsSendChunkFinishedAnalyticsEvent","init","eventNames","PostInit","click","ttsToggle","ttsStart","_createPageContainer","pageContainer","pageIndex","renderBoxesInPageContainerLayer","$container","buildMobileDrawerElement","$el","after","imagesBaseURL","initNavbar","refs","$BRReadAloudToolbar","prepend","renderVoiceOption","join","voiceSortOrder","a","b","localeCompare","renderVoicesMenu","voicesMenu","empty","bookLanguages","sort","otherLanguages","append","val","show","hide","ttsUpdateState","ttsPlayPause","ttsJumpForward","ttsJumpBackward","$rateSelector","parseFloat","tooltips","insertBefore","closest","autoStop","startTTSEngine","constModeThumb","mode","switchMode","constMode1up","addClass","ttsSendAnalyticsEvent","currentIndex","book","getNumLeafs","isPlaying","toggleClass","togglePlayPause","removeClass","ttsRemoveHilites","ttsMaybeFlipToIndex","ttsHighlightChunk","ttsScrollToChunk","in2PageMode","constMode2up","twoPage","currentIndexR","currentIndexL","animationFinishedCallback","jumpToIndex","l","r","t","pageIndexString","boxes","getPage","getActivePageContainerElementsForIndex","forEach","container","entries","last","scrollIntoView","block","isFullscreenActive","inline","behavior","getActivePageContainerElements","remove","action","archiveAnalyticsSendEvent","extraValues","mediaLanguage","vendor","isSafari","global","fails","uncurryThis","trim","whitespaces","charAt","n$ParseFloat","Symbol","ITERATOR","iterator","FORCED","module","exports","string","trimmedString","$entries","stat","O","$parseFloat","forced","fixRegExpWellKnownSymbolLogic","anObject","toLength","requireObjectCoercible","getMethod","advanceStringIndex","regExpExec","MATCH","nativeMatch","maybeCallNative","regexp","matcher","undefined","RegExp","rx","S","done","fullUnicode","unicode","lastIndex","A","n","matchStr","uaMatch","ua","exec","platform_match","matched","version","versionNumber","platform","parseInt","android","bb","blackberry","ipad","iphone","ipod","kindle","playbook","silk","mobile","cros","mac","linux","win","desktop","chrome","opr","safari","webkit","rv","iemobile","ie","edge","msedge","opera","jQBrowser","factory","_undefined","document","SoundManager","smURL","smID","setupOptions","debugFlash","useConsole","consoleOnly","waitForWindowLoad","bgColor","useHighPerformance","flashPollingInterval","html5PollingInterval","flashLoadTimeout","wmode","allowScriptAccess","useFlashBlock","forceUseGlobalHTML5Audio","ignoreMobileRestrictions","html5Test","noSWFCache","idPrefix","autoLoad","autoPlay","from","loops","onid3","onerror","whileloading","onplay","onpause","whileplaying","onposition","onstop","multiShot","multiShotEvents","position","pan","stream","to","usePolicyFile","volume","flash9Options","onfailure","isMovieStar","usePeakData","useWaveformData","useEQData","onbufferchange","ondataerror","movieStarOptions","bufferTime","serverURL","onconnect","duration","audioFormats","required","mp4","related","opus","wav","flac","movieID","id","debugID","debugURLParam","movieURL","altURL","swfLoaded","enabled","oMC","sounds","soundIDs","muted","didFlashBlock","filePattern","filePatterns","flash8","flash9","features","buffering","peakData","waveformData","eqData","movieStar","sandbox","types","remote","localWithFile","localWithNetwork","localTrusted","description","noRemote","noLocal","html5","usingFlash","flash","html5Only","ignoreFlash","SMSound","doNothing","setProperties","fV","debugTS","_wDS","initComplete","mixin","extraOptions","addOnEvent","processOnEvents","initUserOnload","delayWaitForEI","waitForEI","rebootIntoHTML5","setVersionInfo","handleFocus","strings","initMovie","domContentLoaded","winOnLoad","didDCLoaded","getDocument","createMovie","catchError","setPolling","initDebug","disableObject","failSafely","normalizeMovieURL","str","flashBlockHandler","getSWFCSS","swfCSS","toggleDebug","loopFix","policyFix","complain","idCheck","startTimer","stopTimer","timerExecute","parseURL","canIgnoreFlash","featureCheck","html5OK","html5CanPlay","html5ErrorCodes","html5Ext","html5Unload","domContentLoadedIE","testHTML5","event","lastGlobalHTML5URL","hasFlash","detectFlash","badSafariFix","html5_events","showSupport","flushMessages","wrapCallback","didSetup","sm2","globalHTML5Audio","sm","smc","wl","href","doc","on_queue","debugOpen","didAppend","appendSuccess","didInit","disabled","windowLoaded","wdCount","debugLevels","oRemoved","oRemovedHTML","waitingForEI","initPending","h5TimerCount","h5IntervalTimer","messages","needsFlash","Array","useGlobalHTML5Audio","idCounter","msecScale","is_iDevice","isIE","isWebkit","isOpera","mobileHTML5","isBadSafari","hasConsole","isFocused","hasFocus","tryInitOnFocus","okToDisable","flashMIME","emptyURL","overHTTP","protocol","http","netStreamMimeTypes","netStreamTypes","netStreamPattern","preferFlashCheck","kind","html5_event","oFn","e","s","_s","_a","_wD","h5","mimePattern","useAltURL","swfBox","swfDefault","swfError","swfTimedout","swfUnblocked","sm2Debug","highPerf","flashDebug","hasHTML5","canPlayType","noURL","ok","push","globalHTML5","ignoreMobile","mobileUA","beginDelayedInit","readyState","setTimeout","getMovie","movie_id","oOptions","_url","cs","cs_string","oSound","make","_setup_html5","_createSound","connected","apply","destroySound","sID","_bFromSound","oS","_iO","unload","splice","onPosition","nPosition","oMethod","oScope","clearOnPosition","overloaded","allowOverride","setPosition","nMsecOffset","stopAll","hasOwnProperty","pauseAll","resumeAll","togglePause","setPan","nPan","setVolume","nVol","j","isNaN","mute","String","muteAll","unmute","unmuteAll","toggleMute","getMemoryUse","ram","_getMemoryUse","disable","bNoDisable","canPlayMIME","sMIME","canPlayURL","sURL","canPlayLink","oLink","getSoundById","_suppressDebug","onready","sType","ontimeout","_writeDebug","sText","sTypeOrObject","o","oItem","createElement","className","appendChild","createTextNode","style","fontWeight","color","firstChild","alert","_debug","reboot","resetEvents","excludeInit","k","innerHTML","parentNode","removeChild","fired","reset","getMoviePercent","PercentLoaded","resetProperties","add_html5_events","remove_html5_events","stop_html5_timer","start_html5_timer","attachOnPosition","detachOnPosition","applyFromTo","lastHTML5State","urlOmitted","onplay_called","onPositionItems","onPositionFired","lastURL","time","instanceOptions","isHTML5","id3","playState","_called_load","_html5_canplay","autobuffer","preload","_load","fatal","_unload","_bFromSM","_destroySound","_updatePlayState","fN","audioClone","onended","oncanplay","startOK","getAutoPlay","setAutoPlay","substr","lastIndexOf","instanceCount","_oncanplay","_onfinish","currentTime","err","add","_start","onplayerror","bAll","originalPosition","_onbufferchange","_resetOnPosition","_onTimer","_stop","_setAutoPlay","normalizedRate","message","position1K","offset","toFixed","_setPosition","_bCallFlash","_pause","bInstanceOnly","_setPan","_bInstanceOnly","_setVolume","hasIO","method","scope","_processOnPosition","item","f","op","retainPosition","_hasTimer","bytesLoaded","bytesTotal","durationEstimate","buffered","right","failures","isBuffering","bForce","isNew","_get_html5_duration","_whileplaying","d","Infinity","_apply_loop","nLoops","sameURL","dURL","decodeURI","_added_events","oEvt","_onload","nSuccess","loadOK","_onerror","errorCode","nIsBuffering","_onsuspend","onsuspend","_onfailure","msg","level","code","_onwarning","onwarning","io_onfinish","_whileloading","nBytesLoaded","nBytesTotal","nDuration","nBufferLength","floor","bufferLength","oPeakData","oWaveformDataLeft","oWaveformDataRight","oEQData","eqLeft","leftPeak","rightPeak","leftEQ","rightEQ","_oncaptiondata","oData","captiondata","oncaptiondata","_onmetadata","oMDProps","oMDData","onmetadata","_onid3","oID3Props","oID3Data","_onconnect","bSuccess","_ondataerror","sError","body","getElementsByTagName","getElementById","oMain","oAdd","o2","o1","callback","oParent","hasParent","bonusOptions","Function","old","evt","getArgs","oArgs","args","len","pop","element","shift","arguments","abort","canplay","ee","canplaythrough","durationchange","ended","error","loadeddata","_loaded","loadedmetadata","loadstart","fromCharCode","progress","progStr","isProgress","ranges","total","ratechange","suspend","stalled","timeupdate","waiting","iO","oAudio","_called_unload","fileExt","mime","aF","concat","lookup","support","cp","canPlay","isOK","notReady","notOK","domError","spcWmode","swf404","tryDebug","checkSWF","localFail","waitFocus","waitForever","waitSWF","needFunction","badID","currentObj","waitOnload","docLoaded","onloadOK","secNote","badRemove","shutdown","queue","smError","fbTimeout","fbLoaded","fbHandler","manURL","onURL","badFV","as2loop","noNSLoop","needfl9","mfTimeout","needFlash","gotFocus","policy","setupError","setupUndef","setupLate","sm2Loaded","sstr","sOpt","sPre","sMsg","warn","oProp","Date","getTime","isDebug","bPolling","bHighPerformance","_setPolling","oD","oDebug","oTarget","oToggle","tmp","height","lineHeight","margin","textAlign","border","cursor","background","zIndex","onclick","display","e2","errorLevel","oT","sEventType","sMessage","sm2Debugger","handleEvent","css","p","ignoreInit","status","success","srcQueue","canRetry","obj","nP","hasPlugin","AX","ActiveXObject","plugins","mimeTypes","enabledPlugin","flashNeeded","formats","urlResult","setInterval","clearInterval","_setSandboxType","sandboxType","sb","_externalInterfaceOK","swfVersion","initMsg","isRTL","oEmbed","oMovie","movieHTML","oEl","sClass","remoteURL","localURL","extraClass","html","param","dir","quality","bgcolor","pluginspage","hasPriority","FlashVars","setAttribute","overflow","top","abs","oninitmovie","loadIncomplete","cleanup","tests","_externalInterfaceTest","_disableDebug","detachEvent","attachEvent","SM2_DEFER","constructor","getInstance","smBuilder","instance"],"sourceRoot":""}
|