/* Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable no-extend-native */ /* globals VBArray, PDFJS, global */ // Skip compatibility checks for the extensions and if we already ran // this module. if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) && (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) { var globalScope = (typeof window !== 'undefined') ? window : (typeof global !== 'undefined') ? global : (typeof self !== 'undefined') ? self : this; var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; var isAndroid = /Android/.test(userAgent); var isAndroidPre3 = /Android\s[0-2][^\d]/.test(userAgent); var isAndroidPre5 = /Android\s[0-4][^\d]/.test(userAgent); var isChrome = userAgent.indexOf('Chrom') >= 0; var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(userAgent); var isIOSChrome = userAgent.indexOf('CriOS') >= 0; var isIE = userAgent.indexOf('Trident') >= 0; var isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); var isOpera = userAgent.indexOf('Opera') >= 0; var isSafari = /Safari\//.test(userAgent) && !/(Chrome\/|Android\s)/.test(userAgent); var hasDOM = typeof window === 'object' && typeof document === 'object'; // Initializing PDFJS global object here, it case if we need to change/disable // some PDF.js features, e.g. range requests if (typeof PDFJS === 'undefined') { globalScope.PDFJS = {}; } PDFJS.compatibilityChecked = true; // Checking if the typed arrays are supported // Support: iOS<6.0 (subarray), IE<10, Android<4.0 (function checkTypedArrayCompatibility() { if (typeof Uint8Array !== 'undefined') { // Support: iOS<6.0 if (typeof Uint8Array.prototype.subarray === 'undefined') { Uint8Array.prototype.subarray = function subarray(start, end) { return new Uint8Array(this.slice(start, end)); }; Float32Array.prototype.subarray = function subarray(start, end) { return new Float32Array(this.slice(start, end)); }; } // Support: Android<4.1 if (typeof Float64Array === 'undefined') { globalScope.Float64Array = Float32Array; } return; } function subarray(start, end) { return new TypedArray(this.slice(start, end)); } function setArrayOffset(array, offset) { if (arguments.length < 2) { offset = 0; } for (var i = 0, n = array.length; i < n; ++i, ++offset) { this[offset] = array[i] & 0xFF; } } function Uint32ArrayView(buffer, length) { this.buffer = buffer; this.byteLength = buffer.length; this.length = length; ensureUint32ArrayViewProps(this.length); } Uint32ArrayView.prototype = Object.create(null); var uint32ArrayViewSetters = 0; function createUint32ArrayProp(index) { return { get() { var buffer = this.buffer, offset = index << 2; return (buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0; }, set(value) { var buffer = this.buffer, offset = index << 2; buffer[offset] = value & 255; buffer[offset + 1] = (value >> 8) & 255; buffer[offset + 2] = (value >> 16) & 255; buffer[offset + 3] = (value >>> 24) & 255; }, }; } function ensureUint32ArrayViewProps(length) { while (uint32ArrayViewSetters < length) { Object.defineProperty(Uint32ArrayView.prototype, uint32ArrayViewSetters, createUint32ArrayProp(uint32ArrayViewSetters)); uint32ArrayViewSetters++; } } function TypedArray(arg1) { var result, i, n; if (typeof arg1 === 'number') { result = []; for (i = 0; i < arg1; ++i) { result[i] = 0; } } else if ('slice' in arg1) { result = arg1.slice(0); } else { result = []; for (i = 0, n = arg1.length; i < n; ++i) { result[i] = arg1[i]; } } result.subarray = subarray; result.buffer = result; result.byteLength = result.length; result.set = setArrayOffset; if (typeof arg1 === 'object' && arg1.buffer) { result.buffer = arg1.buffer; } return result; } globalScope.Uint8Array = TypedArray; globalScope.Int8Array = TypedArray; // we don't need support for set, byteLength for 32-bit array // so we can use the TypedArray as well globalScope.Int32Array = TypedArray; globalScope.Uint16Array = TypedArray; globalScope.Float32Array = TypedArray; globalScope.Float64Array = TypedArray; globalScope.Uint32Array = function () { if (arguments.length === 3) { // Building view for buffer, offset, and length if (arguments[1] !== 0) { throw new Error('offset !== 0 is not supported'); } return new Uint32ArrayView(arguments[0], arguments[2]); } return TypedArray.apply(this, arguments); }; })(); // window.CanvasPixelArray.buffer/.byteLength // Support: IE9 (function canvasPixelArrayBuffer() { if (!hasDOM || !window.CanvasPixelArray) { return; } var cpaProto = window.CanvasPixelArray.prototype; if ('buffer' in cpaProto) { return; } // Trying to fake CanvasPixelArray as Uint8ClampedArray. Object.defineProperty(cpaProto, 'buffer', { get() { return this; }, enumerable: false, configurable: true, }); Object.defineProperty(cpaProto, 'byteLength', { get() { return this.length; }, enumerable: false, configurable: true, }); })(); // URL = URL || webkitURL // Support: Safari<7, Android 4.2+ (function normalizeURLObject() { if (!globalScope.URL) { globalScope.URL = globalScope.webkitURL; } })(); // Object.defineProperty()? // Support: Android<4.0, Safari<5.1 (function checkObjectDefinePropertyCompatibility() { if (typeof Object.defineProperty !== 'undefined') { var definePropertyPossible = true; try { if (hasDOM) { // some browsers (e.g. safari) cannot use defineProperty() on DOM // objects and thus the native version is not sufficient Object.defineProperty(new Image(), 'id', { value: 'test', }); } // ... another test for android gb browser for non-DOM objects var Test = function Test() {}; Test.prototype = { get id() { }, }; Object.defineProperty(new Test(), 'id', { value: '', configurable: true, enumerable: true, writable: false, }); } catch (e) { definePropertyPossible = false; } if (definePropertyPossible) { return; } } Object.defineProperty = function objectDefineProperty(obj, name, def) { delete obj[name]; if ('get' in def) { obj.__defineGetter__(name, def['get']); } if ('set' in def) { obj.__defineSetter__(name, def['set']); } if ('value' in def) { obj.__defineSetter__(name, function objectDefinePropertySetter(value) { this.__defineGetter__(name, function objectDefinePropertyGetter() { return value; }); return value; }); obj[name] = def.value; } }; })(); // No XMLHttpRequest#response? // Support: IE<11, Android <4.0 (function checkXMLHttpRequestResponseCompatibility() { if (typeof XMLHttpRequest === 'undefined') { return; } var xhrPrototype = XMLHttpRequest.prototype; var xhr = new XMLHttpRequest(); if (!('overrideMimeType' in xhr)) { // IE10 might have response, but not overrideMimeType // Support: IE10 Object.defineProperty(xhrPrototype, 'overrideMimeType', { value: function xmlHttpRequestOverrideMimeType(mimeType) {}, }); } if ('responseType' in xhr) { return; } Object.defineProperty(xhrPrototype, 'responseType', { get: function xmlHttpRequestGetResponseType() { return this._responseType || 'text'; }, set: function xmlHttpRequestSetResponseType(value) { if (value === 'text' || value === 'arraybuffer') { this._responseType = value; if (value === 'arraybuffer' && typeof this.overrideMimeType === 'function') { this.overrideMimeType('text/plain; charset=x-user-defined'); } } }, }); // Support: IE9 if (typeof VBArray !== 'undefined') { Object.defineProperty(xhrPrototype, 'response', { get: function xmlHttpRequestResponseGet() { if (this.responseType === 'arraybuffer') { return new Uint8Array(new VBArray(this.responseBody).toArray()); } return this.responseText; }, }); return; } Object.defineProperty(xhrPrototype, 'response', { get: function xmlHttpRequestResponseGet() { if (this.responseType !== 'arraybuffer') { return this.responseText; } var text = this.responseText; var i, n = text.length; var result = new Uint8Array(n); for (i = 0; i < n; ++i) { result[i] = text.charCodeAt(i) & 0xFF; } return result.buffer; }, }); })(); // window.btoa (base64 encode function) ? // Support: IE<10 (function checkWindowBtoaCompatibility() { if ('btoa' in globalScope) { return; } var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; globalScope.btoa = function (chars) { var buffer = ''; var i, n; for (i = 0, n = chars.length; i < n; i += 3) { var b1 = chars.charCodeAt(i) & 0xFF; var b2 = chars.charCodeAt(i + 1) & 0xFF; var b3 = chars.charCodeAt(i + 2) & 0xFF; var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; var d4 = i + 2 < n ? (b3 & 0x3F) : 64; buffer += (digits.charAt(d1) + digits.charAt(d2) + digits.charAt(d3) + digits.charAt(d4)); } return buffer; }; })(); // window.atob (base64 encode function)? // Support: IE<10 (function checkWindowAtobCompatibility() { if ('atob' in globalScope) { return; } // https://github.com/davidchambers/Base64.js var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; globalScope.atob = function (input) { input = input.replace(/=+$/, ''); if (input.length % 4 === 1) { throw new Error('bad atob input'); } for ( // initialize result and counters var bc = 0, bs, buffer, idx = 0, output = ''; // get next character (buffer = input.charAt(idx++)); // character found in table? // initialize bit storage and add its ascii value ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, // and if not first of each 4 characters, // convert the first 8 bits to one ascii character bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 ) { // try to find character in table (0-63, not found => -1) buffer = digits.indexOf(buffer); } return output; }; })(); // Function.prototype.bind? // Support: Android<4.0, iOS<6.0 (function checkFunctionPrototypeBindCompatibility() { if (typeof Function.prototype.bind !== 'undefined') { return; } Function.prototype.bind = function functionPrototypeBind(obj) { var fn = this, headArgs = Array.prototype.slice.call(arguments, 1); var bound = function functionPrototypeBindBound() { var args = headArgs.concat(Array.prototype.slice.call(arguments)); return fn.apply(obj, args); }; return bound; }; })(); // HTMLElement dataset property // Support: IE<11, Safari<5.1, Android<4.0 (function checkDatasetProperty() { if (!hasDOM) { return; } var div = document.createElement('div'); if ('dataset' in div) { return; // dataset property exists } Object.defineProperty(HTMLElement.prototype, 'dataset', { get() { if (this._dataset) { return this._dataset; } var dataset = {}; for (var j = 0, jj = this.attributes.length; j < jj; j++) { var attribute = this.attributes[j]; if (attribute.name.substring(0, 5) !== 'data-') { continue; } var key = attribute.name.substring(5).replace(/\-([a-z])/g, function(all, ch) { return ch.toUpperCase(); }); dataset[key] = attribute.value; } Object.defineProperty(this, '_dataset', { value: dataset, writable: false, enumerable: false, }); return dataset; }, enumerable: true, }); })(); // HTMLElement classList property // Support: IE<10, Android<4.0, iOS<5.0 (function checkClassListProperty() { function changeList(element, itemName, add, remove) { var s = element.className || ''; var list = s.split(/\s+/g); if (list[0] === '') { list.shift(); } var index = list.indexOf(itemName); if (index < 0 && add) { list.push(itemName); } if (index >= 0 && remove) { list.splice(index, 1); } element.className = list.join(' '); return (index >= 0); } if (!hasDOM) { return; } var div = document.createElement('div'); if ('classList' in div) { return; // classList property exists } var classListPrototype = { add(name) { changeList(this.element, name, true, false); }, contains(name) { return changeList(this.element, name, false, false); }, remove(name) { changeList(this.element, name, false, true); }, toggle(name) { changeList(this.element, name, true, true); }, }; Object.defineProperty(HTMLElement.prototype, 'classList', { get() { if (this._classList) { return this._classList; } var classList = Object.create(classListPrototype, { element: { value: this, writable: false, enumerable: true, }, }); Object.defineProperty(this, '_classList', { value: classList, writable: false, enumerable: false, }); return classList; }, enumerable: true, }); })(); // Checking if worker has console support. Forwarding all messages to the main // thread if console object is absent. (function checkWorkerConsoleCompatibility() { if (typeof importScripts === 'undefined' || 'console' in globalScope) { return; } var consoleTimer = {}; var workerConsole = { log: function log() { var args = Array.prototype.slice.call(arguments); globalScope.postMessage({ targetName: 'main', action: 'console_log', data: args, }); }, error: function error() { var args = Array.prototype.slice.call(arguments); globalScope.postMessage({ targetName: 'main', action: 'console_error', data: args, }); }, time: function time(name) { consoleTimer[name] = Date.now(); }, timeEnd: function timeEnd(name) { var time = consoleTimer[name]; if (!time) { throw new Error('Unknown timer name ' + name); } this.log('Timer:', name, Date.now() - time); }, }; globalScope.console = workerConsole; })(); // Check console compatibility // In older IE versions the console object is not available // unless console is open. // Support: IE<10 (function checkConsoleCompatibility() { if (!hasDOM) { return; } if (!('console' in window)) { window.console = { log() {}, error() {}, warn() {}, }; return; } if (!('bind' in console.log)) { // native functions in IE9 might not have bind console.log = (function(fn) { return function(msg) { return fn(msg); }; })(console.log); console.error = (function(fn) { return function(msg) { return fn(msg); }; })(console.error); console.warn = (function(fn) { return function(msg) { return fn(msg); }; })(console.warn); return; } })(); // Check onclick compatibility in Opera // Support: Opera<15 (function checkOnClickCompatibility() { // workaround for reported Opera bug DSK-354448: // onclick fires on disabled buttons with opaque content function ignoreIfTargetDisabled(event) { if (isDisabled(event.target)) { event.stopPropagation(); } } function isDisabled(node) { return node.disabled || (node.parentNode && isDisabled(node.parentNode)); } if (isOpera) { // use browser detection since we cannot feature-check this bug document.addEventListener('click', ignoreIfTargetDisabled, true); } })(); // Checks if possible to use URL.createObjectURL() // Support: IE, Chrome on iOS (function checkOnBlobSupport() { // sometimes IE and Chrome on iOS loosing the data created with // createObjectURL(), see #3977 and #8081 if (isIE || isIOSChrome) { PDFJS.disableCreateObjectURL = true; } })(); // Checks if navigator.language is supported (function checkNavigatorLanguage() { if (typeof navigator === 'undefined') { return; } if ('language' in navigator) { return; } PDFJS.locale = navigator.userLanguage || 'en-US'; })(); // Support: Safari 6.0+, Android<3.0, Chrome 39/40, iOS (function checkRangeRequests() { // Safari has issues with cached range requests see: // https://github.com/mozilla/pdf.js/issues/3260 // Last tested with version 6.0.4. // Older versions of Android (pre 3.0) has issues with range requests, see: // https://github.com/mozilla/pdf.js/issues/3381. // Make sure that we only match webkit-based Android browsers, // since Firefox/Fennec works as expected. // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318 if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) { PDFJS.disableRange = true; PDFJS.disableStream = true; } })(); // Check if the browser supports manipulation of the history. // Support: IE<10, Android<4.2 (function checkHistoryManipulation() { if (!hasDOM) { return; } // Android 2.x has so buggy pushState support that it was removed in // Android 3.0 and restored as late as in Android 4.2. // Support: Android 2.x if (!history.pushState || isAndroidPre3) { PDFJS.disableHistory = true; } })(); // Support: IE<11, Chrome<21, Android<4.4, Safari<6 (function checkSetPresenceInImageData() { if (!hasDOM) { return; } // IE < 11 will use window.CanvasPixelArray which lacks set function. if (window.CanvasPixelArray) { if (typeof window.CanvasPixelArray.prototype.set !== 'function') { window.CanvasPixelArray.prototype.set = function(arr) { for (var i = 0, ii = this.length; i < ii; i++) { this[i] = arr[i]; } }; } } else { // Old Chrome and Android use an inaccessible CanvasPixelArray prototype. // Because we cannot feature detect it, we rely on user agent parsing. var polyfill = false, versionMatch; if (isChrome) { versionMatch = userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); // Chrome < 21 lacks the set function. polyfill = versionMatch && parseInt(versionMatch[2]) < 21; } else if (isAndroid) { // Android < 4.4 lacks the set function. // Android >= 4.4 will contain Chrome in the user agent, // thus pass the Chrome check above and not reach this block. polyfill = isAndroidPre5; } else if (isSafari) { versionMatch = userAgent. match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//); // Safari < 6 lacks the set function. polyfill = versionMatch && parseInt(versionMatch[1]) < 6; } if (polyfill) { var contextPrototype = window.CanvasRenderingContext2D.prototype; var createImageData = contextPrototype.createImageData; contextPrototype.createImageData = function(w, h) { var imageData = createImageData.call(this, w, h); imageData.data.set = function(arr) { for (var i = 0, ii = this.length; i < ii; i++) { this[i] = arr[i]; } }; return imageData; }; // this closure will be kept referenced, so clear its vars contextPrototype = null; } } })(); // Support: IE<10, Android<4.0, iOS (function checkRequestAnimationFrame() { function installFakeAnimationFrameFunctions() { window.requestAnimationFrame = function (callback) { return window.setTimeout(callback, 20); }; window.cancelAnimationFrame = function (timeoutID) { window.clearTimeout(timeoutID); }; } if (!hasDOM) { return; } if (isIOS) { // requestAnimationFrame on iOS is broken, replacing with fake one. installFakeAnimationFrameFunctions(); return; } if ('requestAnimationFrame' in window) { return; } window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame; if (window.requestAnimationFrame) { return; } installFakeAnimationFrameFunctions(); })(); // Support: Android, iOS (function checkCanvasSizeLimitation() { if (isIOS || isAndroid) { // 5MP PDFJS.maxCanvasPixels = 5242880; } })(); // Disable fullscreen support for certain problematic configurations. // Support: IE11+ (when embedded). (function checkFullscreenSupport() { if (!hasDOM) { return; } if (isIE && window.parent !== window) { PDFJS.disableFullscreen = true; } })(); // Provides document.currentScript support // Support: IE, Chrome<29. (function checkCurrentScript() { if (!hasDOM) { return; } if ('currentScript' in document) { return; } Object.defineProperty(document, 'currentScript', { get() { var scripts = document.getElementsByTagName('script'); return scripts[scripts.length - 1]; }, enumerable: true, configurable: true, }); })(); // Provides `input.type = 'type'` runtime failure protection. // Support: IE9,10. (function checkInputTypeNumberAssign() { if (!hasDOM) { return; } var el = document.createElement('input'); try { el.type = 'number'; } catch (ex) { var inputProto = el.constructor.prototype; var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type'); Object.defineProperty(inputProto, 'type', { get() { return typeProperty.get.call(this); }, set(value) { typeProperty.set.call(this, value === 'number' ? 'text' : value); }, enumerable: true, configurable: true, }); } })(); // Provides correct document.readyState value for legacy browsers. // Support: IE9,10. (function checkDocumentReadyState() { if (!hasDOM) { return; } if (!document.attachEvent) { return; } var documentProto = document.constructor.prototype; var readyStateProto = Object.getOwnPropertyDescriptor(documentProto, 'readyState'); Object.defineProperty(documentProto, 'readyState', { get() { var value = readyStateProto.get.call(this); return value === 'interactive' ? 'loading' : value; }, set(value) { readyStateProto.set.call(this, value); }, enumerable: true, configurable: true, }); })(); // Provides support for ChildNode.remove in legacy browsers. // Support: IE. (function checkChildNodeRemove() { if (!hasDOM) { return; } if (typeof Element.prototype.remove !== 'undefined') { return; } Element.prototype.remove = function () { if (this.parentNode) { this.parentNode.removeChild(this); } }; })(); /** * Polyfill for Promises: * The following promise implementation tries to generally implement the * Promise/A+ spec. Some notable differences from other promise libraries are: * - There currently isn't a separate deferred and promise object. * - Unhandled rejections eventually show an error if they aren't handled. * * Based off of the work in: * https://bugzilla.mozilla.org/show_bug.cgi?id=810490 */ (function checkPromise() { if (globalScope.Promise) { // Promises existing in the DOM/Worker, checking presence of all/resolve if (typeof globalScope.Promise.all !== 'function') { globalScope.Promise.all = function (iterable) { var count = 0, results = [], resolve, reject; var promise = new globalScope.Promise(function (resolve_, reject_) { resolve = resolve_; reject = reject_; }); iterable.forEach(function (p, i) { count++; p.then(function (result) { results[i] = result; count--; if (count === 0) { resolve(results); } }, reject); }); if (count === 0) { resolve(results); } return promise; }; } if (typeof globalScope.Promise.resolve !== 'function') { globalScope.Promise.resolve = function (value) { return new globalScope.Promise(function (resolve) { resolve(value); }); }; } if (typeof globalScope.Promise.reject !== 'function') { globalScope.Promise.reject = function (reason) { return new globalScope.Promise(function (resolve, reject) { reject(reason); }); }; } if (typeof globalScope.Promise.prototype.catch !== 'function') { globalScope.Promise.prototype.catch = function (onReject) { return globalScope.Promise.prototype.then(undefined, onReject); }; } return; } var STATUS_PENDING = 0; var STATUS_RESOLVED = 1; var STATUS_REJECTED = 2; // In an attempt to avoid silent exceptions, unhandled rejections are // tracked and if they aren't handled in a certain amount of time an // error is logged. var REJECTION_TIMEOUT = 500; var HandlerManager = { handlers: [], running: false, unhandledRejections: [], pendingRejectionCheck: false, scheduleHandlers: function scheduleHandlers(promise) { if (promise._status === STATUS_PENDING) { return; } this.handlers = this.handlers.concat(promise._handlers); promise._handlers = []; if (this.running) { return; } this.running = true; setTimeout(this.runHandlers.bind(this), 0); }, runHandlers: function runHandlers() { var RUN_TIMEOUT = 1; // ms var timeoutAt = Date.now() + RUN_TIMEOUT; while (this.handlers.length > 0) { var handler = this.handlers.shift(); var nextStatus = handler.thisPromise._status; var nextValue = handler.thisPromise._value; try { if (nextStatus === STATUS_RESOLVED) { if (typeof handler.onResolve === 'function') { nextValue = handler.onResolve(nextValue); } } else if (typeof handler.onReject === 'function') { nextValue = handler.onReject(nextValue); nextStatus = STATUS_RESOLVED; if (handler.thisPromise._unhandledRejection) { this.removeUnhandeledRejection(handler.thisPromise); } } } catch (ex) { nextStatus = STATUS_REJECTED; nextValue = ex; } handler.nextPromise._updateStatus(nextStatus, nextValue); if (Date.now() >= timeoutAt) { break; } } if (this.handlers.length > 0) { setTimeout(this.runHandlers.bind(this), 0); return; } this.running = false; }, addUnhandledRejection: function addUnhandledRejection(promise) { this.unhandledRejections.push({ promise, time: Date.now(), }); this.scheduleRejectionCheck(); }, removeUnhandeledRejection: function removeUnhandeledRejection(promise) { promise._unhandledRejection = false; for (var i = 0; i < this.unhandledRejections.length; i++) { if (this.unhandledRejections[i].promise === promise) { this.unhandledRejections.splice(i); i--; } } }, scheduleRejectionCheck: function scheduleRejectionCheck() { if (this.pendingRejectionCheck) { return; } this.pendingRejectionCheck = true; setTimeout(() => { this.pendingRejectionCheck = false; var now = Date.now(); for (var i = 0; i < this.unhandledRejections.length; i++) { if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) { var unhandled = this.unhandledRejections[i].promise._value; var msg = 'Unhandled rejection: ' + unhandled; if (unhandled.stack) { msg += '\n' + unhandled.stack; } // Raising and catching the error, so debugger can break on it. try { throw new Error(msg); } catch (_) { console.warn(msg); } this.unhandledRejections.splice(i); i--; } } if (this.unhandledRejections.length) { this.scheduleRejectionCheck(); } }, REJECTION_TIMEOUT); }, }; var Promise = function Promise(resolver) { this._status = STATUS_PENDING; this._handlers = []; try { resolver.call(this, this._resolve.bind(this), this._reject.bind(this)); } catch (e) { this._reject(e); } }; /** * Builds a promise that is resolved when all the passed in promises are * resolved. * @param {array} promises array of data and/or promises to wait for. * @return {Promise} New dependent promise. */ Promise.all = function Promise_all(promises) { var resolveAll, rejectAll; var deferred = new Promise(function (resolve, reject) { resolveAll = resolve; rejectAll = reject; }); var unresolved = promises.length; var results = []; if (unresolved === 0) { resolveAll(results); return deferred; } function reject(reason) { if (deferred._status === STATUS_REJECTED) { return; } results = []; rejectAll(reason); } for (var i = 0, ii = promises.length; i < ii; ++i) { var promise = promises[i]; var resolve = (function(i) { return function(value) { if (deferred._status === STATUS_REJECTED) { return; } results[i] = value; unresolved--; if (unresolved === 0) { resolveAll(results); } }; })(i); if (Promise.isPromise(promise)) { promise.then(resolve, reject); } else { resolve(promise); } } return deferred; }; /** * Checks if the value is likely a promise (has a 'then' function). * @return {boolean} true if value is thenable */ Promise.isPromise = function Promise_isPromise(value) { return value && typeof value.then === 'function'; }; /** * Creates resolved promise * @param value resolve value * @returns {Promise} */ Promise.resolve = function Promise_resolve(value) { return new Promise(function (resolve) { resolve(value); }); }; /** * Creates rejected promise * @param reason rejection value * @returns {Promise} */ Promise.reject = function Promise_reject(reason) { return new Promise(function (resolve, reject) { reject(reason); }); }; Promise.prototype = { _status: null, _value: null, _handlers: null, _unhandledRejection: null, _updateStatus: function Promise__updateStatus(status, value) { if (this._status === STATUS_RESOLVED || this._status === STATUS_REJECTED) { return; } if (status === STATUS_RESOLVED && Promise.isPromise(value)) { value.then(this._updateStatus.bind(this, STATUS_RESOLVED), this._updateStatus.bind(this, STATUS_REJECTED)); return; } this._status = status; this._value = value; if (status === STATUS_REJECTED && this._handlers.length === 0) { this._unhandledRejection = true; HandlerManager.addUnhandledRejection(this); } HandlerManager.scheduleHandlers(this); }, _resolve: function Promise_resolve(value) { this._updateStatus(STATUS_RESOLVED, value); }, _reject: function Promise_reject(reason) { this._updateStatus(STATUS_REJECTED, reason); }, then: function Promise_then(onResolve, onReject) { var nextPromise = new Promise(function (resolve, reject) { this.resolve = resolve; this.reject = reject; }); this._handlers.push({ thisPromise: this, onResolve, onReject, nextPromise, }); HandlerManager.scheduleHandlers(this); return nextPromise; }, catch: function Promise_catch(onReject) { return this.then(undefined, onReject); }, }; globalScope.Promise = Promise; })(); (function checkWeakMap() { if (globalScope.WeakMap) { return; } var id = 0; function WeakMap() { this.id = '$weakmap' + (id++); } WeakMap.prototype = { has(obj) { return !!Object.getOwnPropertyDescriptor(obj, this.id); }, get(obj, defaultValue) { return this.has(obj) ? obj[this.id] : defaultValue; }, set(obj, value) { Object.defineProperty(obj, this.id, { value, enumerable: false, configurable: true, }); }, delete(obj) { delete obj[this.id]; }, }; globalScope.WeakMap = WeakMap; })(); // Polyfill from https://github.com/Polymer/URL /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ (function checkURLConstructor() { // feature detect for URL constructor var hasWorkingUrl = false; try { if (typeof URL === 'function' && typeof URL.prototype === 'object' && ('origin' in URL.prototype)) { var u = new URL('b', 'http://a'); u.pathname = 'c%20d'; hasWorkingUrl = u.href === 'http://a/c%20d'; } } catch (e) { } if (hasWorkingUrl) { return; } var relative = Object.create(null); relative['ftp'] = 21; relative['file'] = 0; relative['gopher'] = 70; relative['http'] = 80; relative['https'] = 443; relative['ws'] = 80; relative['wss'] = 443; var relativePathDotMapping = Object.create(null); relativePathDotMapping['%2e'] = '.'; relativePathDotMapping['.%2e'] = '..'; relativePathDotMapping['%2e.'] = '..'; relativePathDotMapping['%2e%2e'] = '..'; function isRelativeScheme(scheme) { return relative[scheme] !== undefined; } function invalid() { clear.call(this); this._isInvalid = true; } function IDNAToASCII(h) { if (h === '') { invalid.call(this); } // XXX return h.toLowerCase(); } function percentEscape(c) { var unicode = c.charCodeAt(0); if (unicode > 0x20 && unicode < 0x7F && // " # < > ? ` [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1 ) { return c; } return encodeURIComponent(c); } function percentEscapeQuery(c) { // XXX This actually needs to encode c using encoding and then // convert the bytes one-by-one. var unicode = c.charCodeAt(0); if (unicode > 0x20 && unicode < 0x7F && // " # < > ` (do not escape '?') [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1 ) { return c; } return encodeURIComponent(c); } var EOF, ALPHA = /[a-zA-Z]/, ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/; function parse(input, stateOverride, base) { function err(message) { errors.push(message); } var state = stateOverride || 'scheme start', cursor = 0, buffer = '', seenAt = false, seenBracket = false, errors = []; loop: while ((input[cursor - 1] !== EOF || cursor === 0) && !this._isInvalid) { var c = input[cursor]; switch (state) { case 'scheme start': if (c && ALPHA.test(c)) { buffer += c.toLowerCase(); // ASCII-safe state = 'scheme'; } else if (!stateOverride) { buffer = ''; state = 'no scheme'; continue; } else { err('Invalid scheme.'); break loop; } break; case 'scheme': if (c && ALPHANUMERIC.test(c)) { buffer += c.toLowerCase(); // ASCII-safe } else if (c === ':') { this._scheme = buffer; buffer = ''; if (stateOverride) { break loop; } if (isRelativeScheme(this._scheme)) { this._isRelative = true; } if (this._scheme === 'file') { state = 'relative'; } else if (this._isRelative && base && base._scheme === this._scheme) { state = 'relative or authority'; } else if (this._isRelative) { state = 'authority first slash'; } else { state = 'scheme data'; } } else if (!stateOverride) { buffer = ''; cursor = 0; state = 'no scheme'; continue; } else if (c === EOF) { break loop; } else { err('Code point not allowed in scheme: ' + c); break loop; } break; case 'scheme data': if (c === '?') { this._query = '?'; state = 'query'; } else if (c === '#') { this._fragment = '#'; state = 'fragment'; } else { // XXX error handling if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { this._schemeData += percentEscape(c); } } break; case 'no scheme': if (!base || !(isRelativeScheme(base._scheme))) { err('Missing scheme.'); invalid.call(this); } else { state = 'relative'; continue; } break; case 'relative or authority': if (c === '/' && input[cursor + 1] === '/') { state = 'authority ignore slashes'; } else { err('Expected /, got: ' + c); state = 'relative'; continue; } break; case 'relative': this._isRelative = true; if (this._scheme !== 'file') { this._scheme = base._scheme; } if (c === EOF) { this._host = base._host; this._port = base._port; this._path = base._path.slice(); this._query = base._query; this._username = base._username; this._password = base._password; break loop; } else if (c === '/' || c === '\\') { if (c === '\\') { err('\\ is an invalid code point.'); } state = 'relative slash'; } else if (c === '?') { this._host = base._host; this._port = base._port; this._path = base._path.slice(); this._query = '?'; this._username = base._username; this._password = base._password; state = 'query'; } else if (c === '#') { this._host = base._host; this._port = base._port; this._path = base._path.slice(); this._query = base._query; this._fragment = '#'; this._username = base._username; this._password = base._password; state = 'fragment'; } else { var nextC = input[cursor + 1]; var nextNextC = input[cursor + 2]; if (this._scheme !== 'file' || !ALPHA.test(c) || (nextC !== ':' && nextC !== '|') || (nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\' && nextNextC !== '?' && nextNextC !== '#')) { this._host = base._host; this._port = base._port; this._username = base._username; this._password = base._password; this._path = base._path.slice(); this._path.pop(); } state = 'relative path'; continue; } break; case 'relative slash': if (c === '/' || c === '\\') { if (c === '\\') { err('\\ is an invalid code point.'); } if (this._scheme === 'file') { state = 'file host'; } else { state = 'authority ignore slashes'; } } else { if (this._scheme !== 'file') { this._host = base._host; this._port = base._port; this._username = base._username; this._password = base._password; } state = 'relative path'; continue; } break; case 'authority first slash': if (c === '/') { state = 'authority second slash'; } else { err('Expected \'/\', got: ' + c); state = 'authority ignore slashes'; continue; } break; case 'authority second slash': state = 'authority ignore slashes'; if (c !== '/') { err('Expected \'/\', got: ' + c); continue; } break; case 'authority ignore slashes': if (c !== '/' && c !== '\\') { state = 'authority'; continue; } else { err('Expected authority, got: ' + c); } break; case 'authority': if (c === '@') { if (seenAt) { err('@ already seen.'); buffer += '%40'; } seenAt = true; for (var i = 0; i < buffer.length; i++) { var cp = buffer[i]; if (cp === '\t' || cp === '\n' || cp === '\r') { err('Invalid whitespace in authority.'); continue; } // XXX check URL code points if (cp === ':' && this._password === null) { this._password = ''; continue; } var tempC = percentEscape(cp); if (this._password !== null) { this._password += tempC; } else { this._username += tempC; } } buffer = ''; } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { cursor -= buffer.length; buffer = ''; state = 'host'; continue; } else { buffer += c; } break; case 'file host': if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { if (buffer.length === 2 && ALPHA.test(buffer[0]) && (buffer[1] === ':' || buffer[1] === '|')) { state = 'relative path'; } else if (buffer.length === 0) { state = 'relative path start'; } else { this._host = IDNAToASCII.call(this, buffer); buffer = ''; state = 'relative path start'; } continue; } else if (c === '\t' || c === '\n' || c === '\r') { err('Invalid whitespace in file host.'); } else { buffer += c; } break; case 'host': case 'hostname': if (c === ':' && !seenBracket) { // XXX host parsing this._host = IDNAToASCII.call(this, buffer); buffer = ''; state = 'port'; if (stateOverride === 'hostname') { break loop; } } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { this._host = IDNAToASCII.call(this, buffer); buffer = ''; state = 'relative path start'; if (stateOverride) { break loop; } continue; } else if (c !== '\t' && c !== '\n' && c !== '\r') { if (c === '[') { seenBracket = true; } else if (c === ']') { seenBracket = false; } buffer += c; } else { err('Invalid code point in host/hostname: ' + c); } break; case 'port': if (/[0-9]/.test(c)) { buffer += c; } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#' || stateOverride) { if (buffer !== '') { var temp = parseInt(buffer, 10); if (temp !== relative[this._scheme]) { this._port = temp + ''; } buffer = ''; } if (stateOverride) { break loop; } state = 'relative path start'; continue; } else if (c === '\t' || c === '\n' || c === '\r') { err('Invalid code point in port: ' + c); } else { invalid.call(this); } break; case 'relative path start': if (c === '\\') { err('\'\\\' not allowed in path.'); } state = 'relative path'; if (c !== '/' && c !== '\\') { continue; } break; case 'relative path': if (c === EOF || c === '/' || c === '\\' || (!stateOverride && (c === '?' || c === '#'))) { if (c === '\\') { err('\\ not allowed in relative path.'); } var tmp; if ((tmp = relativePathDotMapping[buffer.toLowerCase()])) { buffer = tmp; } if (buffer === '..') { this._path.pop(); if (c !== '/' && c !== '\\') { this._path.push(''); } } else if (buffer === '.' && c !== '/' && c !== '\\') { this._path.push(''); } else if (buffer !== '.') { if (this._scheme === 'file' && this._path.length === 0 && buffer.length === 2 && ALPHA.test(buffer[0]) && buffer[1] === '|') { buffer = buffer[0] + ':'; } this._path.push(buffer); } buffer = ''; if (c === '?') { this._query = '?'; state = 'query'; } else if (c === '#') { this._fragment = '#'; state = 'fragment'; } } else if (c !== '\t' && c !== '\n' && c !== '\r') { buffer += percentEscape(c); } break; case 'query': if (!stateOverride && c === '#') { this._fragment = '#'; state = 'fragment'; } else if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { this._query += percentEscapeQuery(c); } break; case 'fragment': if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { this._fragment += c; } break; } cursor++; } } function clear() { this._scheme = ''; this._schemeData = ''; this._username = ''; this._password = null; this._host = ''; this._port = ''; this._path = []; this._query = ''; this._fragment = ''; this._isInvalid = false; this._isRelative = false; } // Does not process domain names or IP addresses. // Does not handle encoding for the query parameter. function JURL(url, base /* , encoding */) { if (base !== undefined && !(base instanceof JURL)) { base = new JURL(String(base)); } this._url = url; clear.call(this); var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, ''); // encoding = encoding || 'utf-8' parse.call(this, input, null, base); } JURL.prototype = { toString() { return this.href; }, get href() { if (this._isInvalid) { return this._url; } var authority = ''; if (this._username !== '' || this._password !== null) { authority = this._username + (this._password !== null ? ':' + this._password : '') + '@'; } return this.protocol + (this._isRelative ? '//' + authority + this.host : '') + this.pathname + this._query + this._fragment; }, set href(href) { clear.call(this); parse.call(this, href); }, get protocol() { return this._scheme + ':'; }, set protocol(protocol) { if (this._isInvalid) { return; } parse.call(this, protocol + ':', 'scheme start'); }, get host() { return this._isInvalid ? '' : this._port ? this._host + ':' + this._port : this._host; }, set host(host) { if (this._isInvalid || !this._isRelative) { return; } parse.call(this, host, 'host'); }, get hostname() { return this._host; }, set hostname(hostname) { if (this._isInvalid || !this._isRelative) { return; } parse.call(this, hostname, 'hostname'); }, get port() { return this._port; }, set port(port) { if (this._isInvalid || !this._isRelative) { return; } parse.call(this, port, 'port'); }, get pathname() { return this._isInvalid ? '' : this._isRelative ? '/' + this._path.join('/') : this._schemeData; }, set pathname(pathname) { if (this._isInvalid || !this._isRelative) { return; } this._path = []; parse.call(this, pathname, 'relative path start'); }, get search() { return this._isInvalid || !this._query || this._query === '?' ? '' : this._query; }, set search(search) { if (this._isInvalid || !this._isRelative) { return; } this._query = '?'; if (search[0] === '?') { search = search.slice(1); } parse.call(this, search, 'query'); }, get hash() { return this._isInvalid || !this._fragment || this._fragment === '#' ? '' : this._fragment; }, set hash(hash) { if (this._isInvalid) { return; } this._fragment = '#'; if (hash[0] === '#') { hash = hash.slice(1); } parse.call(this, hash, 'fragment'); }, get origin() { var host; if (this._isInvalid || !this._scheme) { return ''; } // javascript: Gecko returns String(""), WebKit/Blink String("null") // Gecko throws error for "data://" // data: Gecko returns "", Blink returns "data://", WebKit returns "null" // Gecko returns String("") for file: mailto: // WebKit/Blink returns String("SCHEME://") for file: mailto: switch (this._scheme) { case 'data': case 'file': case 'javascript': case 'mailto': return 'null'; } host = this.host; if (!host) { return ''; } return this._scheme + '://' + host; }, }; // Copy over the static methods var OriginalURL = globalScope.URL; if (OriginalURL) { JURL.createObjectURL = function(blob) { // IE extension allows a second optional options argument. // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx return OriginalURL.createObjectURL.apply(OriginalURL, arguments); }; JURL.revokeObjectURL = function(url) { OriginalURL.revokeObjectURL(url); }; } globalScope.URL = JURL; })(); }