UNPKG

@lumino/coreutils

Version:
1,043 lines (1,032 loc) 35.7 kB
import { topologicSort } from '@lumino/algorithm'; // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * The namespace for JSON-specific functions. */ var JSONExt; (function (JSONExt) { /** * A shared frozen empty JSONObject */ JSONExt.emptyObject = Object.freeze({}); /** * A shared frozen empty JSONArray */ JSONExt.emptyArray = Object.freeze([]); /** * Test whether a JSON value is a primitive. * * @param value - The JSON value of interest. * * @returns `true` if the value is a primitive,`false` otherwise. */ function isPrimitive(value) { return (value === null || typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string'); } JSONExt.isPrimitive = isPrimitive; function isArray(value) { return Array.isArray(value); } JSONExt.isArray = isArray; function isObject(value) { return !isPrimitive(value) && !isArray(value); } JSONExt.isObject = isObject; /** * Compare two JSON values for deep equality. * * @param first - The first JSON value of interest. * * @param second - The second JSON value of interest. * * @returns `true` if the values are equivalent, `false` otherwise. */ function deepEqual(first, second) { // Check referential and primitive equality first. if (first === second) { return true; } // If one is a primitive, the `===` check ruled out the other. if (isPrimitive(first) || isPrimitive(second)) { return false; } // Test whether they are arrays. let a1 = isArray(first); let a2 = isArray(second); // Bail if the types are different. if (a1 !== a2) { return false; } // If they are both arrays, compare them. if (a1 && a2) { return deepArrayEqual(first, second); } // At this point, they must both be objects. return deepObjectEqual(first, second); } JSONExt.deepEqual = deepEqual; /** * Create a deep copy of a JSON value. * * @param value - The JSON value to copy. * * @returns A deep copy of the given JSON value. */ function deepCopy(value) { // Do nothing for primitive values. if (isPrimitive(value)) { return value; } // Deep copy an array. if (isArray(value)) { return deepArrayCopy(value); } // Deep copy an object. return deepObjectCopy(value); } JSONExt.deepCopy = deepCopy; /** * Compare two JSON arrays for deep equality. */ function deepArrayEqual(first, second) { // Check referential equality first. if (first === second) { return true; } // Test the arrays for equal length. if (first.length !== second.length) { return false; } // Compare the values for equality. for (let i = 0, n = first.length; i < n; ++i) { if (!deepEqual(first[i], second[i])) { return false; } } // At this point, the arrays are equal. return true; } /** * Compare two JSON objects for deep equality. */ function deepObjectEqual(first, second) { // Check referential equality first. if (first === second) { return true; } // Check for the first object's keys in the second object. for (let key in first) { if (first[key] !== undefined && !(key in second)) { return false; } } // Check for the second object's keys in the first object. for (let key in second) { if (second[key] !== undefined && !(key in first)) { return false; } } // Compare the values for equality. for (let key in first) { // Get the values. let firstValue = first[key]; let secondValue = second[key]; // If both are undefined, ignore the key. if (firstValue === undefined && secondValue === undefined) { continue; } // If only one value is undefined, the objects are not equal. if (firstValue === undefined || secondValue === undefined) { return false; } // Compare the values. if (!deepEqual(firstValue, secondValue)) { return false; } } // At this point, the objects are equal. return true; } /** * Create a deep copy of a JSON array. */ function deepArrayCopy(value) { let result = new Array(value.length); for (let i = 0, n = value.length; i < n; ++i) { result[i] = deepCopy(value[i]); } return result; } /** * Create a deep copy of a JSON object. */ function deepObjectCopy(value) { let result = {}; for (let key in value) { // Ignore undefined values. let subvalue = value[key]; if (subvalue === undefined) { continue; } result[key] = deepCopy(subvalue); } return result; } })(JSONExt || (JSONExt = {})); // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * An object which stores MIME data for general application use. * * #### Notes * This class does not attempt to enforce "correctness" of MIME types * and their associated data. Since this class is designed to transfer * arbitrary data and objects within the same application, it assumes * that the user provides correct and accurate data. */ class MimeData { constructor() { this._types = []; this._values = []; } /** * Get an array of the MIME types contained within the dataset. * * @returns A new array of the MIME types, in order of insertion. */ types() { return this._types.slice(); } /** * Test whether the dataset has an entry for the given type. * * @param mime - The MIME type of interest. * * @returns `true` if the dataset contains a value for the given * MIME type, `false` otherwise. */ hasData(mime) { return this._types.indexOf(mime) !== -1; } /** * Get the data value for the given MIME type. * * @param mime - The MIME type of interest. * * @returns The value for the given MIME type, or `undefined` if * the dataset does not contain a value for the type. */ getData(mime) { let i = this._types.indexOf(mime); return i !== -1 ? this._values[i] : undefined; } /** * Set the data value for the given MIME type. * * @param mime - The MIME type of interest. * * @param data - The data value for the given MIME type. * * #### Notes * This will overwrite any previous entry for the MIME type. */ setData(mime, data) { this.clearData(mime); this._types.push(mime); this._values.push(data); } /** * Remove the data entry for the given MIME type. * * @param mime - The MIME type of interest. * * #### Notes * This is a no-op if there is no entry for the given MIME type. */ clearData(mime) { let i = this._types.indexOf(mime); if (i !== -1) { this._types.splice(i, 1); this._values.splice(i, 1); } } /** * Remove all data entries from the dataset. */ clear() { this._types.length = 0; this._values.length = 0; } } // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /** * Plugin registry. */ class PluginRegistry { constructor(options = {}) { this._application = null; this._validatePlugin = () => true; this._plugins = new Map(); this._services = new Map(); if (options.validatePlugin) { console.info('Plugins may be rejected by the custom validation plugin method.'); this._validatePlugin = options.validatePlugin; } } /** * The application object. * * It will be provided as first argument to the * plugins activation and deactivation functions. * * It can only be set once. * * By default, it is `null`. */ get application() { return this._application; } set application(v) { if (this._application !== null) { throw Error('PluginRegistry.application is already set. It cannot be overridden.'); } this._application = v; } /** * The list of all the deferred plugins. */ get deferredPlugins() { return Array.from(this._plugins) .filter(([id, plugin]) => plugin.autoStart === 'defer') .map(([id, plugin]) => id); } /** * Get a plugin description. * * @param id - The ID of the plugin of interest. * * @returns The plugin description. */ getPluginDescription(id) { var _a, _b; return (_b = (_a = this._plugins.get(id)) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : ''; } /** * Test whether a plugin is registered with the application. * * @param id - The ID of the plugin of interest. * * @returns `true` if the plugin is registered, `false` otherwise. */ hasPlugin(id) { return this._plugins.has(id); } /** * Test whether a plugin is activated with the application. * * @param id - The ID of the plugin of interest. * * @returns `true` if the plugin is activated, `false` otherwise. */ isPluginActivated(id) { var _a, _b; return (_b = (_a = this._plugins.get(id)) === null || _a === void 0 ? void 0 : _a.activated) !== null && _b !== void 0 ? _b : false; } /** * List the IDs of the plugins registered with the application. * * @returns A new array of the registered plugin IDs. */ listPlugins() { return Array.from(this._plugins.keys()); } /** * Register a plugin with the application. * * @param plugin - The plugin to register. * * #### Notes * An error will be thrown if a plugin with the same ID is already * registered, or if the plugin has a circular dependency. * * If the plugin provides a service which has already been provided * by another plugin, the new service will override the old service. */ registerPlugin(plugin) { // Throw an error if the plugin ID is already registered. if (this._plugins.has(plugin.id)) { throw new TypeError(`Plugin '${plugin.id}' is already registered.`); } if (!this._validatePlugin(plugin)) { throw new Error(`Plugin '${plugin.id}' is not valid.`); } // Create the normalized plugin data. const data = Private.createPluginData(plugin); // Ensure the plugin does not cause a cyclic dependency. Private.ensureNoCycle(data, this._plugins, this._services); // Add the service token to the service map. if (data.provides) { this._services.set(data.provides, data.id); } // Add the plugin to the plugin map. this._plugins.set(data.id, data); } /** * Register multiple plugins with the application. * * @param plugins - The plugins to register. * * #### Notes * This calls `registerPlugin()` for each of the given plugins. */ registerPlugins(plugins) { for (const plugin of plugins) { this.registerPlugin(plugin); } } /** * Deregister a plugin with the application. * * @param id - The ID of the plugin of interest. * * @param force - Whether to deregister the plugin even if it is active. */ deregisterPlugin(id, force) { const plugin = this._plugins.get(id); if (!plugin) { return; } if (plugin.activated && !force) { throw new Error(`Plugin '${id}' is still active.`); } this._plugins.delete(id); } /** * Activate the plugin with the given ID. * * @param id - The ID of the plugin of interest. * * @returns A promise which resolves when the plugin is activated * or rejects with an error if it cannot be activated. */ async activatePlugin(id) { // Reject the promise if the plugin is not registered. const plugin = this._plugins.get(id); if (!plugin) { throw new ReferenceError(`Plugin '${id}' is not registered.`); } // Resolve immediately if the plugin is already activated. if (plugin.activated) { return; } // Return the pending resolver promise if it exists. if (plugin.promise) { return plugin.promise; } // Resolve the required services for the plugin. const required = plugin.requires.map(t => this.resolveRequiredService(t)); // Resolve the optional services for the plugin. const optional = plugin.optional.map(t => this.resolveOptionalService(t)); // Setup the resolver promise for the plugin. plugin.promise = Promise.all([...required, ...optional]) .then(services => plugin.activate.apply(undefined, [this.application, ...services])) .then(service => { plugin.service = service; plugin.activated = true; plugin.promise = null; }) .catch(error => { plugin.promise = null; throw error; }); // Return the pending resolver promise. return plugin.promise; } /** * Activate all the deferred plugins. * * @returns A promise which will resolve when each plugin is activated * or rejects with an error if one cannot be activated. */ async activatePlugins(kind, options = {}) { switch (kind) { case 'defer': { const promises = this.deferredPlugins .filter(pluginId => this._plugins.get(pluginId).autoStart) .map(pluginId => { return this.activatePlugin(pluginId); }); await Promise.all(promises); break; } case 'startUp': { // Collect the ids of the startup plugins. const startups = Private.collectStartupPlugins(this._plugins, options); // Generate the activation promises. const promises = startups.map(async (id) => { try { return await this.activatePlugin(id); } catch (error) { console.error(`Plugin '${id}' failed to activate.`, error); } }); await Promise.all(promises); break; } } } /** * Deactivate the plugin and its downstream dependents if and only if the * plugin and its dependents all support `deactivate`. * * @param id - The ID of the plugin of interest. * * @returns A list of IDs of downstream plugins deactivated with this one. */ async deactivatePlugin(id) { // Reject the promise if the plugin is not registered. const plugin = this._plugins.get(id); if (!plugin) { throw new ReferenceError(`Plugin '${id}' is not registered.`); } // Bail early if the plugin is not activated. if (!plugin.activated) { return []; } // Check that this plugin can deactivate. if (!plugin.deactivate) { throw new TypeError(`Plugin '${id}'#deactivate() method missing`); } // Find the optimal deactivation order for plugins downstream of this one. const manifest = Private.findDependents(id, this._plugins, this._services); const downstream = manifest.map(id => this._plugins.get(id)); // Check that all downstream plugins can deactivate. for (const plugin of downstream) { if (!plugin.deactivate) { throw new TypeError(`Plugin ${plugin.id}#deactivate() method missing (depends on ${id})`); } } // Deactivate all downstream plugins. for (const plugin of downstream) { const services = [...plugin.requires, ...plugin.optional].map(service => { const id = this._services.get(service); return id ? this._plugins.get(id).service : null; }); // Await deactivation so the next plugins only receive active services. await plugin.deactivate(this.application, ...services); plugin.service = null; plugin.activated = false; } // Remove plugin ID and return manifest of deactivated plugins. manifest.pop(); return manifest; } /** * Resolve a required service of a given type. * * @param token - The token for the service type of interest. * * @returns A promise which resolves to an instance of the requested * service, or rejects with an error if it cannot be resolved. * * #### Notes * Services are singletons. The same instance will be returned each * time a given service token is resolved. * * If the plugin which provides the service has not been activated, * resolving the service will automatically activate the plugin. * * User code will not typically call this method directly. Instead, * the required services for the user's plugins will be resolved * automatically when the plugin is activated. */ async resolveRequiredService(token) { // Reject the promise if there is no provider for the type. const id = this._services.get(token); if (!id) { throw new TypeError(`No provider for: ${token.name}.`); } // Activate the plugin if necessary. const plugin = this._plugins.get(id); if (!plugin.activated) { await this.activatePlugin(id); } return plugin.service; } /** * Resolve an optional service of a given type. * * @param token - The token for the service type of interest. * * @returns A promise which resolves to an instance of the requested * service, or `null` if it cannot be resolved. * * #### Notes * Services are singletons. The same instance will be returned each * time a given service token is resolved. * * If the plugin which provides the service has not been activated, * resolving the service will automatically activate the plugin. * * User code will not typically call this method directly. Instead, * the optional services for the user's plugins will be resolved * automatically when the plugin is activated. */ async resolveOptionalService(token) { // Resolve with `null` if there is no provider for the type. const id = this._services.get(token); if (!id) { return null; } // Activate the plugin if necessary. const plugin = this._plugins.get(id); if (!plugin.activated) { try { await this.activatePlugin(id); } catch (reason) { console.error(reason); return null; } } return plugin.service; } } /** * The namespace for the module implementation details. */ var Private; (function (Private) { class PluginData { constructor(plugin) { var _a, _b, _c, _d; this._activated = false; this._promise = null; this._service = null; this.id = plugin.id; this.description = (_a = plugin.description) !== null && _a !== void 0 ? _a : ''; this.activate = plugin.activate; this.deactivate = (_b = plugin.deactivate) !== null && _b !== void 0 ? _b : null; this.provides = (_c = plugin.provides) !== null && _c !== void 0 ? _c : null; this.autoStart = (_d = plugin.autoStart) !== null && _d !== void 0 ? _d : false; this.requires = plugin.requires ? plugin.requires.slice() : []; this.optional = plugin.optional ? plugin.optional.slice() : []; } /** * Whether the plugin has been activated. */ get activated() { return this._activated; } set activated(a) { this._activated = a; } /** * The resolved service for the plugin, or `null`. */ get service() { return this._service; } set service(s) { this._service = s; } /** * The pending resolver promise, or `null`. */ get promise() { return this._promise; } set promise(p) { this._promise = p; } } /** * Create a normalized plugin data object for the given plugin. */ function createPluginData(plugin) { return new PluginData(plugin); } Private.createPluginData = createPluginData; /** * Ensure no cycle is present in the plugin resolution graph. * * If a cycle is detected, an error will be thrown. */ function ensureNoCycle(plugin, plugins, services) { const dependencies = [...plugin.requires, ...plugin.optional]; const visit = (token) => { if (token === plugin.provides) { return true; } const id = services.get(token); if (!id) { return false; } const visited = plugins.get(id); const dependencies = [...visited.requires, ...visited.optional]; if (dependencies.length === 0) { return false; } trace.push(id); if (dependencies.some(visit)) { return true; } trace.pop(); return false; }; // Bail early if there cannot be a cycle. if (!plugin.provides || dependencies.length === 0) { return; } // Setup a stack to trace service resolution. const trace = [plugin.id]; // Throw an exception if a cycle is present. if (dependencies.some(visit)) { throw new ReferenceError(`Cycle detected: ${trace.join(' -> ')}.`); } } Private.ensureNoCycle = ensureNoCycle; /** * Find dependents in deactivation order. * * @param id - The ID of the plugin of interest. * * @param plugins - The map containing all plugins. * * @param services - The map containing all services. * * @returns A list of dependent plugin IDs in order of deactivation * * #### Notes * The final item of the returned list is always the plugin of interest. */ function findDependents(id, plugins, services) { const edges = new Array(); const add = (id) => { const plugin = plugins.get(id); // FIXME In the case of missing optional dependencies, we may consider // deactivating and reactivating the plugin without the missing service. const dependencies = [...plugin.requires, ...plugin.optional]; edges.push(...dependencies.reduce((acc, dep) => { const service = services.get(dep); if (service) { // An edge is oriented from dependent to provider. acc.push([id, service]); } return acc; }, [])); }; for (const id of plugins.keys()) { add(id); } // Filter edges // - Get all packages that dependent on the package to be deactivated const newEdges = edges.filter(edge => edge[1] === id); let oldSize = 0; while (newEdges.length > oldSize) { const previousSize = newEdges.length; // Get all packages that dependent on packages that will be deactivated const packagesOfInterest = new Set(newEdges.map(edge => edge[0])); for (const poi of packagesOfInterest) { edges .filter(edge => edge[1] === poi) .forEach(edge => { // We check it is not already included to deal with circular dependencies if (!newEdges.includes(edge)) { newEdges.push(edge); } }); } oldSize = previousSize; } const sorted = topologicSort(newEdges); const index = sorted.findIndex(candidate => candidate === id); if (index === -1) { return [id]; } return sorted.slice(0, index + 1); } Private.findDependents = findDependents; /** * Collect the IDs of the plugins to activate on startup. */ function collectStartupPlugins(plugins, options) { // Create a set to hold the plugin IDs. const collection = new Set(); // Collect the auto-start (non deferred) plugins. for (const id of plugins.keys()) { if (plugins.get(id).autoStart === true) { collection.add(id); } } // Add the startup plugins. if (options.startPlugins) { for (const id of options.startPlugins) { collection.add(id); } } // Remove the ignored plugins. if (options.ignorePlugins) { for (const id of options.ignorePlugins) { collection.delete(id); } } // Return the collected startup plugins. return Array.from(collection); } Private.collectStartupPlugins = collectStartupPlugins; })(Private || (Private = {})); // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * A class which wraps a promise into a delegate object. * * #### Notes * This class is useful when the logic to resolve or reject a promise * cannot be defined at the point where the promise is created. */ class PromiseDelegate { /** * Construct a new promise delegate. */ constructor() { this.promise = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); } /** * Resolve the wrapped promise with the given value. * * @param value - The value to use for resolving the promise. */ resolve(value) { let resolve = this._resolve; resolve(value); } /** * Reject the wrapped promise with the given value. * * @reason - The reason for rejecting the promise. */ reject(reason) { let reject = this._reject; reject(reason); } } // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * A runtime object which captures compile-time type information. * * #### Notes * A token captures the compile-time type of an interface or class in * an object which can be used at runtime in a type-safe fashion. */ class Token { /** * Construct a new token. * * @param name - A human readable name for the token. * @param description - Token purpose description for documentation. */ constructor(name, description) { this.name = name; this.description = description !== null && description !== void 0 ? description : ''; this._tokenStructuralPropertyT = null; } } // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ // Fallback function fallbackRandomValues(buffer) { let value = 0; for (let i = 0, n = buffer.length; i < n; ++i) { if (i % 4 === 0) { value = (Math.random() * 0xffffffff) >>> 0; } buffer[i] = value & 0xff; value >>>= 8; } } // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * The namespace for random number related functionality. */ var Random; (function (Random) { /** * A function which generates random bytes. * * @param buffer - The `Uint8Array` to fill with random bytes. * * #### Notes * A cryptographically strong random number generator will be used if * available. Otherwise, `Math.random` will be used as a fallback for * randomness. * * The following RNGs are supported, listed in order of precedence: * - `window.crypto.getRandomValues` * - `window.msCrypto.getRandomValues` * - `require('crypto').randomFillSync * - `require('crypto').randomBytes * - `Math.random` */ Random.getRandomValues = (() => { // Look up the crypto module if available. const crypto = (typeof window !== 'undefined' && (window.crypto || window.msCrypto)) || null; // Modern browsers and IE 11 if (crypto && typeof crypto.getRandomValues === 'function') { return function getRandomValues(buffer) { return crypto.getRandomValues(buffer); }; } // Fallback return fallbackRandomValues; })(); })(Random || (Random = {})); // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * A function which creates a function that generates UUID v4 identifiers. * * @returns A new function that creates a UUID v4 string. * * #### Notes * This implementation complies with RFC 4122. * * This uses `Random.getRandomValues()` for random bytes, which in * turn will use the underlying `crypto` module of the platform if * it is available. The fallback for randomness is `Math.random`. */ function uuid4Factory(getRandomValues) { // Create a 16 byte array to hold the random values. const bytes = new Uint8Array(16); // Create a look up table from bytes to hex strings. const lut = new Array(256); // Pad the single character hex digits with a leading zero. for (let i = 0; i < 16; ++i) { lut[i] = '0' + i.toString(16); } // Populate the rest of the hex digits. for (let i = 16; i < 256; ++i) { lut[i] = i.toString(16); } // Return a function which generates the UUID. return function uuid4() { // Get a new batch of random values. getRandomValues(bytes); // Set the UUID version number to 4. bytes[6] = 0x40 | (bytes[6] & 0x0f); // Set the clock sequence bit to the RFC spec. bytes[8] = 0x80 | (bytes[8] & 0x3f); // Assemble the UUID string. return (lut[bytes[0]] + lut[bytes[1]] + lut[bytes[2]] + lut[bytes[3]] + '-' + lut[bytes[4]] + lut[bytes[5]] + '-' + lut[bytes[6]] + lut[bytes[7]] + '-' + lut[bytes[8]] + lut[bytes[9]] + '-' + lut[bytes[10]] + lut[bytes[11]] + lut[bytes[12]] + lut[bytes[13]] + lut[bytes[14]] + lut[bytes[15]]); }; } // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. /*----------------------------------------------------------------------------- | Copyright (c) 2014-2017, PhosphorJS Contributors | | Distributed under the terms of the BSD 3-Clause License. | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ /** * The namespace for UUID related functionality. */ var UUID; (function (UUID) { /** * A function which generates UUID v4 identifiers. * * @returns A new UUID v4 string. * * #### Notes * This implementation complies with RFC 4122. * * This uses `Random.getRandomValues()` for random bytes, which in * turn will use the underlying `crypto` module of the platform if * it is available. The fallback for randomness is `Math.random`. */ UUID.uuid4 = uuid4Factory(Random.getRandomValues); })(UUID || (UUID = {})); export { JSONExt, MimeData, PluginRegistry, PromiseDelegate, Random, Token, UUID }; //# sourceMappingURL=index.es6.js.map